Skip to content

Error Handling

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

Error Response Format

Every non-2xx response returns a flat JSON envelope modeled on Stripe's error shape:

json
{
  "error": "budgetAmount is required",
  "type": "invalid_request_error",
  "code": "missing_required_field",
  "param": "budgetAmount",
  "docUrl": "https://docs.zernio.com/guides/error-handling"
}
FieldStableDescription
errorNoHuman-readable message. Reworded freely between releases. Never branch client logic on this.
typeYesHigh-level category (invalid_request_error, authentication_error, permission_error, not_found, rate_limit_error, platform_error, api_error).
codeYesMachine-readable code (e.g. missing_required_field, ads_connection_required). Use this for programmatic handling.
paramYesField or query parameter at fault, when applicable. Dotted path for nested fields (e.g. images.square).
docUrlYesLink to error-specific documentation when available.
platformYesSet on platform_error. One of meta, google, tiktok, linkedin, pinterest, twitter.
platformErrorYesSet on platform_error. The raw upstream payload returned by the platform, forwarded unchanged for inspection.

Backward-compatible. The top-level error string is preserved so existing code that reads response.error as a string still works. New fields (type, code, param, ...) are added as top-level siblings, not under a nested details object.

Stability contract

  • type and 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.

Error Types

TypeDefault StatusWhen It Happens
invalid_request_error400 / 422Missing required fields, wrong types, mutually exclusive fields, invalid JSON, unmet preconditions.
authentication_error401Missing or invalid API key.
permission_error403Valid key but feature requires a plan upgrade or add-on (e.g. Ads add-on for AppSumo users; Usage-plan users have all features bundled).
not_found404Resource doesn't exist or isn't accessible under this API key.
rate_limit_error429Request rate limit exceeded. See rate limits.
platform_error502 (or upstream 4xx)Upstream social platform (Meta, Google, TikTok, LinkedIn, Pinterest, X) rejected the request. See "Platform Errors" below.
api_error500Unexpected server-side error. Safe to retry with backoff.

Common Error Codes

CodeTypeMeaning
missing_required_fieldinvalid_request_errorA required field is missing from the body or query. param points at the field.
invalid_field_valueinvalid_request_errorA field has the wrong type, format, or enum value. param points at the field.
mutually_exclusive_fieldsinvalid_request_errorTwo incompatible fields were both provided (e.g. creatives[] + adSetId).
invalid_json_bodyinvalid_request_errorBody could not be parsed as JSON.
missing_credentialsauthentication_errorNo Authorization header.
invalid_credentialsauthentication_errorThe API key is invalid, revoked, or expired.
ads_addon_requiredpermission_errorThe caller does not have the Ads add-on.
feature_not_availablepermission_errorThe caller's subscription tier does not include this feature.
account_not_foundnot_foundThe referenced account is unknown or not accessible.
ad_not_foundnot_foundThe referenced ad is unknown or not accessible.
post_not_foundnot_foundThe referenced post is unknown or not accessible.
audience_not_foundnot_foundThe referenced audience is unknown or not accessible.
linked_account_requiredinvalid_request_errorThe connected account is missing a required linked account (e.g. Instagram Ads requires a linked Facebook account).
ads_connection_requiredinvalid_request_errorThe platform's ads integration isn't connected (e.g. X Ads, TikTok Ads, Google Ads). Call the relevant /v1/connect/*/ads flow.
instagram_business_account_unresolvedinvalid_request_errorThe Instagram Business Account ID couldn't be resolved from the linked Page. The user must connect their Instagram to the Page in Meta Business Settings.
missing_square_imageinvalid_request_errorGoogle Display requires both images.landscape and images.square; only one was sent.
ad_not_commentableinvalid_request_errorThe ad exists but its creative format does not expose a commentable underlying post (e.g. Story ads, Dynamic Product Ads). Returned by GET /v1/ads/{adId}/comments.
rate_limitedrate_limit_errorRequest rate limit exceeded on this endpoint.
platform_api_errorplatform_errorUpstream platform rejected the call. Inspect platform + platformError.
internal_errorapi_errorUnexpected server-side error.

Platform Errors

When an upstream platform (Meta, Google, TikTok, LinkedIn, Pinterest, X) rejects a request, Zernio surfaces a platform_error envelope with the original payload passed through for inspection.

json
{
  "error": "Google rejected the ad: NOT_ENOUGH_SQUARE_MARKETING_IMAGE_ASSET",
  "type": "platform_error",
  "code": "platform_api_error",
  "platform": "google",
  "platformError": {
    "code": 3,
    "message": "Request contains an invalid argument.",
    "details": [ { "errors": [ { "errorCode": { "assetError": "NOT_ENOUGH_SQUARE_MARKETING_IMAGE_ASSET" }, "message": "Too few." } ] } ]
  }
}
  • platform_error returns the upstream 4xx status when the platform indicated bad input, or 502 Bad Gateway when the platform returned 5xx / didn't indicate a status.
  • Inspect platformError for platform-specific error codes you may want to map for retries or end-user messages.
  • platform identifies which upstream surfaced the error, so one handler can branch by integration.

Post Publishing Failures

When a scheduled post fails to publish to one or more platforms, the post status reflects the outcome:

Post StatusMeaning
publishedAll platforms published successfully.
partialSome platforms published, others failed.
failedAll platforms failed to publish.

Each platform entry in the post has its own status and error fields:

json
{
  "post": {
    "status": "partial",
    "platforms": [
      { "platform": "twitter", "status": "published", "platformPostUrl": "https://twitter.com/..." },
      { "platform": "instagram", "status": "failed", "error": "Media processing failed: video too short for Reels" }
    ]
  }
}

Common publishing errors

ErrorCauseFix
Token expiredOAuth token needs refreshCheck account health and reconnect.
Rate limited by platformToo many posts to this platformWait and retry, or space out posts.
Media processing failedFile format/size not supported by platformCheck platform requirements.
Duplicate contentPlatform rejected identical contentModify the content slightly.
Permissions missingAccount lacks required permissionsReconnect with proper scopes.

Retrying failed posts

For failed or partial posts, use the retry endpoint:

typescript
const { post } = await zernio.posts.retryPost('post_123');
python
result = client.posts.retry_post("post_123")
bash
curl -X POST "https://zernio.com/api/v1/posts/post_123/retry" \
  -H "Authorization: Bearer YOUR_API_KEY"

Only the failed platforms are retried; already-published platforms are skipped.

Account Health

Proactively check if your connected accounts are healthy before publishing:

typescript
const health = await zernio.accounts.getAccountHealth();
python
health = client.accounts.get_account_health()
bash
curl "https://zernio.com/api/v1/accounts/health" \
  -H "Authorization: Bearer YOUR_API_KEY"

The health check endpoint returns token validity, permissions status, and recommendations for each account.

Webhook Reliability

If you use webhooks to track post status:

  • Webhooks are delivered at least once (you may receive duplicates); dedupe by event id.
  • Failed deliveries are retried with exponential backoff.
  • You can view delivery logs in the webhooks dashboard.

Best Practices

  • Branch on type and code, never on error text.
  • Handle 429 by respecting the Retry-After header.
  • Treat platform_error upstream 4xx as caller-fixable (bad input forwarded from the platform) and 5xx / 502 as transient.
  • Monitor account health periodically to catch token expirations early.
  • Use webhooks instead of polling for post status updates.
  • Log errors with full context, include the request body and the entire response envelope (including platformError) for debugging.