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" }
}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 |
| POST /v1/approvals/{id}/deny | Bearer aag_… | Pro+ · decide as the key holder |
| 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 |
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.