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
http://localhost:5110 # local development
https://api.paperwright.io # production (planned — not yet live)
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 http://localhost:5110/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 http://localhost:5110/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 http://localhost:5110/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 http://localhost:5110/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 http://localhost:5110/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 (roadmap)
A first-party .NET SDK (Paperwright.Sdk) is planned so a render becomes a
single typed call instead of a hand-rolled HTTP request:
// Planned API — subject to change
var pdf = await paperwright.RenderAsync(templateId, new { invoiceNumber = "INV-1024", total = "$4,200.00" });
Until then, the HTTP API above is the integration surface.
What's next
- API Reference → Overview — base URL, auth, errors, and the versioning policy.
- Per-domain endpoint docs: Auth, Templates, Rendering, API Keys, Collaboration.