Invoicing
Invoicing bills a Customer with a numbered Invoice, payment terms and a hosted payment page, then collects, reminds or voids it.
Invoicing bills a Customer with a numbered Invoice, then collects it by charging a saved card or by waiting for a bank transfer on terms. Refunds and voids correct an Invoice; nothing deletes one.
Contract
| Status | What it means | Moved by |
|---|---|---|
draft | Lines still change, and nothing is owed. | Subscription.renew drafts each period’s Invoice |
open | Numbered, frozen and presented to the Customer. | Invoice.bill |
paid | Collected, with Invoice.paidAt set. | Invoice.collect |
void | Canceled unpaid, and kept forever. | Invoice.void |
Invoice.collection sets how an Invoice is paid.
| How | charge | send |
|---|---|---|
| Suits | Buyers who pay by card | Buyers on terms, whose Invoice.purchaseOrder must print on it |
| Due | On issue | Invoice.terms days after issue, such as 30 |
| Paid by | Invoice.collect charging the default Payment Source | A bank transfer into the Startup’s Stripe balance, or a card on Invoice.payUrl |
| When unpaid | Dunning retries on its schedule | Invoice reminders write a week before due and the day after, with no retry |
| Paid when | The charge succeeds | The transfer reconciles and Invoice.collected fires |
| Rule | Detail |
|---|---|
| Number | Invoice.number runs in sequence per Startup and is never reused, voided Invoices included. |
| Lines | Invoice.lines freezes at Invoice.bill. A correction voids and bills again, or refunds part of a paid Invoice. |
| Purchase order | Invoice.purchaseOrder prints on the Invoice; an accepted Quote carries it in Quote.paymentTerms. |
| Receipt | Invoice.pdf names the seller of record and lives on the Startup’s own Domain. |
| Tax | Stripe Tax computes it at Invoice.bill from Customer.billingAddress and Customer.taxIds. |
| Credits | CreditGrant.apply pays metered lines from Credit Grants as the Invoice finalizes. |
| Refund | Invoice.refund returns all, part, or the unused share of the Period to the original payment, never to a balance. |
| Refund gates | Invoice.refund waits its delay window and refuses while a Dispute is open. Above the Billing Specialist’s Limit, it opens an Approval for the Finance Lead. |
Verbs
| Verb | Object | Event |
|---|---|---|
| Invoice.bill | Invoice | Invoice.billed |
| Invoice.collect | Invoice | Invoice.collected |
| Invoice.void | Invoice | Invoice.voided |
| Invoice.refund | Invoice | Invoice.refunded |
Interfaces
Example
import { $ } from 'startup-builder'
// ledgerlark.com renews a firm's $6, 000 annual plan. The firm's accepted Quote set send collection,
// net-30 terms and purchase order PO-88412, so the renewal drafted invoice_1 with all three.
await $.Invoice.bill({ invoice: 'invoice_1' })
// The firm asks to bill its second entity. Void the first and bill the corrected draft; both stay on record.
await $.Invoice.void({ invoice: 'invoice_1', reason: 'Billed to the wrong entity.' })
await $.Invoice.update({ id: 'invoice_2', collection: 'send', terms: 30, purchaseOrder: 'PO-88412' })
await $.Invoice.bill({ invoice: 'invoice_2' })
// Day 27: the bank transfer reconciles in the Stripe balance, and Invoice.collected fires.
const invoices = await $.Invoice.list({ where: "status = 'paid'" })
// Month 3: the firm drops its $1, 000 reporting add-on. Refund the 9 unused months to the original payment.
await $.Invoice.refund({ invoice: 'invoice_2', amount: { amount: 750, currency: 'USD' }, reason: 'Reporting add-on removed after month 3.' })