PDFCraft
Products

Three things one PDF engine can do

They share a Chromium pool, an API key, an error vocabulary and a bill. That is the whole reason they are one product rather than three — you are not integrating three vendors to generate an invoice, read one back, and prove the estate is accessible.

Render — HTML in, PDF out.

One POST with your markup and a real Chromium renders it, with the print options you actually need — margins, headers and footers, page ranges, wait conditions. One browser is held open per process and hands out a fresh isolated context per render, so you are not paying a cold launch on every request the way a serverless PDF service does.

Endpoints
POST /v1/render
POST /v1/render/async
GET /v1/renders/:id
Billed perone render
Starts atFree for 100/month

Open the playground · Docs

Extract — PDF in, structured JSON out.

The other direction. Tables come back with their headers, row and column counts and per-cell values; labelled fields come back with the raw string they were read from. Every value carries a page number, a bounding box and a confidence score — which is what lets you build a review queue instead of trusting the output blind. No OCR, no model call, no per-page pricing surprise. It is geometry.

Endpoints
POST /v1/extract
POST /v1/extract/async
GET /v1/extractions/:id
Billed perone page read
Starts atSame quota as rendering

Try it on a PDF · Docs

Accessibility — A document estate, triaged.

Point it at a domain. It finds every PDF, checks each against PDF/UA and WCAG 2.1 AA, and returns a report ranked by severity weighted by reach, with a remediation cost range. Half of what it checks is not machine-checkable by a conformance validator: whether the reading order stored in the file matches the page, whether a tagged table is really a grid, whether alt text describes anything or is just a filename.

Endpoints
POST /v1/a11y/scan
GET /v1/a11y/scans/:id
GET /r/:token
Billed perone document checked
Starts atFree for 25 documents

Check a PDF now · Docs

Two subscriptions, not one

Rendering and extraction share a quota, because they share a unit — a render and a page read are both one unit of Chromium doing work. Accessibility does not fit that unit at all: it is priced per document checked, and a scan of five thousand documents has nothing to do with how many invoices you generated this month.

So they are separate subscriptions. An account can hold a render plan, an accessibility plan, both, or neither — and the free tier of each is real rather than a trial. Rendering starts at $9/month once you pass the free allowance; accessibility starts at $49 once.

Full pricing, including the billing rule that decides which failed requests are chargeable.

Why the accessibility one exists

We scanned 15 PDFs published by US federal agencies on 2026-09-27. All 15 failed conformance — including the published text of the ADA Title II rule itself. Nobody’s portfolio is clean, which means “does this conform?” is the wrong first question. Every large portfolio answers no.

The question that gets a remediation budget approved is which of your five thousand documents to fix on Monday — and that needs failures ranked by consequence and priced, not listed. See the full scan, with sources.

One client, all three

The official TypeScript, Python and Go clients cover every endpoint on this page. Each has no dependencies of its own and is generated against the same contract the API validates requests with, so their types cannot drift from the server.

import { Renderer } from '@pdfcraft-dev/pdf';

const client = new Renderer({ apiKey: process.env.PDFCRAFT_API_KEY });

// 1. HTML in, PDF out
const pdf = await client.render({ html: '<h1>Invoice 1042</h1>' });

// 2. PDF in, structured JSON out
const data = await client.extractPdf(pdf, { options: { tables: true } });

// 3. A whole domain, triaged
let scan = await client.scan({ source: { domain: 'example.gov' } });
while (scan.status !== 'succeeded' && scan.status !== 'failed') {
  await new Promise((r) => setTimeout(r, 10_000));
  scan = await client.getScan(scan.id);
}
console.log(scan.documents?.slice(0, 10)); // the ten to fix first

All three clients, plus worked HTTP examples for nine more languages. If yours is not one of them, it is one POST endpoint — curl is a supported client.

Start without an account

The playground renders and extracts with no key at all, and the accessibility checker checks a single document the same way. When you want your own key, create an account — email only, no password to choose.