Errors & Quotas
The error envelope, common error codes, and how free-credit generation behaves.
Error format
Every error is JSON with the same envelope:
{
"error": {
"code": "INSUFFICIENT_CREDITS",
"message": "Required 10 credits, available 4, missing 6. Choose lower-cost settings to continue."
}
}code is stable and safe to branch on; message is human-readable and may change.
Error codes
| HTTP | Code | When | What to do |
|---|---|---|---|
400 | INVALID_INPUT | The body fails validation — missing prompt, bad enum value, or a rule like audio-without-pro. | Fix the request; the message names the offending field. |
404 | JOB_NOT_FOUND | The job ID doesn't exist or doesn't belong to your key/browser session. | Check the ID you stored from job creation. |
402 | INSUFFICIENT_CREDITS | The current free and other credit balance cannot cover the server quote. | Claim eligible free credits or choose lower-cost settings. |
403 | CHALLENGE_REQUIRED | Generation Risk found independent high-risk signals. | Complete the server-requested security check and retry with the same idempotency key. |
429 | GENERATION_COOLDOWN | High frequency and strong independent risk signals triggered a model-specific cooldown. | Wait for the cooldown to end; repeated requests do not extend it. |
502 | CREATE_JOB_FAILED | The render pipeline rejected or failed to accept the task. | Transient — retry with exponential backoff. |
500 | UNKNOWN_ERROR | Something unexpected on our side. | Retry once; if it persists, contact us. |
Failures after a job is accepted don't use this envelope — the job itself moves to status: "failed" with the reason in errorMessage, as described in job lifecycle.
Free credits
- Eligible guests and signed-in users explicitly claim free credits.
- Free credits expire at the next UTC midnight and are consumed before other credits.
- The server calculates the cost from the model, duration, resolution, audio, and supported Feature Video options.
- Failed or cancelled accepted jobs return credits to their original provenance; free refunds never become paid credits.
A clean integration pattern:
const res = await fetch(`${BASE}/api/ai-video/jobs`, { method: 'POST', headers, body });
if (res.status === 402) {
const { error } = await res.json();
if (error.code === 'INSUFFICIENT_CREDITS') {
// retain the draft and ask the user to claim or lower the quoted cost
}
}Need more than the free tier? Contact us and we'll help set up the right volume.