Errors
The error envelope, status codes, and retry guidance.
Errors use the OpenAI envelope, so existing SDK error handling works unchanged:
{
"error": {
"message": "Your credit balance is exhausted or fully reserved by in-flight requests. Add credits at /dashboard/billing.",
"type": "insufficient_quota",
"param": null,
"code": "insufficient_credits"
}
}Status codes
| Status | type | code | Cause |
|---|---|---|---|
| 400 | invalid_request_error | null | Malformed JSON in the request body. |
| 400 | invalid_request_error | passthrough | Unknown role, invalid parameter value, and other upstream validation errors are forwarded from Azure with their status and body. |
| 401 | invalid_request_error | invalid_api_key | Missing, malformed, or revoked key. Check the Authorization: Bearer dw_live_... header. |
| 402 | insufficient_quota | insufficient_credits | Credit balance exhausted or fully reserved by in-flight requests. Unique to prepaid billing — there is no invoice to run negative against. Top up at /dashboard/billing. |
| 404 | invalid_request_error | model_not_found | Model other than gpt-5.5 / gpt-5.5-2026-04-24. |
| 404 | invalid_request_error | unknown_endpoint | A path Draftworks does not implement (embeddings, images, audio, batch, fine-tuning, and any other /v1/* — see SDK compatibility). |
| 404 | invalid_request_error | receipt_not_found | GET /v1/receipts/{id} with an unknown id. |
| 429 | passthrough | passthrough | Rate limited upstream. Retry with exponential backoff — see below. |
| 502 | api_error | upstream_unavailable | The Draftworks gateway could not reach the upstream at all. Safe to retry. |
| 5xx | passthrough | passthrough | Other upstream (Azure) errors are forwarded with their status and body. |
The OpenAI SDKs map these to typed exceptions (AuthenticationError for 401, NotFoundError for 404, APIStatusError with status_code == 402 for credit exhaustion, and so on).
Non-2xx responses from the upstream are forwarded with the upstream status and body only; the original upstream headers are not passed through (only content-type is preserved). Do not rely on reading a retry-after or other rate-limit header from a Draftworks response — retry with exponential backoff instead (see below).
Avoiding 402 in production
A 402 means requests stop until you top up. There is no auto-top-up or balance-alert feature, so mitigate in your own operations:
- Monitor your balance on /dashboard/billing and top up manually before it runs out, or detect the
insufficient_creditscode (HTTP 402) in your client and alert yourself. - Note the edge case: a large streamed response can take the balance slightly negative, since streams are metered as they complete. The overage is honored — the stream finishes — and the deficit is deducted from your next purchase. Only the next request is blocked. Details in pricing and credits.
Retry guidance
- Retry freely:
GET /v1/modelsandGET /v1/receipts/{id}are idempotent reads. - Retry with exponential backoff: 429, 502, and other 5xx on POST requests. Start around 1 s, double per attempt, cap at 4–5 attempts with jitter. A completed request that failed only in transit will have produced a receipt; retries create new, separately billed requests.
- Do not blind-retry: 400, 401, 402, 404. These fail identically until the underlying problem is fixed.
- Streams are not auto-resumed. A dropped stream cannot be continued from the break point; issue a new request. If the client aborts mid-stream you are still billed for the full generation the upstream produced, since the upstream completes regardless of client disconnect; the receipt remains retrievable by its request id. See streaming.