Skip to main content

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

  1. In the dashboard, open Templates → Template library.
  2. 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.