Invoice PDFs

Every order in Distribu can be downloaded as a PDF invoice — US Letter size, single page, generated on demand. No setup, no third-party invoicing tool, nothing to configure. If you've placed an order, you can grab its invoice.

Getting an invoice

From the dashboard

On any order detail page (/dashboard/orders/{id}), click the Download Invoice button in the top-right. You'll get a file named:

invoice-A1B2C3D4.pdf

…where A1B2C3D4 is the last 8 characters of the order's ID, uppercased — matching the short ID shown in the UI.

Direct URL: /dashboard/orders/{id}/invoice. It's a GET endpoint — safe to bookmark, share with staff, or paste into a PDF viewer.

From the storefront

Customers can download their own invoices at /store/{slug}/orders/{id}/invoice. The order detail page on the storefront has a matching button. Invoice access is gated to the logged-in customer — the endpoint returns 404 if the order doesn't belong to them.

Via the REST API

There's no REST API endpoint for the invoice PDF right now. If you need programmatic access, hit the dashboard endpoint with a session cookie — the auth is standard staff auth.

What's on the invoice

The layout is deliberately compact and readable — nothing fancy, just the information you (and your customer) need:

┌────────────────────────────────────────────────────────────────────┐
│  Your Company                                         INVOICE      │
│  ───────────────────────────────────────────────────────────────  │
│                                                                    │
│  BILL TO                              Invoice #   INV-A1B2C3D4     │
│  Acme Restaurant                      Date        April 16, 2026   │
│  billing@acme.com                     PO #        PO-12345         │
│                                                                    │
│  SHIP TO                                                           │
│  123 Main Street                                                   │
│  Brooklyn, NY 11201                                                │
│  United States                                                     │
│                                                                    │
│  ┌──────────────────────────────────────────────────────────────┐ │
│  │ Product          SKU         Unit Price    Qty    Subtotal   │ │
│  ├──────────────────────────────────────────────────────────────┤ │
│  │ Widget Blue      WDG-001     $8.50/each    10     $85.00     │ │
│  │ Widget Red       WDG-002     $9.25/each    5      $46.25     │ │
│  └──────────────────────────────────────────────────────────────┘ │
│                                                                    │
│  ┌──────────────────────────────────────────────────────────────┐ │
│  │                                         TOTAL      $131.25   │ │
│  └──────────────────────────────────────────────────────────────┘ │
│                                                                    │
│  Notes                                                             │
│  Deliver before noon on Thursday.                                  │
│                                                                    │
│               Generated by Distribu · Order clxx...                │
└────────────────────────────────────────────────────────────────────┘

Header

  • Your company name — pulled from Company.name, what you set in Settings → Company.
  • "INVOICE" label in blue.
  • A thin accent bar in the brand blue.

Meta (right side)

  • Invoice # — format INV-{last 8 chars of order id, uppercase}. Same thing as the filename suffix. Stable — an order's invoice number doesn't change over time.
  • Date — the order's creation date, formatted like "April 16, 2026".
  • PO # — only shown if the order has a poNumber. Otherwise omitted.

Bill to

Pulled from the linked customer row:

  • Customer name (falls back to email if no name is set).
  • Customer email underneath, in gray.

Dashboard-created orders (which have no customerId) don't show a Bill To block — that section is simply omitted.

Ship to

Pulled from the frozen snapshot on the order, not the live address. This is intentional: if a customer later edits their address or deletes it, the invoice still reflects where the order was actually shipped.

Storefront orders always have a shipping address — the cart requires picking one. Dashboard and API orders may or may not have one; the Ship To section is omitted if the order has no snapshot.

Line items table

One row per line item with:

  • Product name — truncated with ... if it doesn't fit.
  • SKU — or if the product has no SKU.
  • Unit price — formatted $X.XX/unit (e.g. $8.50/each).
  • Quantity.
  • SubtotalunitPrice × quantity, right-aligned.

Alternating rows have a light background for readability.

If an order has more line items than fit on one page (roughly 20+ depending on product name length), the overflow rows are dropped — the PDF is single-page today, no multi-page pagination. For orders that large, grab the data via the REST API instead.

Total row

A blue band at the bottom of the items table with TOTAL label and the order total, bold white text.

Notes

If the order has a notes field, it's rendered below the total, word-wrapped to fit the page. Up to 6 lines — anything beyond that is dropped.

Footer

A small gray line at the bottom with Generated by Distribu · Order {full id}.

What's NOT on the invoice

  • Tax — Distribu doesn't calculate tax. If you need tax lines, they have to live in the notes field today or be handled in your accounting system.
  • Shipping — no separate shipping line. Same workaround via notes.
  • Payment terms — same (Net 30, Due on receipt, etc.). Add them to the notes field on the order, or put them in your customer's account notes.
  • Your address or contact info — the invoice shows your company name but not a physical address, phone, or logo. A richer letterhead is on the roadmap; if you need to emboss something, most PDF viewers let you overlay or export to an external template.
  • Payment status — invoices show the order total as a single line. There's no "Balance due" / "Paid" concept in Distribu right now.

Caching

The invoice endpoint returns Cache-Control: no-store. Every download regenerates fresh, which means:

  • Always the latest data. If you update an order's notes or PO number (via the API), the next PDF download reflects it.
  • No stale invoices. Some PDF viewers cache aggressively — if you're surprised by an out-of-date invoice, clear your browser/viewer cache or append a cache-buster query param.

Audit

Downloading an invoice does not write an audit log entry right now. If you need to see who downloaded what and when, email us — we can pull it from our server access logs.


Next: Exporting orders.