Reference

Error Codes

All API errors follow a consistent JSON structure. Use the code field to programmatically handle specific error cases.

Error format

Every error response includes an error object with three fields:

json
{
  "error": {
    "code":    "INSUFFICIENT_BALANCE",
    "message": "Your wallet balance ($0.01) is below the cost of this request ($0.02).",
    "status":  402
  }
}

The HTTP status code on the response matches the status field in the body. Always check the code field — it's machine-readable and stable across API versions.

4xx — Client errors

These errors are caused by your request. Fix the issue before retrying (except 429).

Error CodeHTTP StatusDescription
INVALID_REQUEST400Malformed JSON body or missing required fields.
INVALID_MODE400mode must be "1k" or "2k".
PROMPT_TOO_LONG400Prompt exceeds 2000 character limit.
IMAGE_TOO_LARGE400Base64-encoded image exceeds 10MB limit.
INVALID_IMAGE_FORMAT400Image must be JPEG or PNG.
UNAUTHORIZED401Authorization header missing or malformed.
INVALID_TOKEN401Token does not exist or has been revoked.
ACCOUNT_SUSPENDED403Your account has been suspended. Contact support.
INSUFFICIENT_BALANCE402Wallet balance is below the cost of this request.
JOB_NOT_FOUND404Job ID does not exist or belongs to another account.
CONTENT_MODERATED422Prompt or image failed content moderation screening.
RATE_LIMIT_EXCEEDED429Too many requests. Wait before retrying.
INSUFFICIENT_BALANCE (402) means your wallet is too low. Top up via the dashboard or POST /v1/wallet/topup before retrying.

5xx — Server errors

These are unexpected errors on our end. They are safe to retry. Your wallet is never charged for server-side failures.

Error CodeHTTP StatusDescription
GENERATION_TIMEOUT503Generation worker did not respond in time. Job marked failed. No charge.
STORAGE_ERROR503Image was generated but could not be saved to S3. No charge.
SERVICE_UNAVAILABLE503API is temporarily unavailable. Check status.sharkapi.dev.
INTERNAL_ERROR500Unexpected server error. If persistent, contact support with the job_id.

Error handling pattern

Retry 429 and 5xx errors with exponential backoff. For client errors, fix the request before retrying.

javascript
async function apiRequest(url, options, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    const res = await fetch(url, options);

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

    const { error } = await res.json();

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

    // Retry with exponential backoff
    if (attempt < maxRetries) {
      const delay = Math.pow(2, attempt) * 1000; // 2s, 4s, 8s
      await new Promise(r => setTimeout(r, delay));
    }
  }
  throw new Error("Max retries exceeded");
}
Failed jobs (5xx at generation time) are automatically tracked in your request history and never deduct wallet balance.