Skip to content

Recipe: invoice

Goal: your billing service generates a branded PDF invoice for every order, while the layout stays editable by anyone in the editor.

You’ll use: text boxes, a header band, a logo, required and optional variables, the export API.

  1. Create a template named Invoice. Its title becomes the PDF file name (Invoice.pdf).

  2. Header band — draw a rectangle across the top of the page (about 1920 × 180), fill it with your brand color, stroke width 0, then Send to back.

  3. Logo — click the image tool and upload your logo as PNG; move it onto the band.

  4. Title — a text box with INVOICE in Courier Prime or Anton, 64 px, white, on the band.

  5. Variables — create the following, inserting each one in a text box next to its label:

    Variable Required Default
    invoiceNumber ✅
    issueDate ✅
    customerName ✅
    customerAddress
    description ✅
    amount ✅
    vat 0.00
    total ✅
    paymentTerms Payment due within 30 days.
  6. Separators — thin rectangles (height 2) make clean lines between sections.

Click Imprime and fill in the form to check the result. Once it looks right, note the template ID from the URL.

Format every value in your code — Imprime inserts strings as they are.

invoice.ts
const IMPRIME_URL = 'https://app.imprime.io';
const INVOICE_TEMPLATE_ID = process.env.IMPRIME_INVOICE_TEMPLATE_ID!;
const eur = new Intl.NumberFormat('en-IE', { style: 'currency', currency: 'EUR' });
const date = new Intl.DateTimeFormat('en-GB', { dateStyle: 'long' });
export async function renderInvoice(order: Order): Promise<Buffer> {
const res = await fetch(`${IMPRIME_URL}/api/export/${INVOICE_TEMPLATE_ID}/pdf`, {
method: 'POST',
headers: {
'x-api-key': process.env.IMPRIME_API_KEY!,
'Content-Type': 'application/json',
},
body: JSON.stringify({
invoiceNumber: order.invoiceNumber,
issueDate: date.format(order.createdAt),
customerName: order.customer.name,
customerAddress: order.customer.address,
description: order.description,
amount: eur.format(order.amount),
vat: eur.format(order.vat),
total: eur.format(order.amount + order.vat),
}),
});
if (!res.ok) {
const { error } = await res.json();
throw new Error(`Invoice generation failed (${res.status}): ${error}`);
}
return Buffer.from(await res.arrayBuffer());
}

Then store the buffer (S3, database, disk) or attach it to the confirmation email.

When marketing wants a new color or legal wants an extra sentence, they edit the template in Imprime. Your code doesn’t change, as long as variable names stay the same.