Errors
Errors return the matching HTTP status and a JSON body of the shape { "error": { "code", "message" } }. Branch on the stable code rather than the human-readable message.
| Status | Code | Meaning |
|---|---|---|
401 | missing_api_key | No API key was provided. |
401 | invalid_api_key | The key is invalid or revoked. |
402 | quota_exceeded | Monthly PDF quota reached; upgrade your plan. |
402 | ai_quota_exceeded | Monthly AI-authoring allowance reached; upgrade your plan. |
403 | upgrade_required | quality "pro" AI authoring requires a paid plan. |
403 | watermark_not_allowed | Custom watermarks require a paid plan. |
404 | template_not_found | No template with that id exists for your account. |
404 | generation_not_found | No generation with that id exists for your account. |
409 | duplicate_request | This Idempotency-Key was already used within the last 24 hours. |
429 | rate_limited | Too many requests; retry after the Retry-After delay. |
429 | test_quota_exceeded | The account's 100-request daily test allowance was reached. |
422 | invalid_json | The request body was not valid JSON. |
422 | invalid_request | The request body failed validation (e.g. prompt missing or too long). |
422 | invalid_options | options failed validation (unknown key, bad units/bounds, invalid filename, etc.). |
422 | missing_template_id | The 'template_id' field is required. |
422 | data_too_large | The 'data' payload exceeds 256 KB. |
422 | template_too_large | Stored template HTML exceeds 512 KB. |
422 | template_compile_error | The template has a syntax error. |
422 | template_render_error | The template failed to render with this data. |
422 | missing_data_fields | options.strict was set and the template references fields absent from data. |
422 | invalid_webhook_url | options.webhook_url must be a public https URL. |
501 | async_unavailable | Async webhook delivery is not enabled on this deployment. |
502 | enqueue_failed | The async generation job could not be queued; retry. |
502 | ai_failed | AI template generation failed; retry. |
502 | render_failed | The render service returned an error. |
504 | render_timeout | Rendering took longer than 20 seconds. |
402, 429, 502 and 504 are safe to retry with backoff; for 429, wait for the Retry-After header. 4xx validation errors are not retryable: fix the request first.
Every /v1/generate response includes X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset so you can pace requests before hitting a 429.
Every response also carries an X-Request-Id header — a stable id for that request, surfaced in your dashboard Generation logs. Binary renders that completed despite unresolved template variables include X-Doclinth-Warnings: missing=<paths>; URL responses carry the same as a warnings JSON array. Set "options": { "strict": true } to get 422 missing_data_fields instead of a partial render.