home / vendors
Hosted API · live today

A policy gate for the agents you ship to operators.

Your self-storage, voice, SMS or property-management agent drafts an action: waive a late fee, issue a credit, change a gate code, call a tenant at 9 PM. It asks AgentGuard first. The gate reads the operator's policy, answers allow, escalate or block, and signs a receipt of the decision. An escalation reaches a person by one tap, and that person's answer becomes a second signed receipt chained to the first. The gate sees amounts, action types and hashed references. It never sees the conversation, the customer record or a phone number.

Request a pilotHear a storage call
What it sees

Action type, amount, currency, a target-system category, a hashed recipient reference, the recipient's time zone, a consent reference. Any request carrying prompt, message or customer content is rejected with content_rejected.

What it decides

Per-action limits, a daily money cap, a capability ladder, a calling window in the recipient's local time, a consent requirement, a per-recipient contact cap, fleet caps for the whole tenant, and a pause switch for the operator.

What it writes

An Ed25519-signed receipt for every decision, with the policy hash, the inputs it judged and neutral text such as "outside the calling window set in the policy". Anyone holding a receipt can check it at agentguard.run/verify.

How it fits

Four calls, no integration project.

1
Your agent drafts an action

Your runtime already knows the tool call it is about to make. Send its metadata, not its content.

2
POST /api/gate/authorize

With your vendor key and the operator's policy. The answer comes back in one round trip with a signed receipt.

3
Act on the decision

allow runs the tool. escalate opens a one-tap approval for a person. block stops, and the receipt says why.

4
Keep the receipts

Hand them to the operator, an auditor or an underwriter. They verify at /verify without asking us.

Pre-execution policy enforcement is the control the Cloud Security Alliance listed first after the 2026 Hugging Face incident; the gate decides before the action runs. Read the CSA note.

Connect

Connect in ten minutes.

Three ways in, same gate, same receipts. Pick the one your platform already speaks.

MCP: three hosted tools

If your agent platform connects to MCP servers, add https://agentguard.run/api/mcp and send your vendor key on the connection as Authorization: Bearer agk_vendor_... (or as an X-AgentGuard-Vendor-Key header where the platform reserves Authorization). Tools: gate_authorize, gate_approval_status, gate_policy_example. Without a key the tools run only for tenant sandbox.

// tools/call gate_authorize, the same request body as the REST route
{ "name": "gate_authorize", "arguments": {
    "tenant_id": "sandbox", "agent_id": "storage-bot", "capability_claim": "data_write",
    "action": { "type": "waive_fee", "amount_cents": 5000, "currency": "USD", "target_system": "property_management" },
    "policy": { "id": "storage-bot-v1", "version": 1, "on_unavailable": { "default": "stop" },
                "rules": { "waive_fee": { "required_capability": "data_write", "review_above_cents": 0 } } } } }
// structuredContent: { decision: "escalate", decision_text: "held for a person under the policy", receipt: {...}, on_unavailable_effective: "stop" }

Setup for Claude Code, Cursor and ChatGPT is on the hosted MCP page; the gate tools are listed there with the six public ones.

Webhook: one file, no dependencies

If your platform calls an HTTPS URL on each tool call, run one of these handlers next to your agent. Each receives a small event, asks the gate, and answers proceed or not, with the approval id or the block text. The approval link itself goes to your approver, never back to the agent. When the gate does not answer within two seconds the handler reads your own on_unavailable setting for that action type and notes the gap.

handler.js (Node, standard library) · handler.py (Python, standard library) · README

# the event your platform posts to the handler; metadata only
{ "tool": "waive_fee", "arguments": { "amount_cents": 5000, "currency": "USD", "target_system": "property_management" },
  "tenant_id": "acme-storage", "agent_id": "storage-bot" }
# what the handler answers
{ "proceed": false, "approval_id": "apr_...", "text": "held for a person under the policy" }

REST: one POST

The curl examples below run as is in sandbox. With your key, drop tenant_id; the key names the tenant.

API

The whole contract on one page.

Authentication

Send Authorization: Bearer agk_vendor_.... The key binds every request to your tenant, counts toward that tenant's fleet totals and may open approvals. Without a key the gate runs only in sandbox for the public demos: tenant sandbox or demo, nothing stored, receipts marked sandbox: true. Any other tenant without a key is a 401. Keys are issued on the order form and stored hashed; they never appear in receipts.

Authorize a money action

This example runs in sandbox, so you can paste it as is.

# a $50 late-fee waiver; the policy holds anything above $0 for a person
curl -s https://agentguard.run/api/gate/authorize \
  -H "content-type: application/json" -d '{
    "tenant_id":"sandbox","agent_id":"storage-bot","capability_claim":"data_write",
    "action":{"type":"waive_fee","amount_cents":5000,"currency":"USD","target_system":"property_management"},
    "policy":{"id":"storage-bot-v1","version":1,"window":"per_day","window_cap_cents":50000,
      "fleet_caps":{"money_cents_per_day":200000,"contacts_per_day":400},
      "rules":{"waive_fee":{"required_capability":"data_write","review_above_cents":0,"hard_block_above_cents":50000},
               "issue_refund":{"required_capability":"data_write","review_above_cents":10000,"hard_block_above_cents":50000}}}
  }' | jq '{decision, decision_text, receipt_id: .receipt.receipt_id}'

Authorize a call or a text

Contact actions are place_call and send_sms. The recipient reference and the consent reference are ids or hashes your system already holds; the gate never receives a number. In sandbox you can supply recipient_contacts_24h to simulate the per-recipient count; with a key the gate keeps that count itself.

# a collections call at 9:15 PM in the recipient's time zone
curl -s https://agentguard.run/api/gate/authorize \
  -H "content-type: application/json" -d '{
    "tenant_id":"sandbox","agent_id":"collections-bot","capability_claim":"data_write",
    "evaluated_at":"2026-10-19T01:15:00.000Z",
    "action":{"type":"place_call","recipient_ref":"rcp_7f3a9c","recipient_tz":"America/New_York","consent_ref":"cns_01HZX"},
    "policy":{"id":"storage-bot-v1","version":1,
      "calling_window":{"start":"08:00","end":"20:00"},"consent_required":true,
      "velocity_cap":{"per_recipient_per_24h":2},"fleet_caps":{"contacts_per_day":400},
      "rules":{"place_call":{"required_capability":"data_write"},"send_sms":{"required_capability":"data_write"}}}
  }' | jq '{decision, decision_text, local: .receipt.recipient_local_time_at_evaluation}'

What comes back

{
  "decision": "escalate",                 // allow | escalate | block
  "decision_reason": "amount_above_review_threshold",
  "decision_text": "held for a person under the policy",
  "spend_reserved_cents": 0,              // money counts only on allow
  "on_unavailable_effective": "stop",     // your policy's setting for this action type
  "receipt": { "receipt_type": "money_action_authorization", "receipt_id": "rcpt_...", "tenant_id": "...",
               "policy_hash": "...", "decision": "escalate", "signature": "...", "public_key_hex": "..." },
  "approval": { "id": "apr_...", "expires_at": "...", "link": "https://agentguard.run/api/gate/approvals/apr_...?t=...",
                "status_url": "https://agentguard.run/api/gate/approvals/apr_.../status" },
  "approval_delivery": { "email": { "sent": true, "reason": null }, "sms": null },
  "verify_url": "https://agentguard.run/verify"
}

Policy fields

FieldApplies toEffect
rules[type].required_capabilityallLadder read_only < data_write < payment_initiate < payment_execute. A claim below the rule's level blocks.
rules[type].review_above_centsmoneyAbove this amount the action escalates to a person. Set 0 to hold every waiver or credit.
rules[type].hard_block_above_centsmoneyAbove this amount the action blocks, no person asked.
window_cap_centsmoneyDaily ceiling for one agent's allowed money, supplied by your runtime as window_spent_cents.
calling_window.start / endcontactRecipient local time, start inclusive, end exclusive. An unknown time zone escalates instead of guessing.
consent_requiredcontactBlocks any call or text without a consent_ref. Per-action override under rules[type].
velocity_cap.per_recipient_per_24hcontactBlocks the next contact to the same recipient once the count is reached.
fleet_caps.contacts_per_day, fleet_caps.money_cents_per_dayallTenant-wide daily totals across every agent. See Fleet limits and pause.
on_unavailable[type], on_unavailable.defaultallYour own answer to "what if the gate does not reply": proceed or stop, default stop. The gate never decides this; it echoes the setting back as on_unavailable_effective so your runtime can honor it on a timeout and your records can show the gap.

Approvals

When the decision is escalate, the response carries approval.id and approval.status_url, never the link. The link goes only to the approver set on your vendor key: an email address, and a phone number where SMS delivery is enabled for your tenant. We set these with you when we issue the key; a request cannot name its own approver, so an agent cannot route an approval to itself. If your own server shows the owner an Approve button (a platform connector, for example), we can turn on the link in the response for that server's key only. Never give that key to an agent. The link works once and expires in 24 hours. The person sees the action and two buttons. Their decision is signed and chained to the request receipt, with the approver's label and time. Your agent polls the status with its key:

curl -s https://agentguard.run/api/gate/approvals/apr_YOUR_ID/status \
  -H "authorization: Bearer $AGENTGUARD_VENDOR_KEY" | jq '{status, decided_at, approver_label}'
# status: pending | approved | denied | expired; receipt holds the signed decision once settled

Fleet limits and pause

Fleet caps are tenant-wide and reset each UTC day. When fleet_caps.contacts_per_day is reached, every further call or text for the tenant returns block with the text "fleet cap reached for today in the policy"; fleet_caps.money_cents_per_day does the same for allowed refunds, credits and waivers, counting approved escalations too. An operator can also pause a tenant: every action then returns block with "tenant paused by operator" until the pause is cleared. Pauses are set by us on the operator's request today, through an administered endpoint; a self-serve switch is on the order form.

Decision texts

DecisionText on the receipt
allowpermitted under the policy
escalateheld for a person under the policy; recipient time zone not recognized, held for a person
blockabove the per-action limit set in the policy; above the daily money cap set in the policy; outside the calling window set in the policy; no consent reference supplied, the policy requires one; recipient contact count reached the cap set in the policy; capability below the level the policy requires; fleet cap reached for today in the policy; tenant paused by operator
allow / block by a personpermitted by a person under the policy; denied by a person under the policy

Verify a receipt

jq '{receipt: .receipt}' response.json | curl -s https://agentguard.run/api/verify \
  -H "content-type: application/json" -d @- | jq .ok
# change one byte of the receipt and run it again: ok becomes false

Receipts and exports

Every response carries its receipt, and a decision receipt arrives in the status poll. Keep them with your records; they verify without us. A per-tenant export shaped for an operator, an insurer or an auditor is part of the order form, not a public endpoint yet.

What the gate does not do: it does not move money, place calls or send texts; it does not read conversations; it does not decide whether an action was lawful or appropriate. It records what the operator's policy permitted or held, and who said yes.
Terms

Terms for the hosted gate.

Draft terms for early access. The signed order form controls.

  1. The policy is the operator's setting. Every threshold, window, cap and consent rule in a policy is chosen by the operator or the vendor acting for them. AgentGuard applies it as written and does not choose the numbers.
  2. Metadata in, never customer content. The gate evaluates the action type, amounts, currency, target system category, hashed references and a time zone that the vendor sends. Requests carrying prompts, transcripts, names, numbers or card data are rejected and not stored.
  3. A receipt records what the policy permitted. It is a signed record of the evaluation and of who said yes. It is not legal advice and not a statement that any action met a law, a regulation or a contract.
  4. No warranty about the action itself. AgentGuard does not warrant that any call, text, refund, credit or waiver was lawful, timely, appropriate or authorized by the customer. The gate does not move money, place calls or send texts.
  5. The vendor and the operator answer for their agents. Each remains responsible for what its agents do and say, for the accuracy of the metadata it sends, and for the policy it sets, and indemnifies AgentGuard and Dunecrest Ventures Inc. against claims arising from those actions and that content.
  6. Liability is limited. AgentGuard's total liability under these terms is limited to the fees the vendor paid for the gate in the three months before the claim. No party is liable for indirect or consequential loss.
  7. Availability is a setting you own. Each action type carries the vendor's own on_unavailable choice, proceed or stop. When the gate cannot answer, the vendor's runtime applies that choice and the receipt chain shows the gap. No uptime is promised in early access.
  8. Data kept, keys revoked, law applied. AgentGuard keeps hashed references, amounts, action types, decisions, approval records and signatures, and nothing else from a request. Vendor keys can be revoked by the vendor or by AgentGuard at any time. These terms are governed by the law of the State of Wyoming.
Early access

Price on the order form, per location per month.

The first partners start with a 30-day pilot at 1 to 3 locations. We agree the goal and the price up front and write both on the order form. It takes one engineer's afternoon to wire the call and a real operator policy to run. You keep every receipt whatever happens next.

Talk to us

Tell us what your agent can do.

Answer one question about what your agent does for an operator. We reply with a starting policy that fits, in the request shape above, and the page shows where to look first.