Getting started — for developers
Everything in the Paperwright platform is backed by an HTTP API. This page gets you from zero to your first rendered PDF. For the full endpoint catalogue and the versioning policy, see the API Reference.
Base URL
https://api.paperwright.dev # production
http://localhost:5110 # local development
All paths below are relative to the base URL. The current API surface is v1 — see versioning.
Authentication: two lanes
| Lane | Header | Who | Use it for |
|---|---|---|---|
| JWT | Authorization: Bearer <token> | Humans / admin sessions | Sign-up, login, managing templates & API keys, workspace admin |
| API key | X-Api-Key: <key> | Machines / your backend | Rendering from server-side code |
The render endpoints are the only ones that accept both lanes. Everything else (template CRUD, workspaces, keys) is JWT-only. This keeps your production backend from ever holding a user credential.
1. Get a token
curl -X POST https://api.paperwright.dev/api/auth/login \
-H "Content-Type: application/json" \
-d '{ "email": "you@example.com", "password": "••••••••" }'
You'll get back a session JWT. Use it as Authorization: Bearer <token> for the
next calls.
2. Mint an API key (for machine rendering)
curl -X POST https://api.paperwright.dev/api/api-keys \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{ "name": "production-backend" }'
The key is shown once — store it as a secret. From now on your backend
renders with X-Api-Key and never needs a JWT.
3. Create a template
curl -X POST https://api.paperwright.dev/api/templates \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{
"name": "Invoice",
"content": "<h1>Invoice {{invoiceNumber}}</h1><p>Total: {{total}}</p>"
}'
The response includes the template's id (a UUID). Hold onto it.
4. Render it
Render a stored template with fresh data — this accepts either auth lane:
curl -X POST https://api.paperwright.dev/api/templates/<id>/render \
-H "X-Api-Key: <key>" \
-H "Content-Type: application/json" \
-d '{ "data": { "invoiceNumber": "INV-1024", "total": "$4,200.00" } }' \
--output invoice.pdf
Prefer not to store a template? Render inline in one shot:
curl -X POST https://api.paperwright.dev/api/render \
-H "X-Api-Key: <key>" \
-H "Content-Type: application/json" \
-d '{
"content": "<h1>Hello {{name}}</h1>",
"data": { "name": "World" }
}' \
--output hello.pdf
That's the whole loop: template + data → PDF.
The data model in one minute
- A Template has a
nameand HTML-ishcontentwith{{token}}placeholders. - At render time you pass a
dataJSON object; tokens resolve against it. - Special tokens (
{{$today}},{{$now}},{{$page}},{{$pages}}) resolve at render time. - Templates are workspace-scoped: a key or token only ever sees its own workspace's templates. Cross-tenant access returns 404 (never 403 — we don't confirm a resource exists across tenants).
The SDK
The first-party .NET SDK (Paperwright.Sdk, on NuGet) makes a render one typed call:
var client = new PaperwrightClient("YOUR_API_KEY");
byte[] pdf = await client.RenderTemplateAsync(templateId, new { invoiceNumber = "INV-1024", total = 4200.00m });
See the .NET SDK page. Any other language uses the HTTP API above.
What's next
- API Reference → Overview — base URL, auth, errors, and the versioning policy.
- Per-domain endpoint docs: Auth, Templates, Rendering, API Keys, Collaboration.
- Designer guides that matter when you render: Brand colours per tenant
(pass a
theme), Formatting values and Tables and repeating data.