Agent Auth Gateway v1.0

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).

PYTHON requests
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
JAVASCRIPT fetch
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

DecisionMeaningYour loop should
ALLOWPolicy passed: caps, lists, risk tier all clear.Run the action.
DENYKill switch, denylist, or a cap would be breached. Fail-closed.Skip it; log gate.reason.
REQUIRE_APPROVALUnlisted 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.

CONSENT ATTESTATION ON EVERY IMAGE-GEN CALL
{
  "agent_id": 7,
  "action": "generate_image",
  "estimated_cost": 0.04,
  "context": { "consent_attested": true, "attested_by": "workflow:consent-form-v2" }
}

API reference

EndpointAuthNotes
POST /v1/proxyBearer aag_…Body: agent_id action estimated_cost (USD) · 300 req/min per key
GET /v1/agentsBearer aag_…Agents with live spend vs caps
GET /v1/approvals?status=pendingBearer aag_…Pro+ · poll for decisions
POST /v1/approvals/{id}/approveBearer aag_…Pro+ · decide as the key holder
POST /v1/approvals/{id}/denyBearer aag_…Pro+ · decide as the key holder
POST /v1/agents/{id}/killBearer aag_…Body {"enabled": false} disables instantly
GET /v1/policy-rulesBearer aag_…Pro+ · consent-gated policy rules
POST /v1/policy-rulesBearer aag_…Pro+ · create rule: {name, patterns, mode, agent_id?, trip_kill_switch?}
DELETE /v1/policy-rules/{id}Bearer aag_…Pro+ · delete rule

Webhooks PRO

POSTED TO YOUR WEBHOOK URL · PUBLIC HOSTS ONLY
{
  "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.