Template API
The Template API provides REST endpoints for managing reusable PDF templates from internal tools, CI workflows, or AI coding agents without opening the Dashboard Template Designer.
Base URL
Send Template API requests to:
https://api.pdfbolt.com/v1/templates
Authentication
Except for public GET and HEAD requests to /v1/templates/contract, Template API requests require a Personal Access Token. Create one in the Personal Access Tokens section of the API Credentials page in the Dashboard.
Send the token in the PERSONAL-ACCESS-TOKEN header with every protected request:
PERSONAL-ACCESS-TOKEN: <YOUR_PERSONAL_ACCESS_TOKEN>
Store tokens in an environment variable or secret manager. Never expose them in client-side code, logs, or source control.
Each Personal Access Token belongs to the user who created it, not to a team. Requests authenticate as that user and can access every template available to the user in the Dashboard. In a shared team, this may include templates created by other team members.
Personal Access Tokens cannot be restricted to specific templates or operations and do not expire automatically. You can have up to five tokens, including deactivated tokens. Deactivation takes effect immediately and cannot be undone in the Dashboard.
How the Template API Works
Use this workflow to create and publish a template, then generate PDFs through the Conversion API:
- Retrieve the contract. Call
GET /v1/templates/contractto get the current template rules and supported fields. - Prepare the template. Create a complete HTML document with any Handlebars placeholders and Base64-encode it.
- Validate the template. Check the payload and template syntax without rendering a PDF.
- Preview and review. Render the template as a PDF and visually inspect every page. Revise and repeat until it is ready.
- Save the draft. Store the reviewed template without changing the published version used by the Conversion API.
- Verify the draft. Retrieve the template and confirm that the intended values were saved.
- Publish the draft. Make it the version used by the Conversion API.
- Generate PDFs. Send the
templateIdand document-specifictemplateDatato the Conversion API.
Endpoints Overview
The Template API provides the following endpoints:
| Method | Endpoint | Purpose |
|---|---|---|
GET | /v1/templates/contract | Retrieve the versioned Template Contract. |
HEAD | /v1/templates/contract | Check the public Template Contract endpoint without returning a response body. |
GET | /v1/templates | List the current team's templates. |
GET | /v1/templates/{templateId} | Retrieve template details, including content, sample data, and PDF parameters. |
POST | /v1/templates/validate | Validate a template payload without rendering a PDF. |
POST | /v1/templates/preview | Render a template preview and return a raw PDF or JSON response. |
POST | /v1/templates/{templateId}/diff | Compare proposed template changes with the published version. |
POST | /v1/templates/drafts | Create or update a template draft. |
POST | /v1/templates/{templateId}/publish | Publish the active draft. |
Request Fields
Template API request bodies use the fields below. Each endpoint accepts a different subset. See the endpoint reference for the exact request shape.
| Field | Type | Description |
|---|---|---|
templateId | string (UUID) | Existing template UUID used for draft updates. Omit it to create a template. |
name | string | Non-blank template name. Required for creation. Maximum length: 100 characters. |
description | string | Optional template description. Maximum length: 500 characters. |
templateEngine | string | Template engine. Currently only HANDLEBARS is supported. |
content | string | Complete Base64-encoded UTF-8 HTML document, including CSS and any Handlebars placeholders. When supplied in an update, it replaces the stored document. Maximum decoded size: 2 MB. |
sampleData | object | Representative JSON data used to evaluate the template. When supplied in an update, it replaces the stored object. Maximum JSON size: 2 MB. |
parameters | object | PDF parameters used to validate, render, or save a template. Draft updates apply supplied fields as a shallow patch. Maximum JSON size: 2 MB. |
comment | string | Optional publish comment. Maximum length: 500 characters. |
Template Parameters
The parameters object contains the PDF parameters saved with a template version. When creating a new template, you can omit parameters, send an empty object ({}), or provide only selected fields. PDFBolt fills in the missing fields using the defaults shown below and saves the resulting parameters with the template version.
When generating PDFs from the published template, the saved parameters are applied automatically. To change them for a specific PDF, send conversion parameters alongside templateId and templateData. They override the saved parameters for that request only and are not saved to the template.
Use the same fields when validating, previewing, comparing, or saving a template:
| Field | Type | Accepted values | New template default |
|---|---|---|---|
format | string | Letter, Legal, Tabloid, Ledger, A0–A6 | Letter |
landscape | boolean | true or false | false |
waitUntil | string | load, domcontentloaded, networkidle, or commit | load |
printBackground | boolean | true or false | true |
displayHeaderFooter | boolean | true or false | false |
headerTemplate | string | null | Base64-encoded HTML | Not set |
footerTemplate | string | null | Base64-encoded HTML | Not set |
waitForFunction | string | null | JavaScript function | See the default below |
Only these eight parameters can be saved with a template version. Other Conversion API parameters can be sent when generating a PDF, but they apply only to that conversion.
waitForFunctionWhen waitForFunction is omitted during template creation, PDFBolt saves this function:
// wait for all fonts and images to be loaded, if loading fails, try waitUntil networkidle
() => { return document.readyState === 'complete' && document.fonts.status === 'loaded' && Array.from(document.images).every(img => img.complete); }
Endpoint Reference
Get Template Contract
Returns the current version of the Template Contract for programmatic template management. It covers authentication, payload fields, HTML/CSS and Handlebars guidance, defaults, workflows, limits, and technical errors. No authentication is required for GET or HEAD. Use HEAD to check the endpoint status and response headers without returning a response body.
Methods: GET, HEAD
https://api.pdfbolt.com/v1/templates/contract
Success Example
- cURL
- Response
curl 'https://api.pdfbolt.com/v1/templates/contract'
HTTP/1.1 200 OK
Content-Type: application/json
For GET, the response body contains the complete Template Contract for the current version. Use this endpoint to retrieve the latest Template Contract instead of copying its rules into your integration.
Template Contract and OpenAPI
GET /v1/templates/contract provides PDFBolt-specific rules for creating, rendering, reviewing, and publishing templates.
OpenAPI YAML defines the exact endpoints, required fields, response schemas, and status codes. Use both when building a Template API integration.
List Templates
Returns the current team's templates with published and draft version details, excluding deleted templates. Results are ordered by the latest version update, newest first, and are not paginated.
Method: GET
https://api.pdfbolt.com/v1/templates
Success Example
- cURL
- Response
curl 'https://api.pdfbolt.com/v1/templates' \
-H 'PERSONAL-ACCESS-TOKEN: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'
{
"templates": [
{
"id": "8f37b879-46cb-44fc-a5af-c223f5080771",
"name": "Quarterly Report",
"description": "Quarterly performance report",
"templateEngine": "HANDLEBARS",
"hasDraft": true,
"publishedVersion": null,
"draftVersion": {
"id": 383,
"status": "DRAFT",
"versionNumber": 1,
"createdTime": "2026-06-21T09:14:22Z",
"modifiedTime": "2026-06-21T09:18:07Z"
}
},
{
"id": "2b1124e7-7f8d-4fd9-9d0a-4f8cf0c58f98",
"name": "Invoice",
"description": "Monthly invoice template",
"templateEngine": "HANDLEBARS",
"hasDraft": true,
"publishedVersion": {
"id": 381,
"status": "PUBLISHED",
"versionNumber": 3,
"createdTime": "2026-06-20T10:12:34Z",
"modifiedTime": "2026-06-20T10:12:34Z"
},
"draftVersion": {
"id": 382,
"status": "DRAFT",
"versionNumber": 4,
"createdTime": "2026-06-20T11:03:12Z",
"modifiedTime": "2026-06-20T11:08:41Z"
}
}
]
}
Get Template Details
Returns the template's content, sample data, PDF parameters, and metadata for its active draft and latest published version. If an active draft exists, the content, sample data, and PDF parameters come from it. Otherwise, they come from the latest published version.
Method: GET
https://api.pdfbolt.com/v1/templates/{templateId}
Success Example
- cURL
- Response
curl 'https://api.pdfbolt.com/v1/templates/2b1124e7-7f8d-4fd9-9d0a-4f8cf0c58f98' \
-H 'PERSONAL-ACCESS-TOKEN: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'
{
"id": "2b1124e7-7f8d-4fd9-9d0a-4f8cf0c58f98",
"name": "Invoice",
"description": "Monthly invoice template",
"templateEngine": "HANDLEBARS",
"hasDraft": true,
"content": "PCFET0NUWVBFIGh0bWw+PGh0bWw+PGJvZHk+PGgxPkludm9pY2Uge3tpbnZvaWNlTnVtYmVyfX08L2gxPjxwPnt7Y3VzdG9tZXJOYW1lfX08L3A+PC9ib2R5PjwvaHRtbD4=",
"sampleData": {
"invoiceNumber": "INV-1001",
"customerName": "Acme Inc."
},
"parameters": {
"format": "A4",
"landscape": false,
"waitUntil": "load",
"footerTemplate": "PGRpdj48c3BhbiBjbGFzcz0icGFnZU51bWJlciI+PC9zcGFuPjwvZGl2Pg==",
"headerTemplate": "PGRpdj48L2Rpdj4=",
"printBackground": true,
"waitForFunction": "() => document.readyState === 'complete'",
"displayHeaderFooter": true
},
"publishedVersion": {
"id": 381,
"status": "PUBLISHED",
"versionNumber": 3,
"createdTime": "2026-06-20T10:12:34Z",
"modifiedTime": "2026-06-20T10:12:34Z"
},
"draftVersion": {
"id": 382,
"status": "DRAFT",
"versionNumber": 4,
"createdTime": "2026-06-20T11:03:12Z",
"modifiedTime": "2026-06-20T11:08:41Z"
}
}
Validate Template Payload
Validates a template payload without saving it or rendering a PDF. It checks required fields, Base64 content, payload size limits, the template engine, Handlebars syntax and evaluation, and supported PDF parameters. Use it before previewing or saving a draft.
A Handlebars placeholder does not need a matching value in sampleData to pass validation. If the value is missing, the placeholder produces no output.
Method: POST
https://api.pdfbolt.com/v1/templates/validate
- Required body fields:
templateEngine,content,sampleData,parameters - Optional body fields: None
Success Example
- Request
- cURL
- Response
{
"templateEngine": "HANDLEBARS",
"content": "PCFkb2N0eXBlIGh0bWw+PGh0bWw+PGJvZHk+PGgxPkludm9pY2Uge3tpbnZvaWNlTnVtYmVyfX08L2gxPjwvYm9keT48L2h0bWw+",
"sampleData": {"invoiceNumber": "INV-1001"},
"parameters": {
"format": "A4",
"waitUntil": "networkidle",
"printBackground": true
}
}
curl 'https://api.pdfbolt.com/v1/templates/validate' \
-H 'PERSONAL-ACCESS-TOKEN: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' \
-H 'Content-Type: application/json' \
-d '{
"templateEngine": "HANDLEBARS",
"content": "PCFkb2N0eXBlIGh0bWw+PGh0bWw+PGJvZHk+PGgxPkludm9pY2Uge3tpbnZvaWNlTnVtYmVyfX08L2gxPjwvYm9keT48L2h0bWw+",
"sampleData": {"invoiceNumber": "INV-1001"},
"parameters": {
"format": "A4",
"waitUntil": "networkidle",
"printBackground": true
}
}'
HTTP/1.1 200 OK
Preview Template Payload
Renders a template payload as a PDF without saving it. Use ?responseFormat=json to receive the PDF as Base64 with its size in MB. Each successful preview render counts toward your available document conversions.
Method: POST
https://api.pdfbolt.com/v1/templates/preview
- Required body fields:
templateEngine,content,sampleData,parameters - Optional body fields: None
responseFormat | Returns |
|---|---|
pdf (default) | PDF file (application/pdf) |
json | JSON with the PDF encoded as Base64 and its size in MB |
Success Example
- Request
- cURL
- Response
{
"templateEngine": "HANDLEBARS",
"content": "PCFkb2N0eXBlIGh0bWw+PGh0bWw+PGJvZHk+PGgxPkludm9pY2Uge3tpbnZvaWNlTnVtYmVyfX08L2gxPjwvYm9keT48L2h0bWw+",
"sampleData": {"invoiceNumber": "INV-1001"},
"parameters": {"format": "A4", "waitUntil": "networkidle", "printBackground": true}
}
PDF (default)
curl -D headers.txt 'https://api.pdfbolt.com/v1/templates/preview' \
-H 'PERSONAL-ACCESS-TOKEN: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' \
-H 'Content-Type: application/json' \
-d '{
"templateEngine": "HANDLEBARS",
"content": "PCFkb2N0eXBlIGh0bWw+PGh0bWw+PGJvZHk+PGgxPkludm9pY2Uge3tpbnZvaWNlTnVtYmVyfX08L2gxPjwvYm9keT48L2h0bWw+",
"sampleData": {"invoiceNumber": "INV-1001"},
"parameters": {"format": "A4", "waitUntil": "networkidle", "printBackground": true}
}' \
-o preview.pdf
JSON
To receive JSON instead, add ?responseFormat=json to the URL:
curl -D headers.txt 'https://api.pdfbolt.com/v1/templates/preview?responseFormat=json' \
-H 'PERSONAL-ACCESS-TOKEN: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' \
-H 'Content-Type: application/json' \
-d '{
"templateEngine": "HANDLEBARS",
"content": "PCFkb2N0eXBlIGh0bWw+PGh0bWw+PGJvZHk+PGgxPkludm9pY2Uge3tpbnZvaWNlTnVtYmVyfX08L2gxPjwvYm9keT48L2h0bWw+",
"sampleData": {"invoiceNumber": "INV-1001"},
"parameters": {"format": "A4", "waitUntil": "networkidle", "printBackground": true}
}'
PDF (default)
The response body contains raw PDF bytes:
HTTP/1.1 200 OK
Content-Type: application/pdf
JSON
HTTP/1.1 200 OK
Content-Type: application/json
{
"documentSizeMb": 0.08,
"pdfBase64": "JVBERi0xLjQK..."
}
The x-pdfbolt-conversion-cost response header reports the credits charged for either response format.
Compare Proposed Changes with the Published Version
The template must have a published version. The endpoint renders the published version as before and the supplied template payload as after for visual comparison without saving the changes.
Method: POST
https://api.pdfbolt.com/v1/templates/{templateId}/diff
- Required body fields:
content,sampleData,parameters - Optional body fields:
templateEngine
Success Example
- Request
- cURL
- Response
{
"content": "PCFkb2N0eXBlIGh0bWw+PGh0bWw+PGJvZHk+PGgxPkludm9pY2Uge3tpbnZvaWNlTnVtYmVyfX08L2gxPjxwPnt7Y3VzdG9tZXJOYW1lfX08L3A+PC9ib2R5PjwvaHRtbD4=",
"sampleData": {"invoiceNumber": "INV-1001", "customerName": "Acme Inc."},
"parameters": {"format": "A4", "waitUntil": "networkidle", "printBackground": true}
}
curl -D headers.txt 'https://api.pdfbolt.com/v1/templates/2b1124e7-7f8d-4fd9-9d0a-4f8cf0c58f98/diff' \
-H 'PERSONAL-ACCESS-TOKEN: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' \
-H 'Content-Type: application/json' \
-d '{
"content": "PCFkb2N0eXBlIGh0bWw+PGh0bWw+PGJvZHk+PGgxPkludm9pY2Uge3tpbnZvaWNlTnVtYmVyfX08L2gxPjxwPnt7Y3VzdG9tZXJOYW1lfX08L3A+PC9ib2R5PjwvaHRtbD4=",
"sampleData": {"invoiceNumber": "INV-1001", "customerName": "Acme Inc."},
"parameters": {"format": "A4", "waitUntil": "networkidle", "printBackground": true}
}'
{
"before": {
"documentSizeMb": 0.1,
"pdfBase64": "JVBERi0xLjQK...",
"error": null
},
"after": {
"documentSizeMb": 0.1,
"pdfBase64": "JVBERi0xLjQK...",
"error": null
}
}
The response remains HTTP 200 even if one or both renders fail, so check before.error and after.error. The x-pdfbolt-conversion-cost response header reports the credits charged for successful renders only. If both renders fail, its value is 0.
Create or Update a Template Draft
Creates a new template and its first draft when templateId is omitted, or saves changes to an existing template when templateId is provided. Every save validates the complete draft, including preserved fields, without rendering a PDF or consuming conversion credits.
Make one change at a time to a template. Wait for each save or publish request to finish before making another change through the Template API or Dashboard Template Designer. Concurrent changes, including changes made by another user, may overwrite one another.
Method: POST
https://api.pdfbolt.com/v1/templates/drafts
Create a New Template
Omit templateId to create a new template and its first draft. If you omit parameters or provide only some fields, PDFBolt fills in the rest using the template defaults.
An omitted or null description is saved as an empty string.
- Required body fields:
name,templateEngine,content,sampleData - Optional body fields:
description,parameters
- Request
- cURL
- Response
{
"name": "Invoice",
"description": "Monthly invoice template",
"templateEngine": "HANDLEBARS",
"content": "PCFkb2N0eXBlIGh0bWw+PGh0bWw+PGJvZHk+PGgxPkludm9pY2Uge3tpbnZvaWNlTnVtYmVyfX08L2gxPjwvYm9keT48L2h0bWw+",
"sampleData": {"invoiceNumber": "INV-1001"},
"parameters": {"format": "A4", "waitUntil": "networkidle", "printBackground": true}
}
curl 'https://api.pdfbolt.com/v1/templates/drafts' \
-H 'PERSONAL-ACCESS-TOKEN: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' \
-H 'Content-Type: application/json' \
-d '{
"name": "Invoice",
"description": "Monthly invoice template",
"templateEngine": "HANDLEBARS",
"content": "PCFkb2N0eXBlIGh0bWw+PGh0bWw+PGJvZHk+PGgxPkludm9pY2Uge3tpbnZvaWNlTnVtYmVyfX08L2gxPjwvYm9keT48L2h0bWw+",
"sampleData": {"invoiceNumber": "INV-1001"},
"parameters": {"format": "A4", "waitUntil": "networkidle", "printBackground": true}
}'
{
"templateId": "93fee603-cb2a-40db-8deb-b2e3cb1eed0f",
"draftVersionId": 2012,
"versionNumber": 1,
"createdTemplate": true
}
Update an Existing Template
Include templateId and at least one field to update. PDFBolt uses the active draft as the base, or the published version if no active draft exists:
- Omitted top-level fields (
name,description,templateEngine,content,sampleData, andparameters) preserve their current values. - Supplied
contentreplaces the complete HTML document. - Supplied
sampleDatareplaces the complete JSON object. It is not deep-merged. - The
parametersobject is applied as a shallow patch. Include only the fields you want to update. Omitted fields are preserved. An emptyparametersobject does not change any parameters and does not count as an update. - Within
parameters, setheaderTemplate,footerTemplate, orwaitForFunctiontonullto remove the saved value. To updateformat,landscape,waitUntil,printBackground, ordisplayHeaderFooter, provide a concrete value. description: ""clears the description.- Explicit
nullis rejected for every top-level update field.
PDFBolt updates an active draft in place, preserving its draftVersionId and versionNumber. If only a published version exists, it creates the next draft version from it.
- Required body fields:
templateIdand at least one field to update - Updatable fields:
name,description,templateEngine,content,sampleData,parameters
Partial updates are supported only when saving a draft for an existing template. Validate, preview, and diff still require complete template payloads.
- Request
- cURL
- Response
{
"templateId": "93fee603-cb2a-40db-8deb-b2e3cb1eed0f",
"parameters": {"landscape": true}
}
curl 'https://api.pdfbolt.com/v1/templates/drafts' \
-H 'PERSONAL-ACCESS-TOKEN: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' \
-H 'Content-Type: application/json' \
-d '{
"templateId": "93fee603-cb2a-40db-8deb-b2e3cb1eed0f",
"parameters": {"landscape": true}
}'
{
"templateId": "93fee603-cb2a-40db-8deb-b2e3cb1eed0f",
"draftVersionId": 2012,
"versionNumber": 1,
"createdTemplate": false
}
createdTemplate indicates whether the request created the template itself. It is false whenever templateId is provided.
Publish a Template Draft
Publishes the template's active draft.
A JSON object is required. Send {} to publish without a comment.
Method: POST
https://api.pdfbolt.com/v1/templates/{templateId}/publish
- Required body fields: None (a JSON body is still required and may be empty)
- Optional body fields:
comment(maximum 500 characters)
Success Example
- Request
- cURL
- Response
{
"comment": "Ready for production"
}
curl 'https://api.pdfbolt.com/v1/templates/93fee603-cb2a-40db-8deb-b2e3cb1eed0f/publish' \
-H 'PERSONAL-ACCESS-TOKEN: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' \
-H 'Content-Type: application/json' \
-d '{"comment": "Ready for production"}'
{
"templateId": "93fee603-cb2a-40db-8deb-b2e3cb1eed0f",
"publishedVersionId": 2012,
"versionNumber": 1
}
Publishing makes the active draft the new published version.
Generate PDFs from a Published Template
To generate PDFs, send the template's templateId and document-specific templateData to /v1/direct, /v1/sync, or /v1/async. Authenticate with an API-KEY.
The Conversion API always uses the latest published version, even if a newer draft exists. Add conversion parameters to override the saved template defaults for that request. The overrides are not saved to the template.
- Request
- cURL
- Response
{
"templateId": "93fee603-cb2a-40db-8deb-b2e3cb1eed0f",
"templateData": {
"invoiceNumber": "INV-1001",
"customerName": "Acme Inc."
}
}
curl 'https://api.pdfbolt.com/v1/direct' \
-H 'API-KEY: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' \
-H 'Content-Type: application/json' \
-d '{
"templateId": "93fee603-cb2a-40db-8deb-b2e3cb1eed0f",
"templateData": {
"invoiceNumber": "INV-1001",
"customerName": "Acme Inc."
}
}' \
--output invoice.pdf
A successful request returns 200 OK with raw PDF bytes:
HTTP/1.1 200 OK
Content-Type: application/pdf
x-pdfbolt-conversion-cost: 1
[binary PDF data]
The cURL example saves the response body as invoice.pdf.
See the OpenAPI YAML for the complete request schemas.
Billing and Rate Limits
Each successful preview render counts toward your available document conversions. For a diff, each successfully rendered side counts separately. These renders use the team's plan-based Conversion API limits and appear in Dashboard logs and usage as Preview Conversions. Other Template API operations do not count toward document conversions.
Listing, retrieving, validating, saving, and publishing templates use separate fixed per-user management limits. Their 429 responses include Retry-After. Preview and diff follow the Conversion API retry behavior. Public GET and HEAD requests to /v1/templates/contract are not rate limited.
See Rate Limits for current limits, response headers, and retry guidance.
Error Handling
Application-level Template API errors use the standard PDFBolt JSON response format:
{
"timestamp": "2026-07-13T12:00:00Z",
"httpErrorCode": 400,
"errorCode": "BAD_REQUEST",
"errorMessage": "Template validation failed: Field 'content' is required. Send a Base64-encoded UTF-8 HTML document as a string."
}
Read errorMessage for the specific cause. See Error Handling for shared error codes and retry guidance, and the OpenAPI YAML for the responses documented for each endpoint.
Request-level failures return non-2xx responses. Preview rendering failures also return non-2xx responses. Diff rendering failures are returned differently: after request validation succeeds, the endpoint returns HTTP 200 even if one or both renders fail. Check before.error and after.error before treating the comparison as successful.
Next Steps
📄️ PDF Templates
Learn template concepts and Handlebars syntax
📄️ Quick Start Guide
Generate PDFs from published templates
📄️ OpenAPI Reference
Browse endpoint schemas and responses
📄️ Error Handling
Handle API errors, retries, timeouts, and rate-limit responses