PDFCraft

Errors

One shape, stable codes. The docs_url in any error response links straight to its heading below.

{ "error": {
    "code": "quota_exceeded",
    "message": "Monthly render quota reached (100/100). …",
    "docs_url": "https://pdfcraft.dev/errors#quota_exceeded"
} }
HTTPCodeBilled?
400invalid_requestfree
401invalid_api_keyfree
402payment_requiredfree
404not_foundfree
408render_timeoutfree
422render_failedbilled
429rate_limitedfree
429quota_exceededfree
415unsupported_filefree
422extraction_failedfree
500internal_errorfree

What counts as billable

A render is billed if Chromium actually ran. Successes count, and so does render_failed — the browser did the work, your HTML is what broke. Timeouts, our own failures, and every 4xx that never reached the browser are free.

invalid_request · HTTP 400 · free

Both html and url were supplied, or neither, or an option is out of range.

Read the message — it names the offending field. Send exactly one of html or url.

invalid_api_key · HTTP 401 · free

The Authorization header is missing, malformed, or the key has been revoked.

Send "Authorization: Bearer sk_live_…". Issue a fresh key from the dashboard.

payment_required · HTTP 402 · free

The last subscription payment failed, so the account is past_due.

Update the card on the billing portal. Rendering resumes the moment payment clears.

not_found · HTTP 404 · free

No render with that id belongs to your account.

Check the id. Ids from another account also return 404, never 403, so they cannot be probed.

render_timeout · HTTP 408 · free

The page did not finish within timeoutMs and was force-closed.

Raise timeoutMs (max 120000), or relax waitFor — networkIdle on a page with a long-poll never settles.

render_failed · HTTP 422 · billed

Chromium ran but the page threw, navigation failed, or waitFor.selector never appeared.

Load the same HTML in a browser. This one is billable because the browser did the work.

rate_limited · HTTP 429 · free

More requests per second than the plan allows.

Honour the Retry-After header and back off. Paid plans allow 20 req/s.

quota_exceeded · HTTP 429 · free

A free-plan account has used all 100 renders in the current period.

Upgrade, or wait for resets_at from GET /v1/usage. Paid plans never hard-stop; they accrue overage.

unsupported_file · HTTP 415 · free

The file is not a PDF, is password-protected, or is corrupt beyond parsing.

Send an unencrypted PDF. Decrypt it first — we deliberately do not accept passwords, so we never hold one.

extraction_failed · HTTP 422 · free

The PDF parsed but carries no text layer, so there is nothing to extract. Usually a scan or a photo.

Check pages_without_text in the response. A scanned document needs OCR, which this endpoint does not do.

internal_error · HTTP 500 · free

Something on our side broke.

Retry with backoff. Never billed. If it persists, send us the render id.