Skip to main content
Blink PDF is a REST API that converts Markdown into professional, print-ready PDFs in roughly 100 milliseconds. You send a JSON request body containing your Markdown content, and the API streams back a binary PDF — no browser, no headless Chrome, no fuss. This overview covers the base URL, available endpoints, request and response conventions, and what to expect when something goes wrong.

Base URL

All API requests are made to the following base URL:
The current API version is v1. Rendering endpoints are prefixed with /v1/; the unversioned health check lives at /health.
The base URL does not include a trailing slash. Append endpoint paths exactly as shown in the table below.

Endpoints at a Glance

Pick a curated look with the theme field (default report-clean) — call GET /v1/themes for the catalog, see Themes. Pick fonts per request with the fontStack field, or pull any Google Fonts family by URL with googleFontsUrl — see Fonts & Typography. Call GET /v1/fonts for the hosted catalog and GET /v1/style-targets for the full rules styling vocabulary.

Request Format

Render POST requests must include a JSON body and the following headers: POST /v1/render/validate accepts the same JSON body and x-api-key header, but expects Accept: application/json because the response is JSON, not PDF bytes. GET requests that require authentication need only the x-api-key header — no request body is sent.

Response Format

A successful call to POST /v1/render or POST /v1/templates/sandwich-document/render returns a binary PDF (application/pdf). Pipe or write the response body directly to a file rather than reading it as text. On the public free plan, successful PDF responses from POST /v1/render and template routes include a non-removable bottom-center footer (“Made with Blink PDF” plus the brand mark). The response status and schema are unchanged. GET /health, POST /v1/render/validate, and all error responses return JSON (application/json).

Validate before render

POST /v1/render/validate runs the same TypeBox schema and cross-field semantic checks as POST /v1/render, without generating a PDF, metering usage, or recording a successful render audit. Use it to iterate on rules, typography, furniture, and related options before spending a render. A valid body returns 200 with valid: true. When the caller is authenticated, the response also reports the resolved typography (declared pool, active body/heading families, and any unused declarations) and a contentDigest for delivery deduplication:
Validation failures return the same 400 error shape as a failed render request (validation_failed, invalid_body, and related codes). The endpoint does not emit X-Render-* or X-BlinkPDF-Usage-* headers.

Response Headers

Every successful render (POST /v1/render or POST /v1/templates/sandwich-document/render) includes render-status headers and, when the caller is authenticated under plan limits, usage and attribution headers. Both routes share the same spend-cap, tier rate/concurrency, and usage ledger path.

Render status

Each diagnostic object includes severity, code, message, and help (a blinkpdf://reference/… URI). When applicable, entries also include resource and httpStatus. Decode X-Render-Diagnostics like this:

Usage and attribution

Successful authenticated renders on both POST /v1/render and POST /v1/templates/sandwich-document/render emit usage and attribution headers when billing limits apply:

Sandwich template

POST /v1/templates/sandwich-document/render is metered like POST /v1/render: it counts 1 render unit on a successful billed response, shares spend-cap and tier rate/concurrency, applies the free-tier watermark when applicable, and emits the usage/attribution headers above (except cache and content-digest headers). Successful responses always include X-Template-Version (currently 1.0.0). Page-1 body clearance uses a flow offset for the header band; bottom margins reserve the repeating page-footer band and, when the last-page signature would not fit under the body, the signature band as well — so the Markdown body never collides with either chrome band. Client x-idempotency-key is not accepted on template routes (no body fingerprint / pre-check). Do not send it expecting dedupe.

Error Codes

When a request cannot be completed, the API returns a standard HTTP error status code with a JSON body of the shape { "error": "<code>", "detail": "<message>" }. Field-level validation failures may also include an errors array; each member can carry machine-readable kind, allowed keys/values, relocation hints, and optional variants (accepted shapes for object-valued unions: discriminant when, keys, required, enums — never internal numeric ranges).
When you receive a 429, read the Retry-After response header. It contains the number of seconds you should wait before sending another request.

Rate Limiting

Rate limits are enforced per API key and vary by plan. Template renders share the same sustained-rate and concurrency buckets as POST /v1/render. If you exceed your limit, the API returns 429 Too Many Requests and includes a Retry-After header.
Calls to GET /health and POST /v1/render/validate never consume render units. POST /v1/render/validate is, however, rate-limited in its own per-tier bucket, independent of render and template throughput — a validate burst never spends render throughput, and vice versa, so either can return 429 on its own. Only successful POST /v1/render and POST /v1/templates/*/render responses with X-BlinkPDF-Billing: counted consume render units.

Versioning

The current API version is v1, reflected in every endpoint path. When breaking changes are introduced, a new version prefix (e.g. /v2/) will be released alongside the existing version. You will always receive advance notice before an older version is deprecated.