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" }
}

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.

CALL PARAMETERS FOR THRESHOLD RULES
{
  "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.

SCORE AN INHERITANCE REQUEST VIA API
{
  "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

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. Wallet-touch holds need two distinct approver identities (dual control) — the first approval returns {"status": "pending", "dual_control": {...}}
POST /v1/approvals/{id}/denyBearer aag_…Pro+ · decide as the key holder. One deny always denies immediately
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
GET /v1/destructive-gates/rulesBearer aag_…Pro+ · destructive-gate rules
POST /v1/destructive-gates/rulesBearer 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-runBearer aag_…Pro+ · preview the gate decision — no writes
GET /v1/destructive-gates/decisionsBearer aag_…Pro+ · gate audit ledger
POST /v1/reserveBearer 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}/settleBearer aag_…Pro+ · capture the actual: {actual_cost (USD)} · hold releases, actual counts as real spend
POST /v1/reservations/{id}/cancelBearer aag_…Pro+ · release an open hold without spending
GET /v1/reservations?agent_id=&status=Bearer aag_…Pro+ · the reservation ledger
POST /v1/blastradius/evaluateBearer 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

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.