Docs › API reference › Errors
API errors: status codes, error codes, failures
The error envelope, every status and code the API returns, and the failure object that explains why one channel did not post.
There are two kinds of error. A request error means the API refused your request: it comes back as an HTTP
error status with an error envelope. A channel failure means the request was fine but one channel did not
post: it sits on that channel's result as a failure object, and the HTTP status is still a success.
The error envelope
Every request error has the same shape:
codeis stable and lower-case with underscores. Branch on this, not onmessage.messageis one plain sentence. It may change wording, so do not parse it.detailsis present only when it carries something. Otherwise the key is absent.
details can hold:
| Key | When |
|---|---|
rejections |
nothing_to_publish: a list of {channelId, failure} |
current |
stale_write and not_editable: the post or draft as it is now |
failure |
A refused connect: the full failure object |
limit and plan |
plan_limit_reached: which limit (channels or posts_per_month) and the plan id |
{
"error": {
"code": "text_too_long",
"message": "One plain sentence you can show to a person.",
"details": {}
}
}
Status and code pairs
| Status | Code | When |
|---|---|---|
| 400 | invalid_request |
Malformed JSON, a missing or mistyped field, id, cursor or time, an unreadable If-Match, an Idempotency-Key outside 1 to 255 characters, queue: true together with scheduledFor, or an upload with no file part |
| 401 | unauthenticated |
No key or session, or a bad one |
| 401 | invalid_credentials |
Log in: the email and password do not match |
| 403 | csrf |
A cookie-authenticated write without X-OmniPosts-Client: web |
| 403 | forbidden |
A key on a person-only action, or a non-owner on an owner-only one |
| 404 | not_found |
No such id. This is also what another organization's id returns: OmniPosts never reveals that it exists |
| 405 | method_not_allowed |
The path does not take that method |
| 409 | idempotency_conflict |
Same Idempotency-Key, different request. See Idempotency |
| 409 | stale_write |
If-Match did not match. details.current holds the current object |
| 409 | already_promoted |
The draft was already published or discarded |
| 409 | not_editable |
The draft is no longer a draft. details.current holds it |
| 409 | already_dispatched |
A post cannot be edited because a channel has started sending |
| 409 | already_sent |
Alt text cannot change because a post using that media was already sent |
| 409 | email_taken |
Sign up with an email that already has an account |
| 415 | unsupported_media_type |
The body is not JSON (or multipart for uploads) |
| 422 | nothing_to_publish |
Every channel was rejected. details.rejections says why for each |
| 422 | invalid_edit |
The new body fails a channel's rules |
| 422 | plan_limit_reached |
Your plan's limit is used up. See details.limit and details.plan |
| 422 | queue_empty |
queue: true, but you have no posting times |
| 422 | queue_full |
queue: true, but every posting time in the next 12 weeks is taken |
| 422 | media_rejected |
The upload is empty, too large, unreadable or the wrong type |
| 422 | invalid_webhook |
The webhook URL or event list was refused |
| 422 | terms_required, weak_password, password_too_long |
Sign up |
| 422 | confirmation_required |
Delete account without "confirm": "DELETE" |
| 422 | a failure code | A refused connect. error.code is the failure's code, for example channel_switched_off or not_configured |
| 429 | rate_limited |
Too many requests. See Rate limits |
| 500 | internal_error |
Something went wrong on our side. Try again |
A 422 always means the request was understood but cannot be done as sent. Change something before you
retry. A 409 means the state moved: fetch the current object, then decide. A 5xx and a 429 are safe to
retry with backoff. For POST /v1/groups, send an Idempotency-Key so the retry cannot post twice.
The failure object
A target (the result for one channel) that did not post carries a failure. The same object appears in
rejections, in webhook payloads, and in details.failure on a refused connect.
| Field | Meaning |
|---|---|
class |
RECONNECT, RETRYABLE, UNKNOWN, USER_ERROR or PLATFORM_BLOCKED. The kind of problem |
code |
A stable token for this problem. The set of codes grows and differs per platform, so do not switch on a fixed list |
message |
One plain sentence to show a person |
action |
The single thing to offer: RECONNECT, NONE_AUTO_RETRYING, VERIFY_MANUALLY, FIX_CONTENT, CONTACT_SUPPORT or RETRY |
retryable |
Whether POST /v1/groups/{id}/retry will try this channel again |
Show message and exactly one button chosen by action. Decide by class and action, never by code.
| Class | Usual action | What it means and what to do |
|---|---|---|
RECONNECT |
RECONNECT |
The platform no longer accepts the saved login. Send the person to reconnect the channel. retryable is false: once reconnected, send a new post |
RETRYABLE |
NONE_AUTO_RETRYING |
A temporary problem. OmniPosts is retrying by itself, so do nothing. While it is retrying the target is not yet failed |
RETRYABLE |
RETRY |
Automatic retries are used up and the target is failed. retryable is true: call retry |
UNKNOWN |
VERIFY_MANUALLY |
OmniPosts could not confirm whether the post went out. Look at the channel yourself. retryable is never true, because a retry could post twice |
USER_ERROR |
FIX_CONTENT |
The post itself is the problem: too long, wrong media, a missing setting. Change the text, media or settings, then send again |
PLATFORM_BLOCKED |
CONTACT_SUPPORT |
The platform or the channel is blocking posts (for example the channel is switched off, or the account is suspended). Retrying will not help. Contact support |
A target rejected when you create the post (a rejection) is stored as a failed target, so it also appears in
targets and in the results inbox.
{
"class": "RETRYABLE",
"code": "platform_error",
"message": "One plain sentence.",
"action": "NONE_AUTO_RETRYING",
"retryable": true
}