PDFCraft
Deno

HTML to PDF in Deno

One POST, a PDF back. No headless browser to install, no Chromium to keep patched, no fonts to install on the box — the render happens on a warm browser that is already running.

Render HTML to a PDF

const response = await fetch('https://api.pdfcraft.dev/v1/render', {
  method: 'POST',
  headers: {
    authorization: `Bearer ${Deno.env.get('PDFCRAFT_API_KEY')}`,
    'content-type': 'application/json',
  },
  body: JSON.stringify({ html: '<h1>Invoice 1042</h1>' }),
});

if (!response.ok) throw new Error((await response.json()).error.code);

await Deno.writeFile('invoice.pdf', new Uint8Array(await response.arrayBuffer()));

Read a PDF back as JSON

The same key works for extraction. Send a PDF, name the fields you want by the label printed on the page, and get them back with the raw text, a coerced value, a confidence and a bounding box.

const pdf = await Deno.readFile('statement.pdf');

const response = await fetch('https://api.pdfcraft.dev/v1/extract', {
  method: 'POST',
  headers: {
    authorization: `Bearer ${Deno.env.get('PDFCRAFT_API_KEY')}`,
    'content-type': 'application/json',
  },
  body: JSON.stringify({
    file: encodeBase64(pdf),
    schema: { closing_balance: 'currency' },
  }),
});

const { fields } = await response.json();

What bites in Deno

Errors are one shape

Every failure is {"error":{"code","message","docs_url"}} with a stable code, so you can switch on error.code rather than parsing prose. The two worth handling explicitly are rate_limited — honour Retry-After — and render_failed, which means your HTML broke rather than ours did.

The same thing in another language

Or try it with no code at all in the playground. A free key is 100 renders a month.