Docs
Three ways in: a 30-second quickstart, the live REST reference, or the typed TypeScript SDK.
Quickstart
Get an API key from app.paperjet.dev, then render your first PDF.
-
1. Render a PDF with curl
curl -X POST https://api.paperjet.dev/v1/render \ -H "Authorization: Bearer $PAPERJET_API_KEY" \ -H "Content-Type: application/json" \ -o hello.pdf \ -d '{"source":"= Hello #data.name","data":{"name":"World"}}' # 200 OK · application/pdf · 11 KB · 75 ms. -
2. Inject JSON data into Typst
Whatever you pass under
datashows up inside the template as a top-level Typst binding calleddata. It's a real Typst dictionary — use.foodot access, arrays with.at(0), branching withif, mapping with.map().// source field of the request body, or stored as a template: = Hello #data.user.name // loops + branching are real: #for item in data.cart [ - #item.title (#item.qty × #item.price €) ] -
3. Reuse a template across calls
Stable templates live in your account's R2 bucket. Reference them by id; send fresh data on every request.
# 1. Upload the template once npx wrangler r2 object put paperjet-templates/templates/invoice-v1/main.typ \ --file ./invoice-v1.typ --remote # 2. Render against it as often as you want curl -X POST https://api.paperjet.dev/v1/render \ -H "Authorization: Bearer $KEY" \ -d '{"template_id":"invoice-v1","data":{...}}' -
4. Make retries safe
Pass
Idempotency-Keyon POSTs. A retry within 24 h with the same key + same body replays the cached PDF — no double render, no double bill.curl -X POST https://api.paperjet.dev/v1/render \ -H "Authorization: Bearer $KEY" \ -H "Idempotency-Key: order-12345" \ -d '{"template_id":"invoice-v1","data":{...}}'
TypeScript SDK
@paperjet/sdk wraps fetch with
auth, structured errors, and typed responses. Works in Node 20+, Bun, Deno, and
Cloudflare Workers.
// npm install @paperjet/sdk (or bun add, pnpm add, …)
import { Paperjet, PaperjetError } from "@paperjet/sdk";
const pj = new Paperjet({ apiKey: process.env.PAPERJET_API_KEY! });
try {
const pdf = await pj.render(
{ template_id: "invoice-v1", data: invoice },
{ idempotencyKey: `order-$+invoice.id`} },
);
await Bun.write("out.pdf", pdf);
} catch (err) {
if (err instanceof PaperjetError) {
console.error(err.code, err.message, err.requestId);
}
}
The full method surface — pj.renders.list,
pj.templates.list,
pj.keys — is in the
SDK README
and the REST reference.
Looking for something specific?
The interactive API reference covers every endpoint, request/response shape, and error code.
Open the REST reference →