Errors
Updated
All errors have the same shape, and none of them costs credits. Each one tells you whether a retry can help.
The error shape
Every failed call returns JSON like this, with the matching HTTP status:
{
"error": {
"code": "insufficient_credits",
"message": "This call costs up to 2 credits and you have 1.",
"retryable": false,
"docsUrl": "https://chatterapi.com/docs/errors#insufficient_credits",
"topupUrl": "https://chatterapi.com/dashboard/billing",
"instructionsForAgent": "The user's ChatterAPI balance is too low for this call. Tell them and share the topupUrl. Do not retry."
},
"requestId": "req_01JA7Q3V8K2N4P5R6S7T8V"
}code: a stable, machine-readable code. Branch on this rather than on the message.message: a one-sentence description of what went wrong. Forinvalid_inputit names the field.retryable: whether the same request can succeed later.docsUrl: the section of this page for that code.instructionsForAgent: present on 401, 402, 403, 409 and 429. It's written for an LLM and says what to tell the user and whether to retry.requestId: include it when you report a problem to support.
All codes
| Code | HTTP | Retryable | Charged |
|---|---|---|---|
missing_key | 401 | no | 0 |
invalid_key | 401 | no | 0 |
key_revoked | 401 | no | 0 |
account_suspended | 403 | no | 0 |
scope_denied | 403 | no | 0 |
invalid_input | 400 | no | 0 |
not_found | 404 | no | 0 |
insufficient_credits | 402 | no | 0 |
rate_limited | 429 | yes | 0 |
upstream_error | 502 | yes | 0 |
upstream_timeout | 504 | yes | 0 |
x_account_required | 409 | no | 0 |
x_account_needs_reconnect | 409 | no | 0 |
internal | 500 | yes | 0 |
missing_key
HTTP 401, not retryable. The request has no Authorization: Bearer header.
{
"error": {
"code": "missing_key",
"message": "Add the header Authorization: Bearer <your API key>.",
"retryable": false,
"docsUrl": "https://chatterapi.com/docs/errors#missing_key",
"instructionsForAgent": "Ask the user for their ChatterAPI key (it starts with ca_live_). Do not retry without one."
},
"requestId": "req_01JA7Q3V8K2N4P5R6S7T8V"
}What to do: Send Authorization: Bearer ca_live_... on every request. You can create a key on the Keys page of the dashboard.
What an agent should tell the user: Ask the user for their ChatterAPI key (it starts with ca_live_). Do not retry without one.
invalid_key
HTTP 401, not retryable. The key is malformed, or no key with that value exists.
{
"error": {
"code": "invalid_key",
"message": "Unknown API key.",
"retryable": false,
"docsUrl": "https://chatterapi.com/docs/errors#invalid_key",
"instructionsForAgent": "The API key is wrong. Ask the user to copy it again from the Keys page of their dashboard."
},
"requestId": "req_01JA7Q3V8K2N4P5R6S7T8V"
}What to do: Check that you copied the whole key. Keys are ca_live_ or ca_test_ followed by 40 hex characters. A lost key can't be shown again, so create a new one.
What an agent should tell the user: The API key is wrong. Ask the user to copy it again from the Keys page of their dashboard.
key_revoked
HTTP 401, not retryable. The key was revoked from the dashboard.
{
"error": {
"code": "key_revoked",
"message": "This API key was revoked.",
"retryable": false,
"docsUrl": "https://chatterapi.com/docs/errors#key_revoked",
"instructionsForAgent": "This API key was revoked. Ask the user to create a new key on the Keys page."
},
"requestId": "req_01JA7Q3V8K2N4P5R6S7T8V"
}What to do: Create a new key and update your env var. Revoking is permanent.
What an agent should tell the user: This API key was revoked. Ask the user to create a new key on the Keys page.
account_suspended
HTTP 403, not retryable. The account behind the key is suspended.
{
"error": {
"code": "account_suspended",
"message": "This account is suspended.",
"retryable": false,
"docsUrl": "https://chatterapi.com/docs/errors#account_suspended",
"instructionsForAgent": "This ChatterAPI account is suspended. Tell the user to contact support. Do not retry."
},
"requestId": "req_01JA7Q3V8K2N4P5R6S7T8V"
}What to do: Email support with the requestId. Calls will keep failing until the account is restored.
What an agent should tell the user: This ChatterAPI account is suspended. Tell the user to contact support. Do not retry.
scope_denied
HTTP 403, not retryable. An 18+ tool (or nsfw=true) was called on an account that has not turned on 18+ tools, or a write tool was called with a read-only key.
{
"error": {
"code": "scope_denied",
"message": "18+ content is off for this account. Turn it on in Settings after confirming you are 18 or older.",
"retryable": false,
"docsUrl": "https://chatterapi.com/docs/errors#scope_denied",
"instructionsForAgent": "This key or account isn't allowed to use this tool. Tell the user what setting is needed. Do not retry."
},
"requestId": "req_01JA7Q3V8K2N4P5R6S7T8V"
}What to do: Confirm your age and turn on 18+ tools in Settings, or create a key with write access for X actions.
What an agent should tell the user: This key or account isn't allowed to use this tool. Tell the user what setting is needed. Do not retry.
invalid_input
HTTP 400, not retryable. A parameter failed validation, or the request included an unknown parameter. The message names the field.
{
"error": {
"code": "invalid_input",
"message": "limit: Too big: expected number to be <=100",
"retryable": false,
"docsUrl": "https://chatterapi.com/docs/errors#invalid_input"
},
"requestId": "req_01JA7Q3V8K2N4P5R6S7T8V"
}What to do: Fix the named field. Each tool's reference page lists its parameters, types and limits. An expired cursor also returns this error, so restart from the first page.
For agents: do not retry; report the message to the user.
not_found
HTTP 404, not retryable. The user, post, subreddit, tweet or list does not exist, or the path matches no tool.
{
"error": {
"code": "not_found",
"message": "Not found",
"retryable": false,
"docsUrl": "https://chatterapi.com/docs/errors#not_found"
},
"requestId": "req_01JA7Q3V8K2N4P5R6S7T8V"
}What to do: Check the id or name. Reddit account checks return a state instead of this error, so you can tell a deleted account from a suspended one.
For agents: do not retry; report the message to the user.
insufficient_credits
HTTP 402, not retryable. The balance is below the tool's cost. We check this before any upstream call.
{
"error": {
"code": "insufficient_credits",
"message": "This call costs up to 3 credits and you have 1.",
"retryable": false,
"docsUrl": "https://chatterapi.com/docs/errors#insufficient_credits",
"topupUrl": "https://chatterapi.com/dashboard/billing",
"instructionsForAgent": "The user's ChatterAPI balance is too low for this call. Tell them and share the topupUrl. Do not retry."
},
"requestId": "req_01JA7Q3V8K2N4P5R6S7T8V"
}What to do: Top up or upgrade at the topupUrl in the error. Nothing was charged.
What an agent should tell the user: The user's ChatterAPI balance is too low for this call. Tell them and share the topupUrl. Do not retry.
rate_limited
HTTP 429, retryable. You sent more requests per second than your plan allows.
{
"error": {
"code": "rate_limited",
"message": "Over 10 requests per second.",
"retryable": true,
"docsUrl": "https://chatterapi.com/docs/errors#rate_limited",
"instructionsForAgent": "Too many requests per second. Wait retryAfter seconds, then retry once.",
"retryAfter": 1
},
"requestId": "req_01JA7Q3V8K2N4P5R6S7T8V"
}What to do: Wait retryAfter seconds (also in the retry-after header), then retry. Spread your calls out, or upgrade for a higher limit.
What an agent should tell the user: Too many requests per second. Wait retryAfter seconds, then retry once.
upstream_error
HTTP 502, retryable. Every data provider for this tool failed.
{
"error": {
"code": "upstream_error",
"message": "Reddit data is temporarily unavailable. Retry in a few seconds.",
"retryable": true,
"docsUrl": "https://chatterapi.com/docs/errors#upstream_error"
},
"requestId": "req_01JA7Q3V8K2N4P5R6S7T8V"
}What to do: Retry with exponential backoff. If a cached copy exists, you get that instead, marked with a stale_data warning.
For agents: retry with backoff, then report the failure with the requestId.
upstream_timeout
HTTP 504, retryable. The provider took longer than 15 seconds.
{
"error": {
"code": "upstream_timeout",
"message": "X timed out. Retry in a minute.",
"retryable": true,
"docsUrl": "https://chatterapi.com/docs/errors#upstream_timeout"
},
"requestId": "req_01JA7Q3V8K2N4P5R6S7T8V"
}What to do: Retry with backoff. Smaller limit values return faster.
For agents: retry with backoff, then report the failure with the requestId.
x_account_required
HTTP 409, not retryable. An X write tool was called without accountId.
{
"error": {
"code": "x_account_required",
"message": "This X action needs accountId, the id of an X account connected in the dashboard.",
"retryable": false,
"docsUrl": "https://chatterapi.com/docs/errors#x_account_required",
"instructionsForAgent": "This X action needs a connected X account. Ask the user to connect one on the Accounts page and pass its accountId."
},
"requestId": "req_01JA7Q3V8K2N4P5R6S7T8V"
}What to do: Connect an X account in the dashboard and pass its id as accountId.
What an agent should tell the user: This X action needs a connected X account. Ask the user to connect one on the Accounts page and pass its accountId.
x_account_needs_reconnect
HTTP 409, not retryable. The session for the connected X account expired.
{
"error": {
"code": "x_account_needs_reconnect",
"message": "The connected X account needs to be reconnected.",
"retryable": false,
"docsUrl": "https://chatterapi.com/docs/errors#x_account_needs_reconnect",
"instructionsForAgent": "The connected X account's session expired. Ask the user to reconnect it on the Accounts page."
},
"requestId": "req_01JA7Q3V8K2N4P5R6S7T8V"
}What to do: Reconnect the account on the Accounts page, then retry.
What an agent should tell the user: The connected X account's session expired. Ask the user to reconnect it on the Accounts page.
internal
HTTP 500, retryable. This is a bug on our side. We log it with the request id.
{
"error": {
"code": "internal",
"message": "Something went wrong on our side. It has been logged.",
"retryable": true,
"docsUrl": "https://chatterapi.com/docs/errors#internal"
},
"requestId": "req_01JA7Q3V8K2N4P5R6S7T8V"
}What to do: Retry once. If it keeps happening, email support with the requestId.
For agents: retry with backoff, then report the failure with the requestId.
Retry guidance
- Retry only when
retryableis true. - On
rate_limited, wait theretry-afterseconds and then retry. - On
upstream_error,upstream_timeoutandinternal, use exponential backoff with jitter: roughly 0.5s, 1s, 2s, each plus a random fraction. Give up after three or four tries. - Never retry 400, 401, 402, 403, 404 or 409, because the same request will fail the same way.
Reporting a bug
Email support with the requestId from the response (it's also in the x-request-id header) so we can find the exact call in our logs.