Errors
Every Direct API error code, what it means, and whether to retry, including what to do after a paid call fails with a 5xx.
Every error has the same body. Branch on the HTTP status and code; show description or error.message to people.
{
"description": "Human-readable explanation, safe to log.",
"code": "machine_readable_code",
"data": { "request_id": "…", "…": "…" },
"error": { "error_code": "…", "message": "…" }
}Every response, success or error, carries X-Request-Id. Include it when you contact support.
Error codes
| HTTP | code | Meaning | Retry |
|---|---|---|---|
| 400 | invalid_request | malformed JSON, an unknown body field, or input fails the tool's schema (each bad field is named) | no, fix the request |
| 401 | invalid_api_key | missing, malformed, revoked or expired key | no |
| 402 | insufficient_credits | the organization cannot pay for the call | after a top-up |
| 402 | api_key_credit_limit_reached | the call would exceed the key's daily, monthly or total limit (data.period says which) | after the window resets or the limit is raised |
| 402 | subscription_paused | the organization's subscription is paused | after it is resumed |
| 402 | payment_required | the organization's subscription is past due | after the payment is completed |
| 403 | direct_api_disabled | the Direct API is not enabled for this organization | no, contact Morphic |
| 403 | insufficient_scope | the key lacks the scope this tool needs (data.required_scopes) | no, use another key |
| 403 | plan_upgrade_required | the model or feature is not on your plan | no |
| 403 | tool_not_available | the tool charges credits and paid tools are not switched on for your organization yet (data.tool names it); your Morphic contact switches them on | no |
| 403 | model_disabled_by_organization | an org admin switched this model, resolution or audio option off and has not allowed it for the API | no, ask your admin |
| 404 | not_found | unknown tool, generation or webhook, or one outside this key's reach | no |
| 409 | idempotency_conflict | Idempotency-Key reused with a different body or tool | no, use a new key |
| 409 | idempotency_in_progress | the original request with this key is still running | yes, after a second |
| 409 | idempotency_outcome_unknown | the original request with this Idempotency-Key failed or never answered after it may have run, so its outcome is unknown | no: check its result, then use a new key |
| 413 | payload_too_large | body over 1 MB | no |
| 422 | tool_refused | the input is well formed but cannot run; nothing was charged | no, change the input |
| 429 | rate_limited | a rate limit was hit | yes, after Retry-After |
| 500 | internal_error | our fault | a free call, yes; a paid call, see below |
| 503 | service_unavailable | temporary overload or maintenance | a free call, yes, with backoff; a paid call, see below |
| 504 | tool_timed_out | the tool did not answer within 60 s; a call that starts generations may still have started them | a free call, yes; a paid call, see below |
A 422 tool_refused names the field, the value and the values that would have worked; see Tool refusals. A generation that fails after it started reports its own error.error_code on the generation object, and its charge is refunded.
Paid calls that answer 5xx
A paid call that answers 500, 503 or 504 may have started work and charged for it before it failed. Retrying it with the same Idempotency-Key never runs it twice: the retry answers 409 idempotency_outcome_unknown.
- Check what the call did:
list_generations, orGET /v1/direct/usagefiltered by time. - Send a new
Idempotency-Keyonly for work that did not start.
When no answer arrived at all (a dropped connection), retry with the same key. You get the stored answer, or 409 idempotency_in_progress while it still runs. See Idempotency.
If you have any trouble or have any questions, feel free to reach out. We're happy to help. Write to us at support@morphic.com.