Agent management endpoints are called by humans (dashboard session) and by orchestrators
(an organization API key) — never by the
agents themselves. Agents interact through the MCP server. The org key needs
the scope for what it’s doing: agents:read to list or read agents, agents:write for the
mutations (create, budget policy, pause/resume, archive). A write-only key cannot list — the
scopes are independent, not a hierarchy.
Orchestrators can drive most of these as MCP tools instead of REST — create, list, budget
policy, pause/resume, archive — see the management band. Listing
needs agents:read; the mutations need agents:write. Not everything on this page is
machine-callable: PATCH /v1/agents/:id (name/description) and the key mint/revoke routes
remain session-only and have no management tool — they fail even with agents:write.
Create agent
Creates an agent with a non-custodial crypto wallet, a spending policy, and (bundled) its first API key.
The response includes the agent and its API key. Store it immediately — you get one delivery.
Precisely how “one delivery” works depends on the caller:
- Dashboard session: the key is shown once and never again. If it’s lost, revoke and mint a
new one.
- Organization API key: the key is returned once, but a replay of the same
idempotencyKey and payload re-delivers it for roughly 30 minutes — a deliberate
recovery window for a lost response. After that window it is gone the same way, and the replay
returns apiKey: null.
Machine callers must send idempotencyKey. Omitting it returns 400 IDEMPOTENCY_KEY_REQUIRED. Persist a stable, high-entropy value before you call: on any
ambiguous failure (timeout, network error, code-less 5xx, 409 REQUEST_IN_PROGRESS, 409 ORG_NOT_READY, 503 CREATE_RETRYABLE) you replay the same key and payload to recover the
committed agent. Without it, a lost response means an orphaned agent and an unrecoverable
credential.
Key re-delivery is time-boxed to roughly 30 minutes — act on an ambiguous failure immediately.
A replay only re-delivers the raw apiKey while that window is open. After it closes, the replay
still returns the agent but with apiKey: null, mcpConfigBlock: null, and keyDelivery: "expired". Retry promptly and store the key the moment you receive it. Creation draws on the
key’s daily quota; replaying an
already-completed create is free.
keyDelivery: "expired" does NOT mean the key was never delivered — check your own records
before acting on it. It means only that the response arrived after the ~30-minute delivery
window — which can happen on a late replay or on the very first response of a slow create that
spent long enough provisioning. If your original create response actually arrived, that key is
still live and the agent is perfectly usable; the server cannot tell the two cases apart. So do
not treat an expired result as proof the agent is stranded. Confirm from your own delivery
records that no credential was ever stored, and only then treat it as unrecoverable — the
undelivered credential is still the agent’s one active key, so a human must DELETE /v1/agents/:id/key before POST /v1/agents/:id/key (minting straight away returns 409 KEY_ALREADY_EXISTS). The machine alternative is the zombie-archive
sequence — but note an
expired result from a first response has not stamped the durable non-delivery proof the
archive gate needs, so a direct archive_agent there returns 409 KEY_DELIVERY_UNPROVEN and you
must replay the create (to stamp it) before archiving — and because that stamp is best-effort,
retry the replay + archive a few times with backoff if the code recurs, escalating (not looping)
if it persists. Archiving on the expired flag alone can destroy an agent whose key you are
holding.
List agents
Returns the organization’s agents. Optional filters: projectId, teamId.
Update agent
The budget-policy endpoint updates budgetCents, autoApprovalThresholdCents, perTransactionLimitCents, dailySpendLimitCents, and hourly/daily velocity limits. It takes a version token from the last read for optimistic concurrency — a stale token returns 409 VERSION_CONFLICT, so re-read and retry rather than blind-writing.
Step-up applies to human callers. A session must re-verify (passkey or TOTP). An organization
API key does not — minting the key was itself performed by a human under step-up, and that
ceremony is what authorizes it, so a headless caller is never re-challenged. Reading the current
policy via GET /v1/agents/:id/budget-policy requires agents:write for a key, because it is a
write precondition.
Pause and resume
Pausing is instant and reversible — every payment is denied while paused, and the API key stays intact. See Agent Lifecycle.
API keys
One active key per agent. Minting for an archived agent returns 409 AGENT_ARCHIVED.
Archive agent
Terminal: revokes the key and detaches the wallet policy. Requires step-up auth for human callers. Archived agents cannot be reactivated.
Organization API keys are heavily restricted here. A key may archive only a zombie of its own
making — an agent that key lineage created, whose bundled-key re-delivery window has closed, that
never authenticated and has no activity, holds a zero balance, and whose keys no human has ever
minted or revoked (any human key management permanently disqualifies the machine path — the
agent is no longer a machine orphan). Note the server cannot prove the key was never delivered
(only that it can no longer be re-delivered and was never used), so confirm from your own records
before archiving.403 MACHINE_ARCHIVE_DENIED is terminal — a human must archive from the dashboard. But not
every non-success is terminal. Two 409s are recoverable — KEY_STILL_DELIVERABLE (replay the
create to recover the key and keep the agent) and KEY_DELIVERY_UNPROVEN — and so are 409 BALANCE_UNVERIFIABLE (balance couldn’t be confirmed zero; retry later) and a 200 carrying a
non-empty walletsFailed array (the local archive committed but a wallet detach failed; re-issue
the DELETE until it comes back empty). Full sequences on the management
band.
For an emergency hard stop, pause the agent and revoke its API key. Everything halts immediately,
and it’s fully reversible.