Skip to main content

Templates

Design invoices, receipts, labels and certificates once in the dashboard, then create PDFs by sending JSON.

  • Build or customise a template under Templates in the dashboard. The library has 32 starters: invoices, quotes, purchase orders, receipts, bills and statements, payslips and HR letters, shipping and address labels, QR codes, product and asset labels, badges and ID cards, event tickets and vouchers, menus, certificates, letters and envelopes.
  • Each template has fields. A field's key is the JSON property you send, for example invoice_number or customer.name.
  • Render with POST /templates/{template_id}/render. Each successful render is charged as one PDF, the same as /quickjob.
Create the template first

This endpoint renders a template that already exists in your account. It doesn't take a design in the request. Before you call it:

  1. In the dashboard, open Templates and pick a starter from the Template library, click New blank template, or click New HTML template (beta) to write the template in your own HTML.
  2. Adjust the design and fields, then Save.
  3. Copy the template's ID. It appears on the template's card in My templates (with a copy button), in Use via API, and in the editor's address bar (/templates/<template_id>/edit).

Calling render with an ID that doesn't exist in your account returns 404 TEMPLATE_NOT_FOUND. Editing a saved template changes the output of later calls; the ID stays the same. Deleting it makes those calls fail.

Quick Example​

Replace YOUR_TEMPLATE_ID with your template's ID and send values for its fields:

curl -X POST https://api.podpdf.com/templates/YOUR_TEMPLATE_ID/render \
-H "X-API-Key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"data": {
"invoice_number": "INV-1042",
"issue_date": "2026-09-13",
"customer": { "name": "Acme Ltd", "address": "1 Main St\nSpringfield" },
"items": [
{ "description": "Design work", "quantity": 10, "unit_price": 85 },
{ "description": "Hosting", "quantity": 1, "unit_price": 20 }
],
"tax_rate": 20
}
}' \
--output INV-1042.pdf

The totals, currency formatting, page numbers and table headers on every page all come from the template, so you only send the values.

Copy the request from the dashboard

Open a template and click Use via API. It shows the endpoint for that template and an example body with every field, in cURL, JavaScript and Python.

Authentication​

Required. Send an API key or a dashboard ID token:

X-API-Key: your_api_key_here

Learn about authentication →

Request​

Endpoint​

POST https://api.podpdf.com/templates/{template_id}/render

Body​

FieldTypeRequiredDescription
dataobjectYesValues for the template's fields. Nested keys such as customer.name are nested objects. List fields are arrays of objects. Extra keys are ignored. Up to 1 MB.
storebooleanNotrue stores the PDF and returns a download link (valid for 1 hour) instead of the file
filenamestringNoFile name for the Content-Disposition header

Value formats​

Field typeSendExample
Text, Multi-line textstring (numbers are accepted)"Acme Ltd", "Line 1\nLine 2"
Numbernumber or numeric string12.5
Money amountnumber, in the template currency1234.56 → $1,234.56 or 1.234,56 €
Percentagenumber, where 20 means 20%20
DateISO date"2026-09-13"
Image URLpublic https:// URL (PNG or JPEG, up to 2 MB) or data:image/…;base64,…"https://cdn.example.com/logo.png"
Listarray of objects[{ "description": "Design", "quantity": 2 }]

Response​

Success (default)​

200 OK with the PDF as the body.

HeaderDescription
Content-Typeapplication/pdf
X-Job-IdJob ID, visible in GET /jobs
X-PDF-PagesNumber of pages

Success with store: true​

{
"job_id": "3f5c2a7e-8b1d-4c9e-a2f4-6d7e8f9a0b1c",
"template_id": "01J8ZK3QW5V7N2B4X6C8D0E2F4",
"pages": 2,
"truncated": false,
"download_url": "https://…",
"download_url_expires_at": "2026-09-13T13:00:00.000Z"
}

Invalid data​

Every problem is listed so you can fix them all at once. Nothing is charged.

{
"error": {
"code": "TEMPLATE_DATA_INVALID",
"message": "The data does not match the template fields",
"details": {
"errors": [
{ "field": "invoice_number", "error": "is required" },
{ "field": "items[1].quantity", "error": "must be a number" },
{ "field": "customer.logo_url", "error": "must be an https URL or a base64 data:image URI" }
]
}
}
}

Other errors​

StatusCodeMeaning
400TEMPLATE_DATA_TOO_LARGEdata is over 1 MB
400PAGE_LIMIT_EXCEEDEDThe document has more pages than your limit
401UNAUTHORIZEDMissing or invalid API key
403INSUFFICIENT_CREDITS, RATE_LIMIT_EXCEEDEDSame as /quickjob
404TEMPLATE_NOT_FOUNDWrong ID, or the template belongs to another account
408QUICKJOB_TIMEOUTRendering took longer than 30 seconds

See Error handling for retries.

HTML templates (beta)​

A template written in your own HTML renders through this same endpoint, with the same request, response, errors and price. Two things differ:

  • 400 TEMPLATE_DATA_INVALID is also returned when the data makes the template repeat more than 50,000 rows in total, or produce a document larger than 12 MB.
  • Totals are not calculated: send every value the template prints.

GET /templates and GET /templates/{template_id} return kind: "html" for these templates and "blocks" for visual ones. See the guide for the tags.

Page sizes​

Page size, orientation and margins are part of the template, so the same JSON always produces the same layout.

PresetSize
A3, A4, A5ISO sizes
US Letter, US Legal8.5 × 11 in, 8.5 × 14 in
Receipt 80 mm, Receipt 58 mmThermal roll widths; the length follows the content
Shipping label 4 × 6 in101.6 × 152.4 mm
CustomAny width 25–1200 mm and height 25–2000 mm, or automatic length

Managing templates from code​

The dashboard is the usual way to create and edit templates. The management routes need a dashboard ID token rather than an API key:

MethodPathPurpose
GET/templatesList your templates
GET/templates/{template_id}Get a template and its definition (including fields)
POST/templatesCreate from a definition or from a starter ({ "from_starter": "invoice-a4" })
PUT/templates/{template_id}Replace the definition (expected_version prevents overwriting someone else's edit). A template keeps its kind: a visual template cannot be replaced by an HTML one, or the other way round.
DELETE/templates/{template_id}Delete
GET/templates/libraryList starters