Errors and limits
Every error body is application/problem+json: {"type", "title", "status", "detail"}.
| Status | Meaning | What to do |
|---|---|---|
400 |
Domain validation (detail says what is wrong; errors lists invalid fields; an unknown scope on POST /v1/api-tokens lists them in invalid), or accountId missing when the credential reaches several accounts |
Fix the payload; do not retry unchanged. |
401 |
Missing, malformed, expired or revoked credential | Stop. Ask the owner for a new token. Never loop on 401. |
403 naming a scope |
The token lacks a scope (detail: The API token lacks the scope 'broadcasts:write'.) or the route is not available to tokens |
Ask for a token with that scope, or use another route. |
403 without a scope in detail |
The resource belongs to an account the credential cannot use (other account, or the token is bound to another account) | Check GET /v1/me. |
404 |
Missing, or not visible to this account | List again before assuming it is gone. |
409 |
Conflict (bot already connected elsewhere, execution cannot be reprocessed, a job already running) | Read detail. |
429 |
Over the per token limit | Wait the Retry-After seconds, then continue. |
Limits: 120 requests per minute per token (fixed 60 second window, configurable by ApiTokens:RateLimit). The counter is kept per API instance, so the effective ceiling can be higher behind the load balancer; do not rely on that. User JWT sessions are not rate limited here. GraphQL windows are capped (365 days, leadFunnel 7 days); lists clamp limit to 1..200 (100 on leads, flows and broadcasts).
Retries: safe for GET. For writes, retry only after 429 or a network error, and only when you have confirmed (by reading) that the first attempt did not take effect. Use exponential backoff with jitter starting at 1 second for 5xx.