Skip to main content

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​

LaneHeaderWhoUse it for
JWTAuthorization: Bearer <token>Humans / admin sessionsSign-up, login, managing templates & API keys, workspace admin
API keyX-Api-Key: <key>Machines / your backendRendering 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 name and HTML-ish content with {{token}} placeholders.
  • At render time you pass a data JSON 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​