Generate a PDF
Submit a generation job by POSTing a template ID and data payload. Generation is asynchronous — you receive a jobId to poll, or get a webhook when the PDF is ready.
Endpoint
POST
/v1/generate Requires an API key with the document:create scope. The template must have a published version. Request bodies are limited to 100 KB (larger bodies return 413).
Body parameters
| Field | Type | Required | Description |
|---|---|---|---|
templateId | string (UUID) | required | ID of the published template to render |
data | object | required | JSON data passed to Handlebars during rendering. Nested objects and arrays are supported. |
webhookUrl | string (URL) | optional | URL to POST a job.completed event to. Overrides the org default. If omitted, the org default webhook (if set) is used — there is no per-job opt-out, and an empty string is rejected with 400. |
orgId | string (UUID) | optional | Not needed — the API key fixes the organisation. If sent, it must match the key's organisation or the request fails with 403 ORG_MISMATCH. |
meta.filename | string | optional | Custom filename, max 200 characters; the .pdf extension is optional. Cannot contain / \ : * ? " < > |. Duplicates get a numeric suffix automatically. |
meta.retentionSeconds | integer | optional | Seconds to keep the file (1 to 31536000). Cannot exceed your plan maximum (422 RETENTION_LIMIT_EXCEEDED). Defaults to plan max. Common values: 300, 1800, 3600, 86400. |
Response
Returns 202 Accepted with only the jobId. Generation continues asynchronously — poll job status to track it.
Errors
| Status | Code | Cause |
|---|---|---|
400 | VALIDATION_ERROR | Body failed validation, or the template has payload validation on and data doesn't match its schema — see details (paths like data.items.0.qty). No credit is used |
403 | ORG_MISMATCH | orgId doesn't match the API key's organisation |
404 | NOT_FOUND | Template doesn't exist in your organisation |
413 | — | Request body larger than 100 KB |
422 | NO_PUBLISHED_VERSION | The template has never been published |
422 | TEMPLATE_DISABLED | The template is disabled |
422 | QUOTA_EXCEEDED | No credits left |
422 | DAILY_QUOTA_EXCEEDED | Your plan's daily PDF limit has been reached |
422 | RETENTION_LIMIT_EXCEEDED | meta.retentionSeconds is longer than your plan allows |
422 | TEMPLATE_SCHEMA_INVALID | Payload validation is on but the template's published JSON Schema is invalid |
503 | — | Maintenance mode — the body includes maintenanceWindow |
See Errors for the response shape and rate limits.
Use webhooks to avoid polling entirely — PDFox will POST to your endpoint when the PDF is ready.
Related guides
curl -X POST https://api.pdf-fox.com/v1/generate \
-H "Authorization: Bearer pdfs_a1b2c3d4_xxxx" \
-H "Content-Type: application/json" \
-d '{
"templateId": "a3f1d2e4-1111-4562-b3fc-2c963f66afa6",
"data": {
"customer": { "name": "Acme Ltd", "address": "123 High Street, London" },
"invoice": { "number": "INV-0042", "date": "2026-05-17", "total": 3200.00, "isPaid": true }
},
"meta": { "filename": "invoice-INV-0042", "retentionSeconds": 3600 }
}'HTTP/1.1 202 Accepted
{
"jobId": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
}