Guarantees
Errors
When something goes wrong, the API responds with an appropriate HTTP status and a consistent JSON body. This page lists every code, its cause, and how to handle it in your code.
Error format
Unlike a success (which returns the binary), errors always come back as JSON in the format { error: { code, message } }. The code is stable and machine-readable — branch your logic on it, not on the message (which is for humans and may change).
error body
{
"error": {
"code": "template_not_found",
"message": "Template \"invoice\" not found."
}
}HTTP status + code
The HTTP status gives the category (4xx = problem with the request, 5xx = problem with the render). The
code gives the exact cause. Use them together.All codes
| HTTP | code | Meaning | What to do |
|---|---|---|---|
| 401 | missing_api_key | No authentication header was sent. | Send Authorization: Bearer or X-API-Key. |
| 401 | invalid_api_key | Key does not exist, is malformed, or has been revoked. | Check the key; generate a new one in the Dashboard if needed. |
| 402 | quota_exceeded | The organization's monthly render quota has run out. | Reach out to us (support@renderly.dev) to unlock more, or wait for the start of the next month. |
| 404 | template_not_found | The slug provided in template does not exist in the organization. | Check the template slug in the Dashboard (the slug is assigned when you save). |
| 422 | invalid_body | Invalid body: missing template/html, wrong type, invalid enum, etc. | Fix the JSON according to the endpoint reference. |
| 422 | template_empty | The template exists, but has no content to render. | Add at least one block to the template and save it in the editor. |
| 500 | render_failed | Render failure (invalid HTML, unreachable external resource, internal timeout). | Review the content; apply retry with backoff (it may be transient). |
Malformed JSON error
If the request body is not valid JSON, the API responds before schema validation with a parse error (
400 invalid_json). Make sure you send a Content-Type: application/json and a well-formed body.How to interpret by category
| Category | Codes | Nature | Retry? |
|---|---|---|---|
| Authentication (401) | missing / invalid_api_key | Credential missing or invalid. | No — fix the key first. |
| Quota (402) | quota_exceeded | Plan limit reached. | No — only after an upgrade or the start of the month. |
| Request (404 / 422) | template_not_found, invalid_body, template_empty | Something in the request is wrong. | No — retrying as-is gives the same error. |
| Render (500) | render_failed | Failure generating the document. | Maybe — it may be transient; exponential backoff. |
Recommended handling
Branch on the code and separate client errors (do not retry) from transient ones (retry):
node — handling by code
const res = await fetch("https://api.renderly.dev/v1/render", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.RENDERLY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ template: "invoice", data }),
})
if (!res.ok) {
const { error } = await res.json()
switch (error.code) {
case "quota_exceeded":
// pause the queue / alert billing
throw new QuotaError(error.message)
case "template_not_found":
case "template_empty":
case "invalid_body":
// client error: retrying without fixing it won't help
throw new BadRequest(error.code, error.message)
case "render_failed":
// may be transient: retry with backoff
throw new RetryableError(error.message)
default:
throw new Error(`${res.status} ${error.code}: ${error.message}`)
}
}Retry policy
| Situation | Strategy |
|---|---|
| render_failed | Retry with exponential backoff (e.g. 1s, 2s, 4s), at most 3 attempts. |
| quota_exceeded | Do not retry; alert billing and pause the queue. |
| client 4xx | Do not retry; log it and fix the request. |
| network timeout | Idempotent retry — the same body produces the same document. |
Render is idempotent for you
The same body produces the same document. On a network timeout, retrying is safe in terms of the result — but remember that each successful render counts against your quota.
The relationship between quota and the 402 is detailed in Limits & quota.
Next
Limits & quota
Monthly quota per organization, supported formats and sizes.
Renderly