Errors & refunds
HTTP status codes returned by the API, error shape, and the automatic refund contract.
Status codes
| Code | Meaning | Retryable |
|---|---|---|
200 | Request accepted or task snapshot returned | — |
400 | Request body failed validation — inspect details for field-level errors | No (fix the payload) |
401 | Missing or invalid credentials | No (check key) |
402 | Insufficient credits — no charge was made | No (top up) |
404 | Task not found, or owned by a different caller | No |
500 | Unexpected server error | Yes, with backoff |
Error shape
All errors return JSON with an error field. Some include additional keys.
{
"error": "Invalid request",
"details": {
"formErrors": [],
"fieldErrors": {
"prompt": ["Prompt is required"]
}
}
}{
"error": "Insufficient credits",
"required": 12
}{ "error": "Unauthorized" }Automatic refunds
Credits are pre-debited at submission time. If the task ends in status: 2 (FAILED) — for any reason, including provider timeouts and storage errors — credits are refunded atomically via a creditRefunded flag on the task row. You do not need to request the refund.
The refunded amount equals creditsUsed from the submission response. Check creditsRefunded: true in the GET /api/ai/tasks/{id} response to confirm.
Common failure modes
EMPTY_RESULT— the upstream provider reported success but returned no output URL. Auto-refund applies.STORAGE_ERROR— we could not persist the upstream output to our CDN. Auto-refund applies.- Provider-specific codes — passed through from the upstream model. Auto-refund applies.
Idempotency
Endpoints are not yet idempotent. If a POST /generate call times out from the client side, check for any recent tasks belonging to your account via the dashboard before retrying, to avoid double-charging.