Documentation

Invoicing

Invoice generation, PDF rendering, payment links, reminders, and refund processing for B2B and one-off bills.

The invoice module produces and tracks invoices — both auto-generated from orders and manually created for B2B billing, services, and project work. Each invoice has a PDF, a payment link, a status timeline, and an audit trail. Invoices are how the platform handles "I owe you money, here's how to pay" outside the cart-and-checkout flow.

Save and read

POST/storefront/invoices/saveJWT
GET/storefront/invoicesJWT
GET/storefront/invoices/:idJWT
GET/storefront/invoices/dashboard/metricsJWT

save creates or updates an invoice (upsert by ID). The body specifies line items, customer, dates, terms:

{
  "customerId": "cust-acme",
  "merchantCustomerId": "mc-acme",
  "issueDate": "2026-04-25",
  "dueDate": "2026-05-25",
  "currency": "USD",
  "terms": "NET-30",
  "lineItems": [
    { "description": "April consulting", "quantity": 40, "rate": 175, "amount": 7000 },
    { "description": "Cloud hosting", "quantity": 1, "rate": 295, "amount": 295 }
  ],
  "subtotal": 7295,
  "tax": 583.60,
  "total": 7878.60,
  "notes": "Thank you for your business."
}

The platform assigns an invoice number on save (sequential per org, per the configured pattern). The dashboard metrics endpoint returns outstanding receivables, average days-to-pay, top late accounts.

Send and reminders

POST/storefront/invoices/:id/sendJWT
POST/storefront/invoices/:id/reminderJWT

send emails the invoice to the customer with the PDF attached and a payment link. reminder sends a follow-up. Both go through the Broadcast module so delivery tracking, opens, and clicks are recorded.

Payment

GET/storefront/invoices/pay/:idNo auth
POST/storefront/invoices/pay/:idNo auth
GET/storefront/invoices/:id/amount-dueJWT

Public payment endpoints. The pay/:id GET returns the public-safe invoice (line items, total, payment options) — what a customer sees when clicking the payment link in their email. The POST takes a Stripe/PayPal payment intent confirmation and marks the invoice paid.

// Customer-facing payment page
const inv = await fetch(`/api/storefront/invoices/pay/${invoiceId}`, {
  headers: { orgid: ORG_ID },
}).then(r => r.json());

// After Stripe payment
await fetch(`/api/storefront/invoices/pay/${invoiceId}`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', orgid: ORG_ID },
  body: JSON.stringify({
    paymentIntentId: 'pi_xyz',
    amount: inv.total,
  }),
});

Status transitions

POST/storefront/invoices/:id/mark-paidJWT
POST/storefront/invoices/:id/mark-overdueJWT
POST/storefront/invoices/:id/cancelJWT
POST/storefront/invoices/:id/reopenJWT
POST/storefront/invoices/:id/refundJWT
POST/storefront/invoices/:id/duplicateJWT

The status machine: draft → sent → viewed → (partially-paid) → paid (with overdue and cancelled as side states). mark-paid is for offline payments (cheque, ACH outside the platform). mark-overdue is usually triggered by a scheduled job rather than called by hand. refund reverses a payment via the original payment method. duplicate is a quick way to create a recurring invoice — copy, edit dates, save.

PDF and rendering

The PDF is generated server-side from a configurable template (logo, layout, terms text). Org-management exposes the template editor; invoices read the latest template at PDF render time, so updating the template re-styles future invoices without touching past ones.

The PDF URL is on the invoice record under data.pdfUrl. It's a signed URL valid for the org's default expiry (configurable, default 30 days). Re-fetching the invoice generates a fresh URL.

Recurring invoices

For predictable monthly billing, two paths:

  • Subscription via storefront — see Subscriptions and rentals. Stripe handles the recurrence, invoices are auto-generated.
  • Manual recurring — duplicate the invoice on a schedule via the Automation module. Use this for hand-curated B2B invoicing where line items change each month.

Merchant-customer integration

When a B2B merchant account is on NET-30 terms (see Merchant customer), placed orders don't get charged immediately. Instead the merchant's monthly billing job calls POST /crm/merchant-customers/invoices/generate/:id, which rolls unbilled orders into a single invoice via this module. The merchant then pays the invoice through the public payment endpoint.

For US tax compliance with services or hybrid invoices, plug a tax provider into the shipping and tax module. Invoice tax calculation uses the same engine.