POST /generate — plus a public playground endpoint and a health check.
Base URL
.dev is on the HSTS preload list, so plain HTTP is never served.
Authentication
POST /generate requires an API key sent as a bearer token. See Authentication.
Requests and responses
- Request bodies are JSON (
Content-Type: application/json). - A successful generate response is the PDF itself —
Content-Type: application/pdf, the raw bytes as the body. There’s no JSON envelope around it. - The API is synchronous. You get the finished PDF in the response to your request. There’s no job to create, no status to poll, no webhook to wait for.
Endpoints
API keys themselves are created and revoked in the dashboard, not through this API. The key-management routes are part of the dashboard’s signed-in session, not the programmatic surface.
Errors
Every error is an RFC 7807 Problem Details document, served asapplication/problem+json:
title,status, and (usually)detailare always present.errorsis an array of{ code, message }objects, present on most failures. Thecodeis a stable, machine-readable string — branch on it; showmessageto humans. (It’s a top-level field, per the Problem Details extension convention — not nested underextensions.)
code values is on the errors page.
Rate limits
Limits are enforced per API key (and per IP for anonymous endpoints). Exceeding one returns429 Too Many Requests with a Retry-After header (seconds).
The
/generate limiter is a token bucket: it refills at 60 permits per minute and lets you spend up to 120 in a burst. The 429 body uses the standard error envelope with code: "rate_limit.exceeded".
Quotas and billing
Separate from the per-minute rate limit, each plan includes a monthly document quota. When you reach it,/generate returns 402 Payment Required with code: "quota.exceeded" — the request is blocked, not billed as overage. You upgrade deliberately, or wait for the month to roll over.
Request size
The body includes any base64-encoded images — they’re the usual reason a request gets large.