Errors & limits
Error shape
Section titled “Error shape”Every DocJet error response is JSON with the same three fields:
{ "error": "Human-readable message", "code": "MACHINE_READABLE_CODE", "hint": "What to do about it"}Agents and SDKs should branch on code, never on the message text.
Error taxonomy
Section titled “Error taxonomy”| Code | HTTP | Meaning |
|---|---|---|
AUTH_INVALID | 401 | API key missing, malformed, or revoked |
PAYLOAD_INVALID | 422 | Request body fails validation (wrong shape, oversized HTML, bad webhook_url…) |
TEMPLATE_NOT_FOUND | 404 | template_id does not exist — list valid IDs with GET /v1/templates |
RATE_LIMITED | 429 | Per-minute request limit exceeded — back off and retry |
QUOTA_EXCEEDED | 429 | Monthly render quota exhausted — upgrade or wait for the next period |
CONCURRENCY_EXCEEDED | 429 | Too many simultaneous renders for your plan — retry after in-flight renders finish |
INTERNAL_ERROR | 500 | Server-side failure — safe to retry with backoff |
Related codes you may see outside rendering: SIGNUP_THROTTLED (429, signup is per-IP throttled), AUTH_EMAIL_EXISTS (409, email already has a key).
Telling the 429s apart
Section titled “Telling the 429s apart”All three 429 codes are distinct on purpose:
RATE_LIMITED— you’re calling too fast. Wait seconds.CONCURRENCY_EXCEEDED— too many renders in flight at once. Wait for completions.QUOTA_EXCEEDED— the monthly budget is gone. Upgrade viaPOST /v1/billing/checkoutor wait for the period reset.
Limits per plan
Section titled “Limits per plan”| Plan | Renders / month | Rate limit | Concurrent renders |
|---|---|---|---|
| Demo key (public) | 50 | 3 req/min | 1 |
| Free | 100 | 10 req/min | 1 |
| Starter ($9) | 1,000 | 60 req/min | 2 |
| Pro ($29) | 10,000 | 300 req/min | 5 |
| Business ($99) | 100,000 | 1,000 req/min | 10 |
Check where you stand at any time:
curl https://api.docjet.dev/v1/keys/usage \ -H "Authorization: Bearer $DOCJET_API_KEY"Input limits
Section titled “Input limits”- Raw
htmlpayloads: max 512 KB. template_id: must match^[a-z0-9][a-z0-9-]{0,63}$.webhook_url: HTTPS only, default port, max 2,048 characters.