Errors and rate limits
What each status code means, the error body, and how to back off.
Error bodies
Every error returns an HTTP status and a JSON body with a readable error, plus issues when the request failed
validation:
{
"error": "You don't have permission to publish posts (post:publish).",
"issues": []
}
Errors are written to be shown to a person or read by an agent: they say what was refused and why.
| Status | Meaning | What to do |
|---|---|---|
400 | The request is invalid: a field is missing, or the post breaks a network's rule (too long, wrong media). issues says which. | Fix the request. Don't retry it unchanged. |
401 | No credential, a malformed one, or a revoked key or withdrawn sign-in. | Check the Authorization header. |
403 | The credential is valid but lacks a permission (named in the message), or the plan doesn't include the feature. | Use a credential with that permission, or upgrade. |
404 | It doesn't exist, or it belongs to another workspace. | Check the id. |
409 | A conflict: the post already moved on (it published, or someone decided its approval first). | Read the current state, then decide. |
429 | Rate limited. | Wait for Retry-After seconds, then retry. |
502 | A network or provider we called failed, or our access to it is broken. | Retry later; if it persists, reconnect the channel. |
500 | Something went wrong on our side. | Retry later, and tell support if it persists. |
Rate limits
Limits are counted per credential (each API key, or each signed-in person), never per workspace, so one busy integration can't lock your team out.
- Endpoints that cost something, such as AI generation, link previews, GIF search, inbox replies and forced inbox syncs, each have their own budget.
- The MCP server allows 240 tool calls a minute per credential.
A 429 carries a Retry-After header in seconds. A 429 is always safe to retry, because the limiter refuses before
anything runs.
Retrying writes safely
Don't blindly retry a POST that failed with a 5xx or a dropped connection: a POST /posts may already have
committed, and replaying it publishes twice. Read the post back (GET /posts, or GET /posts/publish-status)
first. The SDK follows this rule for you.
Platform limits
Network limits, like X's 280 characters or Instagram's five hashtags, are enforced on our side before anything is
sent, and come back as a 400 with the reason. Fit posts up front with GET /api/v1/platforms, which
serves the same rules.