API Reference — Overview
The Paperwright API is a JSON/HTTP API. This page covers the base URL, authentication, errors, and — most importantly — how the API is versioned and which endpoints are safe to build on today.
Source of truth: the public OpenAPI document at
https://api.paperwright.dev/openapi/v1.json(OpenAPI 3.1.1). Every endpoint below maps to an operation in that spec. Point any client generator at it to get a typed client.
Base URL
http://localhost:5110 # local development
https://api.paperwright.dev # production
In dev, an interactive Scalar UI is served at /scalar/v1.
Authentication
| Lane | Header | Scope |
|---|---|---|
| JWT (Bearer) | Authorization: Bearer <token> | All management endpoints (auth, templates, keys, workspaces, collaboration) |
| API key | X-Api-Key: <key> | Rendering only |
The render endpoints (POST /api/render, POST /api/templates/{id}/render)
are the only ones that accept both lanes. See
Authentication & Sessions.
Workspace scoping
Every resource belongs to a workspace. A request only ever sees its own
workspace's data. Cross-tenant access returns 404 Not Found (deliberately
not 403 — we don't reveal that a resource exists in another tenant).
Errors
| Status | Meaning |
|---|---|
200 | Success |
400 | Validation error (bad/missing body fields) |
401 | Missing or invalid credentials |
402 | Quota exceeded (e.g. AI generation limit on the free tier) |
403 | Authenticated, but not allowed (e.g. deleting another user's comment) |
404 | Not found, or not in your workspace |
409 | Conflict — a concurrent edit changed the resource (optimistic concurrency) |
500 | Server error (generic message; no internal detail is leaked) |
Versioning policy
How versions work
- v1 is the only version. The entire API is served under it, surfaced as the
public OpenAPI document
/openapi/v1.jsonand, in local development only, a Scalar UI at/scalar/v1. - The major version (
v1) is a contract. Within v1 we only make backwards-compatible changes: adding endpoints, adding optional request fields, or adding response fields. We will not remove a field, rename one, or change a status code within v1. - There is no v2, and no deprecation window is published yet. If a breaking change ever becomes necessary, it will ship under a new major version at a new path, and the change will be announced in the changelog before v1 is affected. Until then, nothing you build on v1 gets pulled out from under you.
- Individual endpoints additionally carry a stability label (below) so you know how settled an endpoint is within v1.
Stability labels
| Label | Meaning | Your expectation |
|---|---|---|
| 🟢 Stable | Shipped, verified, in production use. | Safe to build on. Backwards-compatible changes only. |
| 🟡 Beta | Functionally complete, recently shipped, may still gain fields. | Safe to use; pin to documented fields and expect additive changes. |
| 🟠 Experimental | Feature-flagged or v0; shape may change. | Prototype only. Do not depend on the response shape. |
Master endpoint index
Every endpoint in v1.json, grouped by domain, with its version and stability.
Authentication · 🟢 Stable · v1 → details
| Method | Path | Auth | Stability |
|---|---|---|---|
| POST | /api/auth/signup | Public | 🟢 Stable |
| POST | /api/auth/login | Public | 🟢 Stable |
| POST | /api/auth/verify-email | Public | 🟢 Stable |
| POST | /api/auth/resend-verification | Public | 🟢 Stable |
| POST | /api/auth/forgot-password | Public | 🟢 Stable |
| POST | /api/auth/reset-password | Public | 🟢 Stable |
| POST | /api/auth/refresh | Cookie/JWT | 🟢 Stable |
| POST | /api/auth/logout | JWT | 🟢 Stable |
| POST | /api/auth/logout-all | JWT | 🟢 Stable |
| POST | /api/auth/change-password | JWT | 🟢 Stable |
| GET | /api/auth/me | JWT | 🟢 Stable |
| POST | /api/auth/switch-workspace/{workspaceId} | JWT | 🟢 Stable |
| GET | /api/auth/oauth/{provider}/start | Public | 🟡 Beta |
| GET | /api/auth/oauth/{provider}/callback | Public | 🟡 Beta |
Templates · 🟢 Stable · v1 → details
| Method | Path | Auth | Stability |
|---|---|---|---|
| GET | /api/templates | JWT | 🟢 Stable |
| POST | /api/templates | JWT | 🟢 Stable |
| GET | /api/templates/{id} | JWT | 🟢 Stable |
| PUT | /api/templates/{id} | JWT | 🟢 Stable |
| DELETE | /api/templates/{id} | JWT | 🟢 Stable |
| POST | /api/templates/{id}/base-pdf | JWT | 🟢 Stable |
| GET | /api/templates/{id}/base-pdf | JWT | 🟢 Stable |
| DELETE | /api/templates/{id}/base-pdf | JWT | 🟢 Stable |
| GET | /api/templates/{id}/base-pdf/pages/{index} | JWT | 🟢 Stable |
Rendering · 🟢 Stable · v1 → details
| Method | Path | Auth | Stability |
|---|---|---|---|
| POST | /api/render | JWT or API key | 🟢 Stable |
| POST | /api/templates/{id}/render | JWT or API key | 🟢 Stable |
API Keys · 🟢 Stable · v1 → details
| Method | Path | Auth | Stability |
|---|---|---|---|
| GET | /api/api-keys | JWT | 🟢 Stable |
| POST | /api/api-keys | JWT | 🟢 Stable |
| DELETE | /api/api-keys/{id} | JWT | 🟢 Stable |
| GET | /api/usage | JWT | 🟢 Stable |
Workspaces & Invites · 🟢 Stable · v1 → details
| Method | Path | Auth | Stability |
|---|---|---|---|
| GET | /api/workspaces | JWT | 🟢 Stable |
| GET | /api/workspaces/current/members | JWT | 🟢 Stable |
| POST | /api/workspaces/current/invites | JWT (Owner) | 🟢 Stable |
| DELETE | /api/workspaces/current/members/{userId} | JWT (Owner) | 🟢 Stable |
| PATCH | /api/workspaces/current/members/{userId} | JWT (Owner) | 🟢 Stable |
| GET | /api/invites/{token} | Public | 🟢 Stable |
| POST | /api/invites/{token}/accept | JWT | 🟢 Stable |
Collaboration: Presence & Comments · 🟡 Beta · v1 → details
| Method | Path | Auth | Stability |
|---|---|---|---|
| POST | /api/presence | JWT | 🟡 Beta |
| GET | /api/presence/{resourceType}/{resourceId} | JWT | 🟡 Beta |
| DELETE | /api/presence/{resourceType}/{resourceId} | JWT | 🟡 Beta |
| GET | /api/templates/{templateId}/comments | JWT | 🟡 Beta |
| POST | /api/templates/{templateId}/comments | JWT | 🟡 Beta |
| DELETE | /api/templates/{templateId}/comments/{commentId} | JWT | 🟡 Beta |
AI · 🟠 Experimental · v1 (v0 feature) → details
| Method | Path | Auth | Stability |
|---|---|---|---|
| POST | /api/ai/generate-template | JWT | 🟠 Experimental |
Batch Render · 🟡 Beta · v1 → details
| Method | Path | Auth | Stability |
|---|---|---|---|
| POST | /api/templates/{id}/render-batch | JWT or API key | 🟡 Beta |
| POST | /api/templates/{id}/render-batch/upload | JWT or API key | 🟡 Beta |
| GET | /api/templates/{id}/render-batch/jobs/{jobId} | JWT or API key | 🟡 Beta |
| GET | /api/templates/{id}/render-batch/jobs | JWT or API key | 🟡 Beta |
| GET | /api/templates/{id}/render-batch/jobs/{jobId}/result | JWT or API key | 🟡 Beta |
Service
| Method | Path | Auth | Stability |
|---|---|---|---|
| GET | /health | Public | 🟢 Stable |
Conventions used in these docs
- UUIDs — path IDs (
{id},{workspaceId},{userId}, etc.) are UUIDs unless noted ({token}is an opaque string;{index}is an integer). - Request bodies are
application/jsonunless noted (base-PDF upload ismultipart/form-data). - Schema names (e.g.
LoginBody,CreateTemplateBody) match the components in the publicopenapi/v1.json.
The spec documents request bodies in full but currently describes responses only
as 200 OK, and does not yet carry per-operation summaries or security schemes.
The response examples in these pages are illustrative of the intended shape
and will be pinned to the spec as response schemas are added.