/ Features

Every knob we ship.
Nothing we don't.

A full list of what 21pdf does, organised by concern. Every feature is on every plan — plans gate throughput, not capability.

01

Rendering

Chromium — the same engine your users will run the output through.

/ Engine

Chromium-only

Headless Chromium. Replaced wkhtmltopdf in April 2026 — same paginator, modern flex/grid support.

/ Engine

Paper sizes

A3, A4, A5, Letter, Legal, Tabloid via PDFOptions.page_size.

/ Engine

Orientation

Portrait or landscape via PDFOptions.orientation.

/ Engine

Margins

Per-side in mm: margin_top, margin_bottom, margin_left, margin_right.

/ Engine

Network-idle wait

Hold the render until XHRs settle — wait_for_network_idle: true.

/ Engine

CSS @page respected

Print media queries applied; your @page size/margins override PDFOptions.

02

Inputs

Three shapes. Pick the one that fits the pipeline upstream of you.

/ Source

Raw HTML

POST a full HTML payload in the request body under html.

/ Source

URL fetch

Send url; we fetch the page server-side and render it. SSRF-checked before fetch.

/ Source

simple_html shortcut

Fragment-level input. We wrap it in a minimal document before rendering.

/ Source

Inline CSS & fonts

System fonts + any @font-face loaded via your HTML. No font upload API.

/ Source

No markdown

Not in v1. Pre-render to HTML client-side — many good libraries exist.

/ Source

Sanitisation

None. The renderer trusts your HTML. Don’t pass unsanitised user input.

03

Job model

Async by default — the worker pool keeps the HTTP surface fast.

/ Flow

Submit → pool → download

POST returns job_id immediately. Polling endpoint reports queued → processing → succeeded|failed.

/ Flow

Polling endpoint

GET /v1/jobs/:id returns status + PDF pointer when ready.

/ Flow

Signed download

GET /v1/jobs/:id/download streams the PDF from MinIO — single-use within the retention window.

/ Flow

Concurrency gate

Per-plan in-flight limit — 1 Free, 2 Starter, 3 Pro, 5 Business. 429 with Retry-After if exceeded.

/ Flow

Timeouts

Per-job render timeout. Failed jobs do NOT count toward your quota.

/ Flow

Orphan sweeper

Retention worker deletes PDFs older than PDF_RETENTION_DAYS — no stale storage cost.

04

Auth & keys

Bearer tokens. JWT for humans, opaque API keys for machines.

/ Auth

Bearer JWT

Short-lived tokens from /v1/auth/login. 3-tier RBAC: user, admin, superadmin.

/ Keys

Per-user API keys

qpdf_live_* and qpdf_test_* prefixes. Rotate + revoke anytime from the dashboard.

/ Keys

Integration keys

Named keys for internal projects (bill21-prod, etc.) — tenant-scoped, unlimited.

/ Keys

Key in header

Authorization: Bearer qpdf_live_... — same header as the JWT path.

/ Keys

Audit log

Every key use lands in audit_log with request-id, user-id, action, result.

/ Keys

No SDK yet

Raw REST on purpose. curl + your HTTP client of choice. SDKs are roadmap.

05

Security

Boring defences that actually matter for a URL-fetching service.

/ SSRF

HTTP-boundary block

Reject 127.0.0.0/8, 169.254.0.0/16, 10/8, 172.16/12, 192.168/16, fe80::/10, and link-local before a fetch.

/ SSRF

Chromium interceptor

Second-layer check inside the browser — every sub-request the page makes is re-validated.

/ Storage

SSE-S3 at rest

MinIO server-side encryption for PDFs in transit to/from storage.

/ Network

No inbound TLS inside docker

Single-host bridge; internal TLS declined as redundant. Public TLS at edge.

/ Audit

Tamper-evident log

audit_log captures auth, billing, admin actions. Append-only from application.

/ Abuse

Lockout on brute force

Email/password login lockout after repeated failures.

06

Billing & ops

Razorpay subscriptions wired end-to-end.

/ Billing

Razorpay subscriptions

Hosted checkout. We never touch PAN — PCI scope stays at SAQ A.

/ Billing

Quota headers

X-Quota-Used + X-Quota-Limit on /v1/convert so clients self-rate-limit.

/ Billing

7-day grace + dunning

Nag emails on day 1/3/5 after failed payment; auto-downgrade on day 7.

/ Billing

Cycle-aligned reset

usage_this_cycle resets on subscription.charged webhook, not calendar month.

/ Billing

Plan changes

Upgrades immediate + prorated. Downgrades deferred to period end.

/ Ops

Health + audit endpoints

GET /healthz for readiness; /v1/admin/* for superadmin operations.

Build on top of it

Get an API key → Read the docs