# Revoke one agent token, or every live token of an account

`POST /api/v1/agent-tokens/revoke` · operationId `revokeAgentTokens`

For developers: your server sends this request with a server key; it is not a button in the dashboard.

Send exactly one of token (the token itself), tokenId (from the issue response) or accountId (every live token of that account). An empty body, or two of them, is 400 bad_request: nothing is ever revoked by default. Idempotent: revoking a revoked token again answers revoked 0.

## Authentication

Send `Authorization: Bearer YOUR_SERVER_KEY` (siteServerKey: Site server key in Authorization: Bearer <key> (the scheme is case-insensitive and required; a bare key is 401). Shown once on creation or rotation. Publishable keys cannot authenticate). Keep the server key in server-only configuration; never send it to a browser.

## Request body

Content-Type: application/json (required)

Exactly one of token, tokenId or accountId.

- `token` (string, optional)
- `tokenId` (string, optional)
- `accountId` (string, optional) · maxLength 512

```json
{
  "tokenId": "atok_PASTE_TOKEN_ID"
}
```

## Responses

- **200**: Success · body `object`
- **400**: bad_request: the request is invalid; message says what to fix and field names the request field · body `Error`
- **401**: unauthorized (missing or invalid server key, missing Bearer scheme) · body `Error`
- **403**: forbidden: the call came from a browser page or another Site; call from your server with this Site’s server key · body `Error`
- **404**: not_found: unknown path, or an ID in the path that is not on this Site · body `Error`
- **409**: conflict: the request contradicts what is already recorded; message says what · body `Error`
- **413**: payload_too_large: the request body exceeds 131072 bytes · body `Error`
- **429**: rate_limited: wait for Retry-After · body `Error` · headers `Retry-After`
- **500**: internal_error: fail the protected action; do not retry automatically · body `Error`
- **503**: service_unavailable: temporarily unavailable; only verify retries · body `Error`

### Success body fields

- `revoked` (integer, required) · minimum 0: How many live tokens this call revoked.

Failures are not verdicts. Error bodies follow the `Error` schema: `code` is one of `bad_request`, `unauthorized`, `session_reinit_required`, `forbidden`, `not_found`, `conflict`, `identity_required`, `payload_too_large`, `rate_limited`, `internal_error`, `service_unavailable`, `request_failed`, `approval_invalid`, `approval_used`, `approval_expired`, `approval_mismatch`, `step_up_not_held`, `step_up_mismatch`, `step_up_settled`, `step_up_expired`, `step_up_superseded`, `agent_tokens_disabled`, `tool_not_approved`, `tool_not_read_only`. [Errors and retries](/docs/errors) explains each code and what to do.

## Example

```sh tab=curl
curl -sS -X POST 'https://app.trytelltale.dev/api/v1/agent-tokens/revoke' \
  -H "Authorization: Bearer $TELLTALE_SERVER_KEY" \
  -H 'Content-Type: application/json' \
  --data '{"tokenId":"atok_PASTE_TOKEN_ID"}'
```

```js tab=fetch
const response = await fetch("https://app.trytelltale.dev/api/v1/agent-tokens/revoke", {
  method: "POST",
  headers: {
    Authorization: 'Bearer ' + process.env.TELLTALE_SERVER_KEY,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    "tokenId": "atok_PASTE_TOKEN_ID"
  }),
  signal: AbortSignal.timeout(5000)
});
const result = await response.json();
```

Machine-readable contract: [openapi.json](https://app.trytelltale.dev/openapi.json). Request builder: the [API explorer](/docs/api-explorer) shows every operation as curl; it sends requests only on a local dashboard.
