Skip to main content
All errors return JSON with a consistent shape:
Use error.code for programmatic handling; use error.message for logging and display. Some errors include an error.meta object with structured context (for example meta.field for a validation failure, meta.plan and meta.max for billing limits). Codes are stable and namespaced with dot-separated segments, so you can match on a prefix (for example platform.* for any upstream platform failure, or byok.* for any bring-your-own-key issue). The request_id field is present on every error response. The same value appears in the X-Request-ID response header. Include it when reporting an issue to support. See Debugging with request IDs for details on how to supply your own correlation ID.

Code namespaces

The first segment of the code tells you where the failure originated.

Authentication

Accounts

Validation

The code always starts with validation.. The specific sub-code after the dot identifies the field or rule that failed; error.meta.field in the response points to the offending field name when applicable.

Resources

Invite conflicts and validation

POST /v1/invites returns 409 resource.conflict for two different situations, distinguished by the message:
  • an active invite already exists for this brand and platform
  • brand already has a connected account for this platform
Both share the resource.conflict code. Note that GET /v1/invites and GET /v1/accounts query different objects, so an empty invite list does not guarantee that a create will succeed: the brand may already have a connected account for that platform. Check both before treating a create as safe. expires_in_days is required on invite creation and must be one of 1, 3, 7, 14, or 30. Any other value (including omitting it) returns 400 validation.field_invalid with the message expires_in_days must be one of: 1, 3, 7, 14, 30.

Billing and plan limits

Limit responses include error.meta.plan and error.meta.max so clients can prompt the user to upgrade.

Past-due accounts

When a subscription’s payment fails twice (the initial charge plus one automatic retry), API access is paused. Every /v1 endpoint returns 402 with code billing.past_due until the invoice is paid. Three things stay reachable so the account can be recovered:
  • GET /v1/users/me and PATCH /v1/users/me
  • every /v1/billing/* endpoint
  • inbound platform webhooks, which are unaffected
GET /v1/users/me reports the state in two fields: billing_blocked (boolean) and billing_blocked_at (when the block began, or null). Outbound webhooks are not delivered while an account is past due. Events that occur during this window are dropped, not queued, and are not replayed after payment. Ingestion is unaffected, so the underlying data is still recorded and remains queryable through GET /v1/events once access is restored. Access is restored automatically within seconds of a successful payment. There is no endpoint to call and no support ticket to open: paying the invoice, whether through the dashboard’s Stripe portal or an automatic retry, lifts the block.

Platform errors

When the upstream platform (Meta, TikTok, Google, etc.) rejects a call, the error code has the form platform.<name>.<reason>. The HTTP status is forwarded when possible; otherwise it is 502 Bad Gateway.

BYOK (bring-your-own-key)

For platforms that require a customer-supplied OAuth app (currently Twitter / X).

Publishing delivery

These are emitted by the post delivery workers and surface in the inbox / events stream rather than as direct HTTP responses, but they appear in event.error_code for post.failed and post.partial events.

WhatsApp

WhatsApp Cloud API has a richer error surface than other platforms because of its messaging window, frequency caps, and template state machine.

Telegram

Zalo

Zalo uses the generic platform.zalo.* namespace (see the platform.<name>.* row above), not a dedicated top-level namespace. platform.zalo.not_deliverable is the one you’re most likely to hit: Zalo only allows a customer service message within 7 days of the user’s last interaction with your Official Account (free within 48 hours), and rejects sends outside that window with a 422 instead of queuing them.

Bluesky

Bluesky uses the generic platform.bluesky.* namespace (see the platform.<name>.* row above), not a dedicated top-level namespace. platform.bluesky.dm_scope_missing only affects the DM endpoints, so treat it as a per-capability failure rather than a dead connection.

System

Handling common cases

Reconnect when a token dies

account.reconnection_required and platform.<name>.auth both mean the stored OAuth token is no longer usable. Send the user back through GET /v1/oauth/url.

Storage quota

billing.storage_quota (HTTP 413) means the upload would push you past your plan’s storage limit. Check current usage with GET /v1/media/storage and delete unused media or upgrade.

Monthly post or interaction limit

billing.post_limit (HTTP 429) means your monthly allowance is exhausted. Limits reset at the start of your next billing period. The free plan uses a rolling 30-day window from your account anniversary.

Platform throttling

platform.<name>.rate_limit (HTTP 429) is the upstream platform throttling you, not SocialAPI. It does not consume your quota. Wait a few minutes and retry with backoff.

Validation failures

Any validation.* code includes an error.meta.field pointing to the offending input. Surface the field name to the user.

Example error handling