API Basics
Errors
Read the error envelope, decide what to do for each HTTP status, and look up every error code.
Every error has the same shape and a stable code. The code and the HTTP status tell you to fix the request, wait, or reconnect an account.
Error Envelope
Every error response has this body.
{
"error": "Invalid request: geoRestriction entries must be uppercase ISO 3166-1 alpha-2 codes (e.g. \"US\").",
"code": "VALIDATION_ERROR",
"param": "accounts.0.x.geoRestriction.0",
"requestId": "req_8f2a64c1d3b94e0f9a7c5e2b1d0f3a6c"
}Prop
Type
Empty fields are left out. A code never changes its meaning. New codes can appear, so handle an unknown one by its HTTP status.
Request Ids
Every response has a Request-Id header, such as req_8f2a64c1d3b94e0f9a7c5e2b1d0f3a6c. Errors repeat it as requestId. Log it so support can find the request.
HTTP Status Codes
| Status | Meaning | What to do |
|---|---|---|
400 | The request is invalid, or the platform lacks the action | Fix the request |
401 | The API key is missing, invalid or deleted | Send a valid key. See Authentication |
402 | Billing is blocked, a payment method is needed, or the wallet is short | Fix it in the dashboard. See Pricing |
403 | The key is read_only, or this caller cannot take the action | Use a read_write key |
404 | Nothing has this id here, or the id is of another kind | Check the id and its prefix |
409 | A reconnect is needed, the state is wrong, or an Idempotency-Key conflicts | Read code, then reconnect or check the state |
422 | The platform refused, such as for a missing permission | Fix the cause in code |
429 | A rate limit, or the platform is limiting the account | Wait for Retry-After. See Handle 429 |
500 | An unexpected error | Try again. If it repeats, contact support |
502 | The platform failed or did not respond, for now | Try again later |
503 | The action is paused, such as uploads or new connections | Try again later |
A 400 or 422 sent again unchanged returns the same error.
Publish Failures
POST /v1/posts checks the whole request first. If any account cannot take the post, nothing is created. After a 201, each post publishes on its own. A post that fails ends as failed, with the reason in error.
{
"id": "pst_8b7f2c641e3d4f9ab2c56d0e8a4f1b27",
"groupId": "grp_7d2e5b1a9c4f4a68b3e07f1c2d9a6e45",
"accountId": "acc_YOUR_INSTAGRAM_ACCOUNT_ID",
"platform": "instagram",
"status": "failed",
"platformPostId": null,
"url": null,
"error": {
"code": "MEDIA_UNFETCHABLE",
"message": "Could not download media URL (HTTP 403)."
}
}- The posts of one request share a
groupId, but each succeeds or fails alone. X can bepublishedwhile Instagram isfailed. - A failed post is final. Fix the cause and create a new post.
- The
post.failedwebhook carries the same post. PUBLISH_INTERRUPTEDmeans the post may be live. Check the platform before you post again.TOKEN_INVALIDfrom any request marks the account for a reconnect.
More in Failed Posts.
Webhook Failures
An event can arrive more than once, so skip any id you have handled. A failed delivery never affects publishing. Send it again with Retry Delivery. See Delivery and Retries for the full delivery rules.
Billing
Billing errors return 402. A blocked workspace gets PAYMENT_METHOD_REQUIRED or PAYMENT_PAST_DUE on every request, reads included. details.billingState names the cause. An X action the wallet cannot cover returns INSUFFICIENT_WALLET. See Billing Blocks.
Best Practices
- Build logic on
codeand the status. Logerror,param,detailsandrequestId. - Send an
Idempotency-Keywith everyPOST, and reuse it on a retry. See Idempotent Requests. - Check each post's
status. One request can publish on X and fail on Instagram. - Reconnect any account that is not
activebefore a publish fails. See Account Status. - Retry
429,500,502and503after a wait. Fix the request on any other4xx. - Reconnect on
TOKEN_INVALID,TOKEN_EXPIREDorCONNECTION_INACTIVE.
Error Codes
Every code, grouped by area.
In the Status column, Post means the code also shows in a post's error.code. Analytics means it shows in an analytics reading's error. Neither is an HTTP error. A code with several statuses lists them all.
Requests and Authentication
| Code | Status | Cause | Fix |
|---|---|---|---|
VALIDATION_ERROR | 400, Post | A field is missing, unknown or invalid, such as a wrong id kind, a long text, an unsupported option or a bad schedule. As a post error, the platform refused a parameter | Fix the field in param or error |
INVALID_CURSOR | 400 | cursor is not a nextCursor of this list | Use the last nextCursor, or drop cursor |
UNAUTHORIZED | 401 | The API key is missing, invalid or deleted | Send a valid key. See Create an API Key |
FORBIDDEN | 403 | A read_only key tried to write, a key limited to some profiles managed profiles or named another profile, or another workspace started the connect session | Use a read_write key, a key with access to all profiles, or this workspace's key |
GROUP_DISABLED | 403 | The key's restricted access turned off this part of the API. details.group names it | Use a key that has the group |
NOT_FOUND | 404, Post | Nothing with this id exists in the workspace, or its prefix is wrong. As a post error, the post or its account was removed first | Check the id |
IDEMPOTENCY_KEY_REUSED | 409 | The Idempotency-Key was used for another request | Use a new key |
IDEMPOTENCY_KEY_IN_USE | 409 | A request with this Idempotency-Key is still running | Wait for Retry-After, then retry |
RATE_LIMITED | 429, Post, Analytics | An API or publishing limit was hit, or the platform slowed the account | Wait for Retry-After or the time in the message. See Rate Limits |
QUOTA_EXCEEDED | 429, Post, Analytics | The platform is at capacity for this action | Try again after the time in the message |
INTERNAL_SERVER_ERROR | 500 | An unexpected error | Try again later. If it repeats, contact support with the requestId |
SERVICE_UNAVAILABLE | 503 | The service is paused for now, such as media uploads | Try again later. If it repeats, contact support with the requestId |
Billing and Wallet
| Code | Status | Cause | Fix |
|---|---|---|---|
PAYMENT_METHOD_REQUIRED | 402 | The workspace has 3 or more accounts and no payment method | Add a payment method in the dashboard |
PAYMENT_PAST_DUE | 402 | A payment failed | Update the payment method and pay the invoice |
INSUFFICIENT_WALLET | 402, Post | The wallet cannot pay for an X action. Nothing is created or changed. As a post error, a scheduled X post was not covered at publish time | Top up the wallet, then retry. Check the balance with GET /v1/wallet |
USAGE_BILLING_REQUIRED | 402 | A 3rd account needs a payment method | Add a payment method, then connect again |
USAGE_BILLING_FAILED | 402 | Billing for the new account failed, so it was not connected | Check the payment method and connect again |
Accounts and Connections
| Code | Status | Cause | Fix |
|---|---|---|---|
ACCOUNT_NOT_FOUND | 404, Analytics | No account has this id in the workspace, or a picked Instagram account has no linked Page | Use an id from List Accounts |
CONNECTION_INACTIVE | 409, Post, Analytics | The account is disconnected or its access was revoked | Reconnect the account |
CONNECTION_BROKEN | 409 | The Instagram account on Facebook Login has no linked Page | Reconnect the account |
TOKEN_INVALID | 409, Post, Analytics | The platform revoked the account's access. The account turns revoked and account.revoked is sent | Reconnect the account |
TOKEN_EXPIRED | 409, Post, Analytics | The platform says the account's access expired | Try again. If it repeats, reconnect |
PERMISSION_DENIED | 422, Post | A permission is missing, or the platform refused the action | Reconnect and approve every permission. On TikTok, the message may ask for a private account |
ACCOUNT_RESTRICTED | 422, Post, Analytics | X or TikTok restricted the account, such as a suspension or posting ban | Fix it on the platform, then try again |
ACCOUNT_SUSPENDED | 422, Post, Analytics | Bluesky took down, suspended or deactivated the account | Restore the account on Bluesky |
AUTH_FAILED | 422 | Bluesky rejected the handle or App Password | Check the handle and create a new App Password |
CONNECT_FAILED | 400 | The account could not be connected, such as when it already is | Check for an existing account |
RECONNECT_MISMATCH | 400 | A reconnect used another account | Reconnect with the same account |
BLUESKY_RECONNECT_APP_PASSWORD | 400 | A Bluesky reconnect has no identifier and appPassword | Send both |
INVALID_REDIRECT_URL | 400 | redirectUrl is not HTTPS or has credentials. HTTP works only for localhost | Send a valid HTTPS URL |
REDIRECT_URL_REQUIRED | 400 | The connect session or reconnect needs a redirectUrl | Send redirectUrl |
INVALID_CONNECT_SESSION | 400 | connectSession is malformed, changed or over 10 minutes old | Create a new connect session |
FACEBOOK_PAGES_FAILED | 400 | The user's Facebook Pages could not be listed | Try again, or create a new connect session |
INSTAGRAM_ACCOUNTS_FAILED | 400 | The linked Instagram accounts could not be listed | Try again, or create a new connect session |
PAGE_NOT_FOUND | 404 | The user cannot access the picked Facebook Page | Pick a Page from the candidates |
PLATFORM_MAINTENANCE | 503 | Connects and reconnects to this platform are paused | Try again later |
PROFILE_IN_USE | 409 | An API key is limited to the profile you tried to delete | Delete the keys limited to it first |
PROFILE_NAME_TAKEN | 409 | The name exists in any letter case, or is reserved | Choose another name |
PROFILE_NOT_FOUND | 404 | No profile has the name in the path | List the profiles and use a current name |
UNSUPPORTED_PLATFORM | 400, Analytics | The account's platform does not have this action | Use an account on a supported platform |
STATS_FAILED | 502 | The platform did not return account stats | Try again. Reconnect if the message says so |
LIST_FAILED | 502 | The platform did not return the account's media or posts | Try again. Reconnect if the message says so |
REVIEWS_FAILED | 502 | Facebook did not return the Page reviews | Try again. Reconnect if it keeps failing |
PROFILE_FAILED | 502 | Facebook did not read or update the Messenger profile | Check the input and try again |
CREATOR_INFO_FAILED | 502, Post | TikTok creator info did not load. Creating or editing a TikTok post needs it, so nothing is created | Try again. Reconnect if it keeps failing |
BOARDS_FAILED | 502 | Pinterest boards could not be listed | Try again. Reconnect if it keeps failing |
BOARD_CREATE_FAILED | 502 | Pinterest did not create the board | Check the message and try again |
SANDBOX_MISMATCH | Post | The Pinterest account cannot publish in the current Pinterest environment | Disconnect and reconnect Pinterest |
Media
| Code | Status | Cause | Fix |
|---|---|---|---|
UNSUPPORTED_MEDIA_TYPE | 400, Post | The file type is not supported | Use a supported format |
MEDIA_NOT_FOUND | 404 | A media[].id does not exist in this workspace | Use an id from GET /v1/media |
MEDIA_NOT_UPLOADED | Post | The file was never uploaded, or the upload expired | Upload the file, then create the post again |
MEDIA_TYPE_MISMATCH | Post | The uploaded file's type is not its contentType | Create a new media item with the right type |
MEDIA_TOO_LARGE | 400, Post | The file is over the size limit for its type | Upload a smaller file |
MEDIA_FORMAT_UNSUPPORTED | 400, Post | The platform does not take the file's format for this kind of post. On a 400, param names the file | Convert the file to a format in the platform's Media Requirements |
MEDIA_TOO_LARGE_FOR_PLATFORM | 400, Post | The file is over the platform's size limit for this kind of post. On a 400, param names the file | Compress the file under the limit in the platform's Media Requirements |
MEDIA_UNFETCHABLE | Post | The media URL could not be downloaded | Meet the Media URL Requirements |
INVALID_MEDIA | Post | The platform refused the file's format, count, size or kind | Check the platform's media requirements |
MEDIA_REQUIRED | Post | A media post has no media | Add media |
MEDIA_UPLOAD_FAILED | Post | The platform refused or failed the upload | Check the media and post again |
MEDIA_PROCESSING_FAILED | Post | X could not process the media | Re-encode the file and post again |
MEDIA_PROCESSING_TIMEOUT | Post | The platform did not process the media in time | Use a smaller or shorter file and post again |
CONTAINER_FAILED | 502, Post | Instagram or Threads could not process the media | Check the format and size, then post again |
URL_OWNERSHIP_UNVERIFIED | Post | TikTok refuses media from the URL's domain | Upload the file and use its id |
REEL_UPLOAD_FAILED | Post | Facebook did not accept the reel upload | Create the post again |
STORY_UPLOAD_FAILED | Post | Facebook did not accept the story upload | Create the post again |
Publishing
| Code | Status | Cause | Fix |
|---|---|---|---|
PUBLISH_FAILED | 502, Post | The platform refused the post without a specific reason | Read error.message, fix the content and post again |
PUBLISH_INTERRUPTED | Post | The outcome is unknown, and the post may be live | Check the platform before posting again |
PLATFORM_UNAVAILABLE | 502, Post, Analytics | The platform is down or did not respond. Connecting or reconnecting an account can return it too | Try again later. If it repeats, contact support with the requestId |
POST_NOT_PUBLISHED | 409 | quotePostId or replyToPostId names a pst_ post that is not live | Wait until it is live, or use the platform's post id |
TEXT_TOO_LONG | 400, 422, Post | The text is over the platform or account limit | Shorten it. See Text Limits |
TEXT_REQUIRED | 400, 422, Post | A text post or message has no text | Add text |
CAPTION_TOO_LONG | Post | The Instagram caption is over 2,200 characters | Shorten the caption |
INVALID_FIRST_COMMENT | Post | The Instagram firstComment is over 2,200 characters | Shorten the comment |
INVALID_AI_LABEL | Post | Instagram isAiGenerated was sent on a story | Remove it, or post a reel or feed post |
UNSUPPORTED_MEDIA_KIND | Post | The platform cannot publish this mediaKind | Use a mediaKind the platform supports |
UNSUPPORTED_FEATURE | Post | The platform has no threads, quotes or replies | Remove thread, quotePostId or replyToPostId |
INVALID_MULTI_IMAGE | Post | The image count is outside the platform's range | Send a count the platform accepts |
DUPLICATE_CONTENT | 422, Post | X rejected the text as a duplicate | Change the text |
GEO_RESTRICTION_FAILED | Post | X rejected the geoRestriction list | Check the country codes, or remove geoRestriction |
INVALID_LINK | Post | The Bluesky link is not a valid URL | Fix the link |
INVALID_QUOTE | Post | The Bluesky post to quote is not a valid at:// URI or was not found | Use an existing post's pst_ id or at:// URI |
INVALID_REPLY | Post | The Bluesky post to reply to is not a valid at:// URI or was not found | Use an existing post's pst_ id or at:// URI |
INVALID_TOPIC_TAG | Post | The Threads topicTag is over 50 characters or has . or & | Fix the tag |
INVALID_AUDIO | Post | Instagram audioId needs a single video with mediaKind reel or video, on Facebook Login | Use a single video, or reconnect with Facebook Login |
INVALID_SPONSOR | Post | An Instagram sponsor was not found, or a paid partnership was sent without Facebook Login | Use a valid username or id, or reconnect with Facebook Login |
INVALID_TRIAL_REEL | Post | An Instagram trial reel is not a single video, or has sponsors | Use a single video without sponsors |
INVALID_CAROUSEL | Post | Facebook carouselCards needs multi_image and one card per image | Send one card per image with multi_image |
TEXT_FORMAT_UNSUPPORTED | Post | Facebook textFormatPresetId only works on text-only posts | Remove it, or post text only |
PRIVACY_LEVEL_REQUIRED | Post | The TikTok privacyLevel is missing or invalid | Send a valid privacyLevel |
INVALID_PRIVACY_LEVEL | 400, Post | The creator does not allow this TikTok privacyLevel. As a post error, their settings changed after scheduling | Use a value from GET /v1/accounts/{id}/creator-info |
INTERACTION_DISABLED | 400 | tiktok.allowComment, allowDuet or allowStitch is true, but the creator turned it off. Nothing is created | Set the option named in error to false. See GET /v1/accounts/{id}/creator-info |
SPAM_RISK | Post | TikTok flagged the post as a spam risk | Review the content before posting again |
POSTING_LIMIT_REACHED | Post | TikTok says the account posted too often | Wait before posting to this account again |
CAPACITY_LIMITED | Post | TikTok is not accepting more direct posts right now | Try again in a few hours |
UPLOAD_LIMIT_EXCEEDED | Post | The YouTube channel reached its upload limit | Wait until YouTube's limit resets |
Edit, Cancel and Delete
| Code | Status | Cause | Fix |
|---|---|---|---|
NOT_EDITABLE | 409 | The post is not scheduled, or was made outside Onepostly | Delete it and create a new post |
POST_PUBLISHING | 409 | The post is publishing right now | Try again once its status is final |
NOT_DELETABLE | 409 | Nothing is on the platform. The post failed before it went out, or is a draft | Nothing to delete. Delete a draft in the dashboard |
DELETE_FAILED | 502 | The platform did not delete the post | Try again later, and check the platform |
DELETE_PERMISSION | 422 | The account cannot delete this post | Reconnect and approve every permission, or check the account owns it |
THREAD_DELETE_PARTIAL | 502 | The first post was deleted, but not all of its thread | Send the delete again |
MEDIA_DELETE_UNSUPPORTED | 400 | Instagram Login accounts cannot delete media | Reconnect with Facebook Login, or use the Instagram app |
INVALID_EXTERNAL_ID | 400, Analytics | The Bluesky post id is not an at:// URI | Use the at:// URI as platformPostId |
Comments and Engagement
| Code | Status | Cause | Fix |
|---|---|---|---|
NOT_PUBLISHED | 409, Analytics | The post is not published yet | Wait until it publishes, then call again |
ACCOUNT_REQUIRED | 400 | A platform post id was sent without accountId | Send accountId too |
AMBIGUOUS_TARGET | 400 | The post was published to several accounts | Send accountId to pick one |
POST_ACCOUNT_MISMATCH | 400 | A like, bookmark or repost names another account's pst_ post | Act as the post's account, or use platformPostId |
TARGET_SYNC_FAILED | 502 | The platformPostId post did not load from the platform | Check the id and try again |
MISSING_EXTERNAL_ID | 404, Analytics | The post or comment has no usable platform id | Pass a valid id |
NOT_A_COMMENT | 400 | The id is one of your posts, not a comment | Use DELETE /v1/posts/{id} |
COMMENT_CREATE_FAILED | 502 | The platform did not post the comment or reply | Try again |
COMMENT_DELETE_FAILED | 502 | The platform did not delete the comment | Try again |
COMMENT_HIDE_FAILED | 502 | The platform did not hide or unhide the comment | Try again |
COMMENT_LIKE_FAILED | 502 | Facebook did not like the comment | Try again |
COMMENT_UNLIKE_FAILED | 502 | Facebook did not remove the like | Try again |
PRIVATE_REPLY_FAILED | 502 | The private reply was not sent. A comment takes one, within 7 days | Check the comment's age and past replies |
COMMENTS_PERMISSION | 422 | A comment permission is missing, the comment cannot be deleted, or comments are off | Reconnect and approve every permission. On YouTube, check comments are on |
COMMENTS_UNSUPPORTED | 400 | Comments cannot be read for this post | Nothing to do |
UNSUPPORTED_MEDIA | 400 | The post is a story, which has no comments | Nothing to do |
COMMENTS_FAILED | 502 | The comments could not be read | Try again |
INVALID_PARENT | 400 | The Bluesky comment to reply to has an invalid id | Use a cmt_ id from List Comments |
INVALID_COMMENT_ID | 400 | The Bluesky comment id is invalid | Use a cmt_ id from List Comments |
RESOLVE_FAILED | 404 | Bluesky could not find the post or comment to reply to | Check that it still exists |
ENGAGEMENT_FAILED | 502 | The like or bookmark failed | Try again. Reconnect if the message says so |
ENGAGEMENT_PERMISSION | 422 | The account is missing permission for likes or bookmarks | Reconnect and approve every permission |
LIKE_FAILED | 502 | The platform did not like the post | Try again |
UNLIKE_FAILED | 502 | The platform did not remove the like | Try again |
BOOKMARK_FAILED | 502 | The platform did not bookmark the post | Try again |
UNBOOKMARK_FAILED | 502 | The platform did not remove the bookmark | Try again |
REPOST_FAILED | 502 | The platform did not repost the post | Try again |
UNREPOST_FAILED | 502 | The platform did not remove the repost | Try again |
REPOST_PERMISSION | 422 | The account cannot repost | Reconnect and approve every permission |
UNREPOST_PERMISSION | 422 | The account cannot remove the repost | Reconnect and approve every permission |
UNREPOST_REQUIRES_REPOST_ID | 400 | The Threads repost was not made through Onepostly | Undo it in the Threads app |
REPOSTS_UNSUPPORTED | 400 | Reposts cannot be read for this post | Nothing to do |
REPOSTS_UNAUTHORIZED | 422 | X rejected the account's access while reading reposts | Reconnect the account |
REPOSTS_FAILED | 502 | The reposts could not be read | Try again |
READ_FAILED | 502 | The platform list could not be read | Try again |
SYNC_FAILED | 502 | POST /v1/accounts/{id}/sync could not load the account's posts | Try again |
Inbox and Automations
| Code | Status | Cause | Fix |
|---|---|---|---|
CONVO_NOT_FOUND | 404 | The conversation does not exist | Check the cnv_ id |
RECIPIENT_NOT_FOUND | 404 | The recipient does not exist. Facebook needs the numeric user id | Check the recipient |
RECIPIENT_UNREACHABLE | 409 | The recipient does not accept messages from this account | Reach them another way |
MESSAGE_WINDOW_EXPIRED | 409 | The 24-hour Instagram or Facebook messaging window closed | Wait for the person to message again |
CONVO_LOCKED | 409 | The Bluesky conversation is locked | Nothing to do |
INBOX_PERMISSION | 422 | The account is missing messaging permission | Reconnect and approve every permission |
INBOX_FAILED | 502 | The platform did not complete the inbox request | Try again. Reconnect if it keeps failing |
INVALID_ATTACHMENT | 400 | attachmentUrl is not an HTTPS URL | Use a public HTTPS URL |
ATTACHMENT_UNSUPPORTED | 400 | Attachments only work on Instagram and Facebook | Remove the attachment |
TEMPLATE_UNSUPPORTED | 400 | Quick replies, buttons and cards only work on Instagram and Facebook | Remove them |
INVALID_TEMPLATE | 400 | A button lacks url or payload, or an attachment has buttons or cards | Fix the buttons |
LIMIT_REACHED | 400 | The account has the most automations it can have | Delete an automation first |
CONFLICT | 409 | The automations changed while the request ran | Send the request again |
Analytics
| Code | Status | Cause | Fix |
|---|---|---|---|
INVALID_RANGE | 400 | since is not before until, or the range is too long | Fix the dates |
TIMELINE_UNSUPPORTED | 400 | X posts have no daily timeline | Use GET /v1/posts/{id}/analytics |
ANALYTICS_PERMISSION | 422, Analytics | The account is missing the insights permission | Reconnect and approve every permission |
ANALYTICS_FAILED | 502, Analytics | The platform did not return metrics | Try again later. Reconnect if the message says so |
ANALYTICS_PENDING | Analytics | The platform has no metrics yet | Read again later |
POST_NOT_FOUND | Analytics | The post was deleted, or the account cannot see it. The reading is unavailable for good | Check the post on the platform |
VIDEO_ID_PENDING | Analytics | The TikTok video is not public yet | Read again later |
VIDEO_NOT_FOUND | Analytics | TikTok has no metrics yet, or the YouTube video was removed | Read again later, or check the video exists |
PRIVACY_RESTRICTED | Analytics | TikTok only reports metrics for public posts | Publish with public_to_everyone |
Webhooks
| Code | Status | Cause | Fix |
|---|---|---|---|
CREATE_FAILED | 500 | The webhook endpoint could not be created | Try again. If it repeats, contact support with the requestId |
DELIVERY_IN_PROGRESS | 409 | The delivery is still being attempted | Wait for success or failed, then retry |
See Analytics Status for how the analytics codes relate to status.