Skip to content
Dashboard

Error Handling

Understand API error responses and implement robust error handling in your applications.

Error Response Format

All API errors follow a consistent JSON structure. Every error response includes a success field set to false, an error object with a machine-readable code and human-readable message, and a meta object with request metadata.

{
  "success": false,
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable error description"
  },
  "meta": {
    "request_id": "req_abc123def456",
    "timestamp": "2026-02-01T12:00:00Z"
  }
}

The request_id is useful for debugging. Include it when contacting support. It is also returned on every response in the X-Request-Id header.

Response Headers

Every authenticated response, success or failure, carries these headers:

HeaderMeaning
X-Request-IdSame value as meta.request_id. Log it.
X-RateLimit-LimitRequests allowed per minute for this key
X-RateLimit-RemainingRequests left in the current minute window
X-RateLimit-ResetWhen the current window resets, as UTC epoch seconds
X-RateLimit-Daily-LimitSent only when the daily limit is finite
X-RateLimit-Daily-RemainingSent only when the daily limit is finite
Retry-AfterSent on 429 only. Seconds to wait before retrying.

Error Codes Reference

The following table lists all possible error codes, their HTTP status codes, and common causes:

StatusCodeDescriptionCommon Cause
400VALIDATION_ERRORInvalid request body or parametersMissing project_id, topic shorter than 3 characters, unknown platform name
400NO_PROJECTNo project could be resolved for the requestAccount has no projects yet, or no project_id was passed to /social/generate
401UNAUTHORIZEDMissing or invalid authenticationNo Bearer token, expired key, malformed key
402INSUFFICIENT_CREDITSNot enough credits for the operationAccount balance too low for the requested operation
403FORBIDDENAPI key lacks the required permission or scopeKey missing write permission for POST endpoints, wrong scope
404NOT_FOUNDResource does not exist or is not owned by the userInvalid ID, deleted resource, accessing another user's data
409CONFLICTOperation conflicts with current resource statePublishing content that is already published, duplicate operations
412PRECONDITION_FAILEDRequired precondition not metPublishing content that is still generating, or the account has no connected social profiles
429RATE_LIMIT_EXCEEDEDToo many requestsExceeded per-minute or daily rate limit
500INTERNAL_ERRORUnexpected server errorServer-side issue. Retry with backoff.

Error Response Examples

400 Validation Error

400VALIDATION_ERROR
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "topic: String must contain at least 3 character(s), project_id: Required"
  },
  "meta": {
    "request_id": "req_abc123",
    "timestamp": "2026-02-01T12:00:00Z"
  }
}

400 No Project

400NO_PROJECT
{
  "success": false,
  "error": {
    "code": "NO_PROJECT",
    "message": "No project available. Pass project_id, or create a project first (GET /api/v1/projects)."
  },
  "meta": {
    "request_id": "req_bcd234",
    "timestamp": "2026-02-01T12:00:00Z"
  }
}

401 Unauthorized

401UNAUTHORIZED
{
  "success": false,
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Invalid or expired API key"
  },
  "meta": {
    "request_id": "req_def456",
    "timestamp": "2026-02-01T12:00:00Z"
  }
}

402 Insufficient Credits

402INSUFFICIENT_CREDITS
{
  "success": false,
  "error": {
    "code": "INSUFFICIENT_CREDITS",
    "message": "This operation requires 2.4 credits but your balance is 1.2"
  },
  "meta": {
    "request_id": "req_ghi789",
    "timestamp": "2026-02-01T12:00:00Z"
  }
}

412 Precondition Failed

412PRECONDITION_FAILED
{
  "success": false,
  "error": {
    "code": "PRECONDITION_FAILED",
    "message": "Content is still generating. Poll /api/v1/social/content/{id} until status is ready."
  },
  "meta": {
    "request_id": "req_pqr678",
    "timestamp": "2026-02-01T12:00:00Z"
  }
}

403 Forbidden

403FORBIDDEN
{
  "success": false,
  "error": {
    "code": "FORBIDDEN",
    "message": "API key lacks 'write' permission required for this endpoint"
  },
  "meta": {
    "request_id": "req_jkl012",
    "timestamp": "2026-02-01T12:00:00Z"
  }
}

429 Rate Limit Exceeded

429RATE_LIMIT_EXCEEDED
{
  "success": false,
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Rate limit exceeded. Retry after 45 seconds."
  },
  "meta": {
    "request_id": "req_mno345",
    "timestamp": "2026-02-01T12:00:00Z",
    "retry_after": 45
  }
}

Retry Strategies

Not all errors should be retried. Use the following guidelines to determine when and how to retry failed requests:

  • 429 Rate Limit: Always retry with exponential backoff using the Retry-After header
  • 500 Internal Error: Retry up to 3 times with exponential backoff
  • 412 Precondition Failed: Retry only after the precondition clears. Keep polling the content until it is ready, or connect the social account first.
  • 400 / 401 / 402 / 403 / 404 / 409: Do NOT retry. Fix the request, the key, or the balance first.
async function apiRequest(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    const res = await fetch(url, options);

    if (res.ok) return res.json();

    const body = await res.json();

    // Don't retry client errors (except rate limits)
    if (res.status < 500 && res.status !== 429) {
      throw new Error(`API Error: ${body.error.code}: ${body.error.message}`);
    }

    if (attempt === maxRetries) {
      throw new Error(`Failed after ${maxRetries + 1} attempts: ${body.error.code}`);
    }

    // Exponential backoff: 1s, 2s, 4s
    const retryAfter = res.headers.get('Retry-After');
    const delay = retryAfter ? parseInt(retryAfter) * 1000 : Math.pow(2, attempt) * 1000;
    await new Promise(resolve => setTimeout(resolve, delay));
  }
}

Best Practices

  • Always check the success field before accessing data
  • Log request_id from error responses for debugging
  • Implement exponential backoff for 429 and 500 errors
  • Check credit balance before expensive operations to avoid 402 errors
  • Validate input client-side before sending to reduce 400 errors
  • Use appropriate permissions and scopes to prevent 403 errors