Error Handling

Error envelope, stable codes, and HTTP status codes returned by the Onepostly API.

Error Response Format

Every non-2xx response returns a flat JSON envelope:

{
  "error": "Post not found.",
  "code": "NOT_FOUND"
}
FieldStableDescription
errorNoHuman-readable message. Reworded freely between releases. Never branch client logic on this.
codeYesMachine-readable code (e.g. VALIDATION_ERROR, INSUFFICIENT_WALLET). Use this for programmatic handling.
paramYesRequest field at fault, when applicable. Dotted path for nested fields (e.g. destinations.0.accountId).
detailsYesAdditional structured context when available (e.g. retryAfterSeconds on rate limits).
platformYesReserved for platform errors: the upstream platform that rejected the request (e.g. x, tiktok).

Branch on code, not on the message. The error string exists for humans and may change at any time. The code is stable once shipped.

Stability Contract

  • code values are stable once shipped. Build retries, alerting, and i18n against them.
  • The error message can change freely. Treat it as display-only.
  • New codes may be added at any time. Removing a code is a breaking change.

HTTP Status Codes

StatusWhen It HappensHandling
400 / 409Missing fields, wrong types, invalid JSON, unmet preconditions, conflictsFix the request; retrying unchanged won't help
401Missing or invalid API keyCheck the key
402 / 403Wallet balance can't cover the call, a read-only key hit a write route, or the workspace is blocked on billingTop up, use a read_write key, or fix billing in the dashboard
404Resource doesn't exist or isn't accessible under this keyCheck the id
429API quota or posting velocity exceededSleep for Retry-After
502Upstream social platform rejected or failed the requestRead the destination's errorCode / errorMessage
500 / 503Unexpected server-side errorSafe to retry with backoff

Common Error Codes

CodeHTTPMeaning
VALIDATION_ERROR400Body or query failed schema validation. param points at the field (e.g. destinations.0.accountId).
UNAUTHORIZED401API key missing, invalid, or revoked.
FORBIDDEN403Read-only key used on a write route, or not allowed to manage this resource.
INSUFFICIENT_WALLET402X action costs more than the wallet balance. Top up in the dashboard.
PAYMENT_METHOD_REQUIRED402The workspace has no payment method on file and needs one to keep going. Add a card in the dashboard.
PAYMENT_PAST_DUE402A charge on the workspace could not be collected. Every request is refused until it is paid. Update the card in the dashboard.
NOT_FOUND404The referenced resource doesn't exist in this workspace.
ACCOUNT_NOT_FOUND404The referenced connected account is unknown or belongs to another workspace.
CONNECTION_INACTIVE400The target account is disconnected or expired. Reconnect it.
CONNECTION_LIMIT_REACHED403The plan's connected-account cap is full. Disconnect one or upgrade.
RATE_LIMITED429API quota or posting velocity exceeded. details carries limit, currentCount, retryAfterSeconds.
VELOCITY_LIMITED—Per-account publishing cap hit (webhook + destination errorCode only).
TOKEN_INVALID400The platform revoked the access token. Reconnect the account.
TEXT_TOO_LONG400Text exceeds the platform's character limit.
MEDIA_TOO_LARGE400Media file exceeds the platform's size limit.
MEDIA_UNFETCHABLE400The media URL wasn't reachable from our servers.
UNSUPPORTED_PLATFORM400The requested action isn't supported for this platform yet.
NOT_PUBLISHED400Comments, engagement, or delete require a published post.
PLATFORM_ERROR502Catch-all when an upstream platform call failed. The message names the platform.
INTERNAL_SERVER_ERROR500Unexpected server-side error.

This list is not exhaustive; new codes ship without notice. Handle unknown codes with a generic fallback.

A workspace blocked on billing is refused everything. While a workspace has no payment method on file, or a charge on it could not be collected, every API request returns 402. Reads and writes are refused alike, and MCP tool calls fail the same way. Analytics stop advancing, and posts that were already scheduled stay scheduled rather than publishing. The workspace resumes the moment billing is settled in the dashboard.

Platform Errors

When an upstream platform rejects a publish, the failure lands on the destination, not just the HTTP response. Every destination carries its own outcome:

{
  "post": {
    "id": "1699f415-7fb6-43f4-9d2a-c447491f32a8",
    "status": "partial",
    "destinations": [
      {
        "platform": "x",
        "status": "published",
        "externalPostId": "1960956321831854280",
        "externalUrl": "https://x.com/acme/status/1960956321831854280",
        "errorCode": null,
        "errorMessage": null
      },
      {
        "platform": "instagram",
        "status": "failed",
        "errorCode": "MEDIA_TOO_LARGE",
        "errorMessage": "Video exceeds Instagram's 100 MB limit."
      }
    ]
  }
}

Post status summarizes the destinations: published when all succeeded, partial when some did, failed when none did. A terminal failure also fires the post.platform.failed webhook carrying the same errorCode / errorMessage pair — see webhooks.

Publishing Is Not Retried

A publish attempt is final. When a destination cannot be published, Onepostly marks it failed with the platform's own errorCode and errorMessage, and never submits it again. Waiting will not change the outcome.

That makes the failing destination the whole story. To publish the content again, create a new post once you have fixed the cause. Conditions that clear on their own arrive as their own codes, so you can tell a temporary platform state from a permanent rejection.

CodeMeaningWhat to do
RATE_LIMITEDThe platform throttled the requestWait out the window, then create a new post
PLATFORM_UNAVAILABLEThe platform reported a transient server-side failureTry again later
MEDIA_PROCESSING_TIMEOUTThe platform did not finish processing the media in timeTry a smaller file, or post again

Common Publishing Failures

ErrorCauseFix
Token expired / revokedOAuth token needs refresh or was revokedCheck authHealth on the connection and reconnect.
Rate limited by platformToo many posts to this accountRespect the velocity limits; space posts out.
Media rejectedFormat, size, or aspect ratio not supportedCheck the platform's requirements in its guide.
Duplicate contentPlatform rejected identical textModify the text meaningfully before retrying.
Permissions missingAccount lacks the required scopeReconnect with the proper scopes.

Webhook Reliability

If you use webhooks to track post status:

  • Deliveries are at-least-once; you may receive duplicates. Dedupe by the stable event id.
  • Failed deliveries are retried up to 5 times on 408, 429, 5xx, and network errors.
  • Delivery history (status, attempts, last response) is available per endpoint through the API and dashboard.

Best Practices

  • Branch on code, never on error text.
  • Handle 429 by sleeping for Retry-After (or details.retryAfterSeconds).
  • Treat 500/503 as transient and retry with backoff; treat 4xx as caller-fixable.
  • Read the failing destination, not just post status — one post can succeed on X and fail on Instagram.
  • Watch authHealth on connections to catch token expirations before they fail a publish.
  • Use webhooks instead of polling for status changes.
  • Log the full envelope (code, param, details) when reporting issues.