Skip to Content

Errors

All VoxBurst API errors follow the same envelope:

{ "error": { "code": "VALIDATION_ERROR", "message": "Content exceeds maximum length for Twitter (280 characters)", "details": { "field": "content", "platform": "TWITTER", "maxLength": 280, "actualLength": 312 } } }

code is always a stable machine-readable string. message is human-readable and may change. details is present on VALIDATION_ERROR and IDEMPOTENCY_* codes — always branch on code, never message.


Global error codes

These codes can appear on any endpoint.

HTTPCodeMeaningRetryableUser-fixable
400BAD_REQUESTMalformed request — missing required field, wrong type, or invalid ID formatNoYes
400VALIDATION_ERRORRequest body failed schema or semantic validation — see details for field-level infoNoYes
401UNAUTHORIZEDMissing or invalid API keyNoYes — check key
402LIMIT_EXCEEDEDPlan limit reached (accounts, posts, workspaces)NoYes — upgrade plan
403AUTHORIZATION_ERRORValid key but insufficient scope for this endpointNoYes — add scope
404NOT_FOUNDResource does not exist in this workspaceNoYes — check ID
409CONFLICTState conflict — resource is in a status that doesn’t permit this operationNoYes — check status
409IDEMPOTENCY_CONFLICTIdempotency key reused with a different request bodyNoYes — use a new key
409IDEMPOTENCY_IN_PROGRESSA request with this key is currently in flightYes — wait and retry
400IDEMPOTENCY_INVALID_KEYIdempotency key format invalid (bad chars or wrong length)NoYes — fix key format
429RATE_LIMITEDRate limit exceeded — Retry-After header indicates when to retryYes — after delay
500INTERNAL_ERRORUnexpected server errorYes — with backoffNo
503SERVICE_UNAVAILABLEDependency unavailable (database, queue)Yes — with backoffNo

400 BAD_REQUEST is returned for malformed ID parameters (e.g. passing a non-cuid2 string as a post ID) — before any database lookup. Handle both 400 and 404 when an ID is user-supplied.


Posts errors

POST /v1/posts and PATCH /v1/posts/:id

HTTPCodeWhen it occursFix
400VALIDATION_ERRORContent too long, invalid contentType, bad scheduledFor format, missing accountIdsFix the failing field — details names it
400VALIDATION_ERRORscheduledFor is in the past (beyond 60s grace window)Use a future timestamp
400VALIDATION_ERRORBoth scheduledFor and queue: true providedUse one or the other, not both
400VALIDATION_ERRORmediaIds contains an ID that doesn’t exist or isn’t READYPoll media status before attaching
400VALIDATION_ERRORThread sequences are non-contiguous or don’t start at 1Fix thread item sequence numbers
402LIMIT_EXCEEDEDWorkspace has reached its plan’s scheduled-post limitUpgrade plan or publish/archive existing posts
404NOT_FOUNDAccount ID not found in this workspaceUse GET /v1/accounts to get valid IDs
404NOT_FOUNDPersona ID not foundUse GET /v1/personas to get valid IDs
409CONFLICTPost is in a status that doesn’t allow editing (e.g. published)Check post status — see state machine
409CONFLICTversion token mismatch (optimistic concurrency)Re-fetch the post, use the new updatedAt as version
409CONFLICTDuplicate scheduled post (same content + account + time fingerprint)Change content or schedule time

POST /v1/posts/:id/publish

HTTPCodeWhen it occursFix
400VALIDATION_ERRORX-Callback-Url is not a valid HTTPS URLFix the callback URL
404NOT_FOUNDPost ID not foundCheck the post ID
409CONFLICTPost is not in a publishable statusPost must be draft, scheduled, approved, failed, or partial

POST /v1/posts/:id/retry

HTTPCodeWhen it occursFix
404NOT_FOUNDPost ID not found
409CONFLICTPost is not failed or partialOnly failed/partial posts can be retried

DELETE /v1/posts/:id

HTTPCodeWhen it occursFix
404NOT_FOUNDPost ID not found
409CONFLICTPost is publishing or published — cannot be deletedUnpublish first, then archive

POST /v1/posts/validate

HTTPCodeWhen it occursFix
400VALIDATION_ERRORplatforms array is empty or contains an invalid platform constantUse valid Platform enum values (e.g. "TWITTER")

Accounts errors

POST /v1/accounts/connect/:platform

HTTPCodeWhen it occursFix
400INVALID_PARAMcallbackUrl is missing or not a valid URLProvide a valid HTTPS callback URL
402LIMIT_EXCEEDEDPlan limit on connected accounts reachedUpgrade plan or disconnect an unused account
403PLATFORM_RESTRICTEDPlatform is not enabled for this workspaceContact support or upgrade to a plan that includes the platform

POST /v1/accounts/callback/:platform

HTTPCodeWhen it occursFix
400INVALID_PARAMOAuth state token invalid or expired (>10 min old)Restart the connect flow to get a fresh state token
400INVALID_PARAMAuthorization code invalidRestart the connect flow

POST /v1/accounts/:id/refresh

HTTPCodeWhen it occursFix
404NOT_FOUNDAccount ID not found
400VALIDATION_ERRORToken refresh failed — platform rejected the refresh requestUser must reconnect via the full OAuth flow

POST /v1/accounts/:id/select-page

HTTPCodeWhen it occursFix
400INVALID_PAGE_IDPage not available for this accountRe-fetch pages with GET /v1/accounts/:id/pages
400DESTINATIONS_NOT_LOADEDAccount page list not yet loadedWait a moment and retry
404NOT_FOUNDAccount ID not found

Media errors

POST /v1/media/upload

HTTPCodeWhen it occursFix
400VALIDATION_ERRORcontentType not in the supported MIME types listUse a supported MIME type — see Supported File Types
400VALIDATION_ERRORsizeBytes exceeds the per-type maximumCompress or reduce the file
503UPLOAD_UNAVAILABLES3 presign service temporarily unavailableRetry after a short delay

POST /v1/media/bulk-presign and POST /v1/media/bulk-video-upload-urls

HTTPCodeWhen it occursFix
400REQUEST_TOO_LARGECombined batch size exceeds 20 GBSplit into smaller batches
400VALIDATION_ERRORMore than 20 files in a single requestSplit into multiple requests of ≤ 20
503UPLOAD_UNAVAILABLES3 presign service unavailableRetry after a short delay

GET /v1/media/:id and DELETE /v1/media/:id

HTTPCodeWhen it occursFix
404NOT_FOUNDMedia item not found in this workspaceCheck the mediaId

POST /v1/media/:id/validate

HTTPCodeWhen it occursFix
404NOT_FOUNDMedia item not found
202(not an error)Returns { "queued": false } if validation queue not configuredNo action needed — validation skipped

Webhook errors

POST /v1/webhooks

HTTPCodeWhen it occursFix
400VALIDATION_ERRORurl is not a valid HTTPS URLUse a valid https:// URL
400VALIDATION_ERRORevents contains an unknown event typeUse a valid event type — see Events
402LIMIT_EXCEEDEDPlan does not include custom webhooks (Pro+ required)Upgrade to Pro or Agency plan
403AUTHORIZATION_ERRORwebhooks:write scope not present on API keyAdd webhooks:write scope

POST /v1/webhooks/test

HTTPCodeWhen it occursFix
404NOT_FOUNDWebhook endpoint ID not found
400VALIDATION_ERROREndpoint is disabledRe-enable the endpoint first

Error recovery cheatsheet

SituationAction
429 RATE_LIMITEDWait for Retry-After seconds, then retry identically
500 INTERNAL_ERRORRetry with exponential backoff (1s, 2s, 4s); if persists, contact support
503 SERVICE_UNAVAILABLERetry with exponential backoff
409 IDEMPOTENCY_IN_PROGRESSWait ~2 seconds, retry with the same Idempotency-Key
409 CONFLICT (post status)Fetch the post, check its current status, decide whether to wait or fix
409 CONFLICT (version mismatch)Re-fetch the post; use updatedAt as the new version token
400 BAD_REQUEST (malformed ID)Check that the ID starts with c and is 25 chars (cuid2 format)
404 NOT_FOUNDConfirm the resource exists in the correct workspace
401 UNAUTHORIZEDRegenerate your API key from the dashboard
403 AUTHORIZATION_ERRORAdd the required scope to your API key

Negative examples — common failures

These are the highest-friction validation cases, shown as failing requests with the exact error response.

Instagram post without media or contentType

curl -X POST https://api.voxburst.io/v1/posts \ -H "Authorization: Bearer vb_live_xxxxx" \ -H "Content-Type: application/json" \ -d '{ "content": "Hello!", "accountIds": ["acc_instagram_abc"] }'
{ "error": { "code": "VALIDATION_ERROR", "message": "Content is required for Instagram posts", "details": { "platform": "INSTAGRAM", "reason": "MEDIA_REQUIRED" } } }

Fix: Add "contentType": "IMAGE" and "media": ["media_id_here"]. Instagram requires at least one image or video on every post.


Twitter post over 280 characters

curl -X POST https://api.voxburst.io/v1/posts/validate \ -H "Authorization: Bearer vb_live_xxxxx" \ -H "Content-Type: application/json" \ -d '{ "content": "This is a very long tweet that exceeds the 280 character limit. Lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt ut labore et dolore magna aliqua ut enim ad minim veniam quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat duis aute irure dolor.", "platforms": ["TWITTER"] }'
{ "valid": false, "platforms": { "TWITTER": { "valid": false, "errors": [ { "code": "CONTENT_TOO_LONG", "message": "Content exceeds maximum length for Twitter (280 characters). Current: 321 characters." } ], "warnings": [] } } }

Fix: Shorten the content to ≤280 characters. Note that links count as 23 characters regardless of their actual length.


Scheduling in the past

curl -X POST https://api.voxburst.io/v1/posts \ -H "Authorization: Bearer vb_live_xxxxx" \ -H "Content-Type: application/json" \ -d '{ "content": "Old post", "accountIds": ["acc_abc"], "scheduledFor": "2025-01-01T00:00:00Z" }'
{ "error": { "code": "VALIDATION_ERROR", "message": "Scheduled time must be in the future", "details": { "field": "scheduledFor" } } }

Fix: Use a future UTC timestamp. VoxBurst allows a 60-second grace window for clock skew.


Media not yet READY

curl -X POST https://api.voxburst.io/v1/posts \ -H "Authorization: Bearer vb_live_xxxxx" \ -H "Content-Type: application/json" \ -d '{ "content": "Photo post", "accountIds": ["acc_ig"], "contentType": "IMAGE", "media": ["media_still_processing"] }'
{ "error": { "code": "VALIDATION_ERROR", "message": "Media media_still_processing is not ready for publishing (status: PROCESSING)" } }

Fix: Poll GET /v1/media/:id until status is "READY" before attaching media to a post.


Bulk create over 50 posts

curl -X POST https://api.voxburst.io/v1/posts/bulk \ -H "Authorization: Bearer vb_live_xxxxx" \ -H "Content-Type: application/json" \ -d '{ "posts": [ ... 51 items ... ] }'
{ "error": { "code": "VALIDATION_ERROR", "message": "Maximum 50 posts per bulk request", "details": { "field": "posts", "max": 50, "actual": 51 } } }

Fix: Split into batches of ≤50 posts per request.


threadPosts sequences not contiguous

curl -X POST https://api.voxburst.io/v1/posts \ -H "Authorization: Bearer vb_live_xxxxx" \ -H "Content-Type: application/json" \ -d '{ "content": "Thread", "accountIds": ["acc_twitter"], "contentType": "THREAD", "threadPosts": [ { "sequence": 1, "content": "First tweet" }, { "sequence": 3, "content": "Third tweet — sequence 2 is missing!" } ] }'
{ "error": { "code": "VALIDATION_ERROR", "message": "Thread post sequences must be 1-based and contiguous", "details": { "field": "threadPosts" } } }

Fix: Use sequences 1, 2, 3 … with no gaps and no duplicates.


Malformed resource ID

curl https://api.voxburst.io/v1/posts/not-a-valid-id \ -H "Authorization: Bearer vb_live_xxxxx"
{ "error": { "code": "BAD_REQUEST", "message": "Invalid path parameter 'id': Invalid ID format" } }

Fix: VoxBurst IDs are cuid2  format: exactly 25 characters, starting with c, followed by 24 lowercase alphanumeric characters. Example: cmp6v6bhf000369v60htcu3vc. Both 400 and 404 should be handled when accepting user-supplied IDs.


Optimistic concurrency conflict (stale version)

curl -X PATCH https://api.voxburst.io/v1/posts/post_abc \ -H "Authorization: Bearer vb_live_xxxxx" \ -H "Content-Type: application/json" \ -d '{ "content": "Updated content", "version": "2026-06-01T10:00:00.000Z" }'
{ "error": { "code": "CONFLICT", "message": "Post has been modified since you last loaded it. Re-fetch and retry.", "details": { "field": "version" } } }

Fix: Re-fetch the post with GET /v1/posts/:id, use the response’s updatedAt as the new version token, and retry the update.

Last updated on