Docs menu

API referenceErrors and quota

Errors and quota

The stable error codes, what each one means, and how the monthly quota is counted.

This page is the code reference: what each refusal means and what to do about it. The numbers behind the refusals are on Limits: what each plan allows, how a document is measured and what a refusal costs.

Error format#

Every error is a JSON body with at least two fields. code is the stable contract: it never changes meaning, so script against it. error is a sentence for people and may be reworded at any time. A refusal against a limit (413 payload_too_large, 422 too_many_resources, 422 too_many_pages, 429 rate_limited and 422 render_timeout) adds limit: the limit's name, the value that was exceeded and the plan it came from, so a client reads the number without parsing the sentence. The names are the plan columns Limits lists. One refusal in that set carries no limit: a 413 with reason preparation_limit, where the renderer, not the plan, set the bound. Treat limit as optional and read reason when it is missing. A failed remote resource adds reason and resource_id. When the server knows how long to wait, a Retry-After header gives the number of seconds. Only the codes the table marks send it.

The three shapes, as the document publishes them:

HTTP/1.1 400 · empty_document
{
  "code": "empty_document",
  "error": "The request carried no Markdown to render."
}
HTTP/1.1 413 · payload_too_large
{
  "code": "payload_too_large",
  "error": "The document, one of its resources or the request as a whole is over a size limit.",
  "reason": "markdown_limit",
  "limit": {
    "name": "markdown_kb",
    "value": 256,
    "plan": "free"
  }
}
HTTP/1.1 400 · invalid_request
{
  "code": "invalid_request",
  "error": "A field of the request was missing, of the wrong type or out of range.",
  "reason": "render_options"
}

401 responses also carry WWW-Authenticate: Bearer. All API responses, errors included, are sent with Cache-Control: no-store.

Error codes#

The codes below are every value the documented routes can produce, with the fields the envelope carries beside code and error. The sentences are the current wording and may change.

StatusCodeMeaningWhat to doAlso carriesRetry-After
401unauthorizedThe request carried no API key, or one that is no longer valid.Check the Authorization header and that the key has not been revoked.NoneNo
403account_blockedThe account is blocked and cannot render or download until support lifts it.Contact support; retrying answers the same.NoneNo
403email_unverifiedThe account's email address has not been verified yet.Open the link in the sign-up mail or request a new one, then call again.NoneNo
400invalid_requestA field of the request was missing, of the wrong type or out of range.Fix the field reason names and send the request again.reasonNo
413payload_too_largeThe document, one of its resources or the request as a whole is over a size limit.Send a smaller document, and on preparation_limit make it simpler rather than changing plan.limit, reason, renderer_boundNo
400empty_documentThe request carried no Markdown to render.Send a document with content in it.NoneNo
422too_many_pagesThe rendered document has more pages than were allowed for it: the plan's page limit, or the deployment's ceiling where that is lower.Split the document. limit.plan names the plan whose limit it was, and a plan with a higher one lifts it; limit.plan null means the deployment capped it below the plan, and only the operator can raise that.limitNo
422too_many_resourcesThe document references more resources than one render loads.Reference fewer resources, or split the document into several renders.limitNo
422 / 503resource_fetch_failedA resource the document references could not be loaded.Check that the resource resource_id names is reachable, then retry.reason, resource_idNo
409idempotency_in_progressA render with the same Idempotency-Key is still running.Wait the Retry-After seconds and retry with the same key.NoneYes
422idempotency_mismatchThe Idempotency-Key was already used for different document or resource content.Use one Idempotency-Key per document; retrying unchanged answers the same.NoneNo
429idempotency_replay_limitThe Idempotency-Key has been replayed as often as the plan allows.Render under a new key, which uses one of the period's documents, or wait for the key to expire.NoneYes
429rate_limitedThe account sent more requests, or asked for more concurrent renders, than its plan allows.Wait the Retry-After seconds and retry, letting the running renders finish first when limit names concurrency.limitYes
402quota_exhaustedThe account has no documents left for the current period.Check GET /v1/usage, then upgrade the plan or wait for the next period.NoneNo
503quota_unavailableThe account's usage could not be checked, so no render was started.Retry after a short pause; nothing was counted.NoneNo
503queue_fullThe render queue is full; the same request can be sent again shortly.Retry after the Retry-After delay; the document was returned to your period.NoneYes
422render_timeoutThe render ran past the time allowed for it: the plan's time limit, or the deployment's ceiling where that is lower.Simplify or split the document; retrying unchanged answers the same. limit.plan null means the deployment capped the time below the plan, and only the operator can raise that.limitNo
503render_unavailableNo render capacity was available for this request, or this deployment does not offer what it asked for, such as upload delivery.Retry after a pause, and report it if it persists.NoneNo
422render_failedThe document could not be rendered.Retry once; if it fails again the document is at fault.NoneNo
403plan_requiredThe account's plan does not include what the request asked for.Move to a plan that includes what reason names.reasonNo
400invalid_bundleThe certificate bundle in the request could not be read.Check the bundle's format against what reason says and send it again.reasonNo
400certificate_expiredThe certificate is past its validity period.Seal with a certificate that is still inside its validity period.reasonNo
422signing_failedThe document was rendered but could not be sealed.Retry once, and check the certificate if it fails again.NoneNo
503signing_unavailableSealing is temporarily unavailable.Retry after a pause; reason says what was unavailable.reasonNo
400unknown_signing_identityNo stored certificate of this account matches the one the request named.Name one of the account's stored certificates, or send the bundle in the request.NoneNo
404not_foundThe usage period asked for does not belong to this account, or the path does not exist.Check the path and, on GET /v1/usage, that period is one of this account's periods.NoneNo
405method_not_allowedThe path exists but does not answer this HTTP method; the Allow header lists the ones it does.Use a method the Allow header names.NoneNo
424upload_failedThe storage at upload_url did not accept the PDF or did not answer in time; status is its HTTP status, or null when no answer arrived.Check that the pre-signed URL is still valid and signed for Content-Type: application/pdf, then retry with a fresh one; the document was returned to your period.statusNo
500internal_errorThe request failed for a reason the service could not classify.Retry after a pause, and report it if it persists.NoneNo

Monthly quota#

Each plan includes a number of documents per period; the counts are on Limits. Periods start each month at 00:00 UTC on the day the account signed up or, after a purchase, on the day of the purchase. A monthly upgrade starts a new period on its day. The counter is transactional in the database, so it is exact under concurrency. It counts only PDFs that were actually served: a document is reserved before the render starts and returned to your period when the render fails, times out, exceeds the page limit, or cannot be dispatched. Which refusals return the document to your period is on Limits.

When the period's documents are used up, /v1/render answers 402 quota_exhausted; the message says the period's documents are used up and links to pricing. Grants add documents to the period. Check credits_used, credits_included, credits_granted and the period boundaries with GET /v1/usage.