Invoices and receipts from JSON
This guide builds an invoice template in the dashboard and generates PDFs from your code.
1. Start from the library
- In the dashboard, open Templates → Template library.
- Pick Invoice (A4) or Invoice (US Letter) and click Use this template.
The builder opens with a live preview on the right:
- Blocks (left): add headings, text, details lists, addresses, item tables, totals, images, barcodes, signatures, columns and a footer. Drag blocks, or use the arrows, to reorder them.
- Page & style (left): paper size, orientation, margins, font, colours, language, currency and date format.
- Properties (right): edit the selected block. Any text box has an Insert field button (
{ }) that places a value from your JSON, such as{{customer.name}}.
2. Decide what your JSON contains
Click Fields & test data.
- Fields lists every value the template expects. The JSON key is the property name you send. Mark a field Required to have the API reject requests that leave it out.
- Test data fills in example values for the preview. The values are saved with the template and used as the example in Use via API.
A list field, such as items, becomes table rows. Its columns are defined under the field. A totals block adds up quantity × unit_price, applies discount and tax, and formats everything in the template currency.
3. Save and try it
Click Save, then Generate PDF to fill the form and download a PDF. This uses one credit.
4. Call the API
Click Use via API and copy the request. It already contains your template ID and every field.
const response = await fetch('https://api.podpdf.com/templates/01J8ZK3QW5V7N2B4X6C8D0E2F4/render', {
method: 'POST',
headers: { 'X-API-Key': process.env.PODPDF_API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({
data: {
invoice_number: order.number,
issue_date: order.date, // "2026-09-13"
customer: { name: order.customerName, address: order.address },
items: order.lines.map((line) => ({ description: line.name, quantity: line.qty, unit_price: line.price })),
tax_rate: 20,
},
}),
});
if (response.status === 400) {
const { error } = await response.json();
console.error(error.details.errors); // [{ field: 'items[0].quantity', error: 'must be a number' }]
} else {
const pdf = Buffer.from(await response.arrayBuffer());
}
Tips
- Receipts: choose Receipt 80 mm or Receipt 58 mm. The page grows with the number of items, so a single roll-paper page is always produced.
- Labels: the Shipping label 4 × 6 in starter includes Code 128 and QR codes generated from your tracking number.
- Long invoices: table headers repeat on every page, rows never split across pages, and the footer can show "Page 2 of 3".
- Logos: upload a PNG, JPEG or SVG (up to 1 MB) in an image block, or send an
https://image URL in your data. - Changing a template does not change its ID, so your integration keeps working. Use Duplicate to try a new layout without affecting live traffic.
See the Templates API reference for every option and error code.