Error envelope
Every error response, regardless of status code, follows the same JSON shape:
json
{
"error": {
"code": "insufficient_credits",
"message": "Out of API credits. Top up or wait for the next refill cycle."
}
}The code field is stable and machine-readable; switch on it. The message field is human-friendly and may evolve.
Status codes
| Param | Type | Notes |
|---|---|---|
401 | unauthorized | Bearer token missing, malformed, or revoked. |
402 | insufficient_credits | Wallet is empty. Wait for the monthly refill or top up. |
403 | plan_required | Account is signed in but not on the Developer plan. |
403 | account_banned | Account is suspended. Contact support. |
403 | forbidden | Authenticated, but not allowed to touch this resource (e.g. someone else's campaign). |
404 | *_not_found | creator_not_found, post_not_found, campaign_not_found. |
409 | duplicate_request | The request id was already processed. Retries are idempotent. |
422 | missing_parameter | A required body or query parameter was omitted. |
422 | invalid_campaign | Campaign create payload failed validation. |
429 | rate_limited | Throttled. Honor the Retry-After header. |
502 | upstream_error | TikTok analysis pipeline is unreachable. Credits are refunded automatically. |
500 | internal_error | Something on our end. Sentry has it; ping us if it persists. |
Retrying safely
All endpoints accept a request_id derived from the HTTP X-Request-Id header (or generated if absent). Repeating the same request id yields 409 duplicate_request and does not double-charge or double-act. This makes naive retries safe.
Recommendation
For batch
POST /v1/posts/analyze calls, generate one stable UUID per logical batch and pass it as X-Request-Id. Network blips become free retries instead of accidental double-charges.