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.

Updated

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:

  • code is stable and lower-case with underscores. Branch on this, not on message.
  • message is one plain sentence. It may change wording, so do not parse it.
  • details is 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
}