Documentation
The 3-line integration.
Wrap the tool call you already make. Ask the gateway first. Obey the decision. Your agent needs an API key (create one under Console → API keys) and its agent id (shown on the agent page).
import requests def authorized(agent_id, action, estimated_cost=0.0): """Ask the gateway. Returns (decision, payload).""" r = requests.post( "https://agent-auth-gateway.onrender.com/v1/proxy", headers={"Authorization": "Bearer aag_YOUR_KEY"}, json={"agent_id": agent_id, "action": action, "estimated_cost": estimated_cost}, timeout=10) r.raise_for_status() g = r.json() return g["decision"], g # in your agent loop: decision, gate = authorized(7, "send_email", 0.02) if decision == "allow": send_email(draft) elif decision == "deny": log(f"blocked: {gate['reason']}") else: # require_approval approval_id = gate["approval_id"] wait_until_decided(approval_id) # poll GET /v1/approvals
async function authorized(agentId, action, estimatedCost = 0) { const r = await fetch( "https://agent-auth-gateway.onrender.com/v1/proxy", { method: "POST", headers: { "Authorization": "Bearer aag_YOUR_KEY", "Content-Type": "application/json" }, body: JSON.stringify({ agent_id: agentId, action, estimated_cost: estimatedCost }), }); if (!r.ok) throw new Error(await r.text()); const g = await r.json(); return [g.decision, g]; } // in your agent loop: const [decision, gate] = await authorized(7, "send_email", 0.02); if (decision === "allow") await sendEmail(draft); else if (decision === "deny") log(`blocked: ${gate.reason}`); else await waitUntilDecided(gate.approval_id);
Decisions
| Decision | Meaning | Your loop should |
|---|---|---|
| ALLOW | Policy passed: caps, lists, risk tier all clear. | Run the action. |
| DENY | Kill switch, denylist, or a cap would be breached. Fail-closed. | Skip it; log gate.reason. |
| REQUIRE_APPROVAL | Unlisted or high-risk action. Held for a human (Pro+). | Poll GET /v1/approvals until decided. |
Consent-gated image tools PRO
Consent-gated policy rules (Pro) gate image-generation tool calls on consent attestation metadata — deterministic, never an accuracy play: the gateway checks that the call carries context.consent_attested=true plus a non-empty context.attested_by. It never judges image content. Install the one-click ARTICLE5_CONSENT_GATE template (Console → Policy templates) ahead of the EU AI Act Article 5 enforcement wave on 2 Dec 2026. Missing attestation → the call is denied or routed to the approval queue per the rule's mode, and can optionally trip the agent's kill switch. Every decision lands in the audit log with the rule name, agent identity, and the missing-attestation reason.
{
"agent_id": 7,
"action": "generate_image",
"estimated_cost": 0.04,
"context": { "consent_attested": true, "attested_by": "workflow:consent-form-v2" }
}Destructive-action gates PRO
Destructive-action gates (Pro) make irreversible tool calls impossible to auto-execute — deterministic, never an accuracy play: the gateway matches the call name and detail text against your fnmatch or regex patterns (e.g. *delete*, re:drop\s+(table|database|schema)) plus parameter thresholds read from the call context (e.g. record_count >= 100). Fail-closed: a call that doesn't declare the parameter is treated as meeting the threshold, so agents can't dodge a bulk rule by omitting it. A matched call is denied outright, held for human approval with a dry-run preview of exactly what would happen, or auto-denied when it would also breach the agent's budget cap — and can optionally trip the agent's kill switch. Every decision (held, approved, denied, auto-denied, expired) lands in the gate audit ledger with the full context and a pre-execution state snapshot. Install the one-click DESTRUCTIVE_GATE template (Console → Destructive gates). Preview any call without side effects at POST /v1/destructive-gates/dry-run.
{
"agent_id": 7,
"action": "delete_records",
"estimated_cost": 0.02,
"context": { "record_count": 500 }
}Infra-agent blast-radius bound PRO
The blast-radius bound (Pro) caps an infra agent's credential inheritance at provisioning time — the only checkpoint that works on agents whose changes take effect immediately with no PR/CI review. Declare the bound per agent (allowed credential scopes, egress domains, persistence vectors, max score); the inherited scopes are scored 0–100, MITRE ATT&CK-mapped (each scored scope lists the ATT&CK tactics + technique IDs the inherited credential could enable — e.g. cloud:admin → T1078, T1136, T1098). Anything above the bound holds for your approval via the approval queue — never silently escalated. Every inheritance decision (allow / hold / grant / denial) is appended to a hash-chained evaluation ledger; the console verifies the chain and flags tampering.
What it does NOT claim: scores are advisory estimates, never "safe" certifications — a sub-bound score does not mean the agent is safe. The bound cannot stop breaches that bypass credential inheritance (social engineering, supply-chain compromise of the agent's own code, a cloud admin widening the service account directly at the provider). ATT&CK technique mapping is heuristic, not detection evidence. Unknown scope tokens hold for approval by design until the scored catalog covers them.
{
"agent_id": 7,
"requested_scopes": ["db:read", "ssh:exec"]
}POST the above to POST /v1/blastradius/evaluate (Bearer key, Pro plan) → {"decision": "allow"} or {"decision": "require_approval", "approval_id": 42, "score": 68, "band": "High", "attack_tactics": [...]}. Read the bound with GET /v1/blastradius/policy?agent_id=7. Console: agent detail → Blast-radius bound →.
API reference
| Endpoint | Auth | Notes |
|---|---|---|
| POST /v1/proxy | Bearer aag_… | Body: agent_id action estimated_cost (USD) · 300 req/min per key |
| GET /v1/agents | Bearer aag_… | Agents with live spend vs caps |
| GET /v1/approvals?status=pending | Bearer aag_… | Pro+ · poll for decisions |
| POST /v1/approvals/{id}/approve | Bearer aag_… | Pro+ · decide as the key holder. Wallet-touch holds need two distinct approver identities (dual control) — the first approval returns {"status": "pending", "dual_control": {...}} |
| POST /v1/approvals/{id}/deny | Bearer aag_… | Pro+ · decide as the key holder. One deny always denies immediately |
| POST /v1/agents/{id}/kill | Bearer aag_… | Body {"enabled": false} disables instantly |
| GET /v1/policy-rules | Bearer aag_… | Pro+ · consent-gated policy rules |
| POST /v1/policy-rules | Bearer aag_… | Pro+ · create rule: {name, patterns, mode, agent_id?, trip_kill_switch?} |
| DELETE /v1/policy-rules/{id} | Bearer aag_… | Pro+ · delete rule |
| GET /v1/destructive-gates/rules | Bearer aag_… | Pro+ · destructive-gate rules |
| POST /v1/destructive-gates/rules | Bearer aag_… | Pro+ · create gate rule: {name, patterns, param_conditions, mode, agent_id?, trip_kill_switch?} |
| DELETE /v1/destructive-gates/rules/{id} | Bearer aag_… | Pro+ · delete gate rule |
| POST /v1/destructive-gates/dry-run | Bearer aag_… | Pro+ · preview the gate decision — no writes |
| GET /v1/destructive-gates/decisions | Bearer aag_… | Pro+ · gate audit ledger |
| POST /v1/reserve | Bearer aag_… | Pro+ · reserve budget before a high-cost action: {agent_id, action, amount (USD), note?, ttl_minutes?} → open hold, or held + approval when it would breach a cap |
| POST /v1/reservations/{id}/settle | Bearer aag_… | Pro+ · capture the actual: {actual_cost (USD)} · hold releases, actual counts as real spend |
| POST /v1/reservations/{id}/cancel | Bearer aag_… | Pro+ · release an open hold without spending |
| GET /v1/reservations?agent_id=&status= | Bearer aag_… | Pro+ · the reservation ledger |
| POST /v1/blastradius/evaluate | Bearer aag_… | Pro+ · score a credential inheritance request: {agent_id, requested_scopes[]} → allow or hold (approval_id) |
| GET /v1/blastradius/policy?agent_id= | Bearer aag_… | Pro+ · read the agent's declared blast-radius bound |
Webhooks PRO
{
"event": "approval.required", // or "approval.decided"
"approval_id": 42,
"agent": "billing-agent",
"action": "refund_customer",
"estimated_cost_cents": 420,
"approve_url": "https://…/a/SIGNED_TOKEN" // no login needed
}Rate limits: /v1/proxy 300/min per key · other v1 endpoints 120/min per key. Every response includes a human-readable reason.