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 Code | HTTP Status | Description |
|---|---|---|
| INVALID_REQUEST | 400 | Malformed JSON body or missing required fields. |
| INVALID_MODE | 400 | mode must be "1k" or "2k". |
| PROMPT_TOO_LONG | 400 | Prompt exceeds 2000 character limit. |
| IMAGE_TOO_LARGE | 400 | Base64-encoded image exceeds 10MB limit. |
| INVALID_IMAGE_FORMAT | 400 | Image must be JPEG or PNG. |
| UNAUTHORIZED | 401 | Authorization header missing or malformed. |
| INVALID_TOKEN | 401 | Token does not exist or has been revoked. |
| ACCOUNT_SUSPENDED | 403 | Your account has been suspended. Contact support. |
| INSUFFICIENT_BALANCE | 402 | Wallet balance is below the cost of this request. |
| JOB_NOT_FOUND | 404 | Job ID does not exist or belongs to another account. |
| CONTENT_MODERATED | 422 | Prompt or image failed content moderation screening. |
| RATE_LIMIT_EXCEEDED | 429 | Too 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 Code | HTTP Status | Description |
|---|---|---|
| GENERATION_TIMEOUT | 503 | Generation worker did not respond in time. Job marked failed. No charge. |
| STORAGE_ERROR | 503 | Image was generated but could not be saved to S3. No charge. |
| SERVICE_UNAVAILABLE | 503 | API is temporarily unavailable. Check status.sharkapi.dev. |
| INTERNAL_ERROR | 500 | Unexpected 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.
