Invoice customization

Branding, fields, numbering, and footers.

View as MarkdownInstall skills

Customize how invoices look and what they say — logo, brand colors, custom fields, numbering schemes, and footers — so the documents your customers receive match your brand and satisfy the disclosure rules of your jurisdiction.

What you can customizeAsk

Customization lives in two places. Account-level branding applies to every invoice you issue; per-invoice fields override or extend that branding for a single document. Most teams set branding once and only reach for overrides when a specific customer or region needs something different.

LayerSet onExamples
Brandingaccount.brandingLogo, primary color, support email, default footer
Numberingaccount.invoice_settingsPrefix, sequence, per-customer vs. account-wide
Custom fieldsinvoice.custom_fieldsPO number, VAT ID, cost center
Footer & memoinvoice.footer, invoice.descriptionLegal notice, payment terms, free-text note

Branding renders on the hosted invoice page, the PDF, and email receipts alike. You set it once — there is no separate "PDF theme."

Set account brandingAsk

Branding is global state on your account. Update it from the dashboard or the API; changes apply to invoices finalized after the update (already-finalized invoices keep the branding they were locked with).

import { Vinr } from '@vinr/sdk';
const vinr = new Vinr({ secretKey: process.env.VINR_SECRET_KEY });

await vinr.account.updateBranding({
  logo: 'file_logo_9f2a',        // upload via vinr.files.create first
  primaryColor: '#1A1F36',       // buttons, accents, table header
  secondaryColor: '#F6F8FA',     // page background
  supportEmail: 'billing@acme.eu',
  defaultFooter: 'Acme Europe BV · VAT NL0000.00.000.B01 · Payment due within 14 days',
});

Prop

Type

Numbering schemesAsk

Every finalized invoice gets a human-readable number that is sequential, gap-free, and immutable once assigned — a hard requirement in most tax regimes. You control the prefix and the scope of the sequence.

One global counter. INV- then a zero-padded sequence: INV-000123, INV-000124.

await vinr.account.updateInvoiceSettings({
  numberPrefix: 'INV-',
  numberScope: 'account',   // single sequence across all customers
  numberPadding: 6,
});

Each customer carries its own counter, useful when buyers expect contiguous numbering on their own statements: ACME-0001, ACME-0002.

await vinr.account.updateInvoiceSettings({
  numberPrefix: 'ACME-',
  numberScope: 'customer',  // sequence resets per customer
  numberPadding: 4,
});

Numbers are assigned at finalization, not at draft creation, and cannot be changed afterward. Draft invoices show no number. Voiding an invoice does not reclaim its number — the gap is intentional and auditable. See Sending & voiding invoices.

Custom fields and footers per invoiceAsk

Per-invoice settings override the account defaults for one document. Set them on a draft before finalizing — typically the moment you need a buyer's PO number or a region-specific note.

const invoice = await vinr.invoices.update('inv_8Hq2', {
  customFields: [
    { name: 'Purchase order', value: 'PO-44915' },
    { name: 'Cost center',    value: 'EMEA-OPS' },
  ],
  footer: 'Reverse charge — VAT to be accounted for by the recipient.',
  description: 'Q2 platform subscription, seats 1–25.',
});                              // still a draft; "inv_..."

Custom fields render as a labelled table above the line items. You may set up to 4 fields per invoice; each name and value is capped at 30 and 140 characters respectively.

LocalizationAsk

Set locale on the customer (or per-invoice) to translate static labels — "Invoice", "Due", "Subtotal", "Tax" — and to format dates, currency symbols, and decimal separators. Your own text (footer, custom field values, line item descriptions) is rendered verbatim, so localize that content yourself.

await vinr.customers.update('cust_3Tg9', { locale: 'de-DE' });
// Renders "Rechnung", "Fällig", "1.000,00 €"

Resulting eventsAsk

Branding and numbering changes do not emit events on their own. Customization shows up when an invoice moves through its lifecycle:

  • invoice.finalized — fires once the number, branding, custom fields, and footer are locked onto the document.
  • invoice.updated — fires when you change custom fields, footer, or description on a draft.

Verify webhook deliveries before trusting them:

const event = vinr.webhooks.verify(payload, req.headers['x-vinr-signature']);
if (event.type === 'invoice.finalized') {
  // event.data.number is now assigned and immutable
}

Edge casesAsk

Next stepsAsk

Was this page helpful?
Edit on GitHub

Last updated on

On this page