What a failure looks like.
Application errors use the HTTP status and a JSON detail object. Show message to a person. Branch on code.
{
"detail": {
"code": "text_too_long",
"message": "5,001 characters is over the 5,000 limit for one run."
}
}
Some errors add details. A low balance looks like this:
{
"detail": {
"code": "insufficient_balance",
"message": "Available balance is 0.01 USD. This run needs about 0.05 USD reserved until the final cost is known.",
"details": {
"available_usd": "0.010000",
"hold_required_usd": "0.050000",
"is_estimate": true
}
}
}
Status codes
| HTTP | Code | When |
|---|---|---|
| 400 | invalid_request | The body is missing prose, quality is not low, standard, or high, or an estimate has neither text nor word_count. |
| 400 | text_too_long | The draft is over max_chars_per_run (5,000 characters). |
| 400 | confirmation_required | DELETE /v1/runs without ?confirm=true. |
| 401 | unauthenticated | Missing or unknown API key, or no session. |
| 402 | insufficient_balance | The available balance cannot cover the hold. Nothing is queued. |
| 403 | account_suspended | The account cannot call the API. |
| 403 | forbidden | An API key tried to create another API key. |
| 404 | not_found | That run or key is not yours, or does not exist. |
| 409 | run_in_progress | Delete was called on a queued or running run. Cancel it first. |
| 422 | The JSON shape is wrong. Unknown fields such as model or mode are rejected here. The body is a validation list, not a code. | |
| 429 | rate_limited | Too many creates. Wait for the Retry-After header. details.retry_after_seconds says the same thing. |
| 503 | provider_unavailable | The account is not ready to run yet. Try again shortly, and check can_run_reason on GET /v1/me. |
Validation errors
A 422 means the request never reached a run. The usual cause is a field the API no longer accepts.
{
"detail": [
{
"type": "extra_forbidden",
"loc": ["body", "model"],
"msg": "Extra inputs are not permitted"
}
]
}