REST APIAuthentication

Regent has three production hosts and two kinds of key. Sending the wrong kind returns a 401 on every host, so check this table first:

HostWhat it isKey to sendWhere you get it
api.regentprotocol.orgPlatform API — organizations, agents, mandates, audit, KYCOrg API key rgnt_…Dashboard → API Keys → Create API key
control-api.regentprotocol.orgRegent Control decision API — /v1/control/decisions, /complete, receipts, JWKSControl key rgnt_ctrl_…Dashboard → Control → Onboarding, or Admin MCP create_control_key
gw.regentprotocol.orgCloud Gateway — governed tool calls on the agent’s behalfControl key rgnt_ctrl_… + X-Agent-Id headersame as above

An org key on control-api answers 401 {"code":"UNAUTHORIZED","message":"invalid API key"}; a control key on api.regentprotocol.org answers 401 {"code":"INVALID_API_KEY"}. The two are different secrets scoped to the same organization — the control key never reaches the platform API and never reads your org’s data.

The rest of this page is about the platform API. Its requests authenticate with a single header:

Authorization: Bearer rgnt_<your-api-key>

Or equivalently (some tools prefer the explicit header name):

X-API-Key: rgnt_<your-api-key>

Get an API key

From the dashboard: API Keys → Create API Key. The rgnt_… value is shown once.

Smoke test

curl https://api.regentprotocol.org/v1/organizations/<org-id>/agents \
  -H "Authorization: Bearer rgnt_..."

A 200 with a JSON array (possibly empty) means auth and org scoping are both working.

A 401 means the key is missing/expired. A 403 with code: NOT_MEMBER means the key is for a different org than the one in the path.

Org scoping

Every /v1/organizations/{org_id}/... endpoint requires the org ID to match the org your API key is scoped to. The gateway enforces this server-side — you can’t access another org’s data even if you guess UUIDs.

Rate limits

Current per-IP limits: 30 requests/second (burst 20) on API routes; login and signup are limited to 5/min. Rate-limited responses return 429 RATE_LIMITED with a Retry-After header.

Error format

Every non-2xx returns the same shape:

{
  "detail": {
    "code": "MANDATE_LIMIT_EXCEEDED",
    "category": "PER_TX",
    "message": "amount exceeds the per-transaction allowance",
    "authorization_id": "abc..."
  }
}

See the error code reference for the full list.

What next