Errors & limits
Error format
Section titled “Error format”Every error response has the same shape:
{ "error": { "code": "validation_failed", "message": "Invalid input", "details": [{ "field": "/customer/name", "reason": "Required property 'name' is missing" }] }, "meta": { "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736" }}Branch on code, which is stable, not on message, which is meant for people. details
is present for some codes, described below. Quote meta.trace_id when you contact support
about a failed request.
Status codes
Section titled “Status codes”| Status | code |
Meaning |
|---|---|---|
400 |
validation_failed |
The request or the render data is invalid. details lists each field. See Data & JSON Schema. |
400 |
invalid_json |
The body isn’t valid JSON. |
401 |
unauthorized |
The API key is missing, wrong or deleted. |
402 |
plan_limit_exceeded |
A plan quota is used up, such as monthly renders or the number of templates. |
403 |
forbidden |
The API key lacks the permission this call needs, such as render. |
404 |
not_found |
The template, version, file or job doesn’t exist in this workspace. A template with no published version also returns 404 for its latest version. |
406 |
not_acceptable |
The Accept header asks for an unsupported format. |
409 |
conflict |
The change conflicts with the current state, such as a duplicate asset alias. |
410 |
workspace_scheduled_for_deletion |
The workspace is being deleted and is read-only. |
412 |
conflict |
The If-Match header no longer matches. Reload and retry. |
422 |
render_failed |
The template failed while rendering. See below. |
429 |
rate_limit_exceeded |
Too many requests. See Rate limits. |
5xx |
internal_error, storage_error |
Something went wrong on our side. Retry with backoff. |
Render errors
Section titled “Render errors”A 422 render_failed means the data was valid but the template couldn’t render it.
details points at the failing spot:
{ "error": { "code": "render_failed", "message": "Template error in main.html at line 2: wrong type for value; expected float64; got string", "details": [ { "file": "main.html", "line": 2, "column": 30, "field": ".total", "reason": "wrong type for value; expected float64; got string" } ] }}Here the data sent "total": "12,50", a string, to a function that needs a number. A
schema typing total as number would have caught it earlier, as a 400 naming the field.
Render errors caused by the template are deterministic, so retrying won’t help. Render jobs retry only temporary failures; see Retries.
Rate limits
Section titled “Rate limits”Render calls are rate limited per workspace and per minute, with higher limits on higher plans. See Pricing for each plan’s limits and monthly render quota.
Every rate-limited response carries:
| Header | |
|---|---|
X-RateLimit-Limit |
Requests allowed in the current window |
X-RateLimit-Remaining |
Requests left in the current window |
X-RateLimit-Reset |
When the window resets, in Unix seconds |
Over the limit, the API answers 429 rate_limit_exceeded with a Retry-After header in
seconds. Wait that long before retrying. The limit is shared by all of the workspace’s API
keys, and covers both POST /v1/render and POST /v1/render/jobs.
Render limits
Section titled “Render limits”| Limit | |
|---|---|
| Render time | 45 seconds per document |
| Asset size | 10 MB per file |
| Page size | 200 inches on either side |
| Tags per file | 10, up to 128 characters each |
| Webhook endpoints | 10 per workspace |