Invoices
Driptab generates invoices automatically at period close and when add-ons are applied. This page explains the invoice lifecycle, how fees are computed, and how payments are recorded.
Invoice types
invoice_type |
When generated | Contents |
|---|---|---|
subscription |
At period close (arrears charges) or period start (immediate charges) | Base plan fee + usage fees for the period |
addon |
When an add-on is applied to a customer | The add-on's flat fee |
one_time |
Reserved for future use | — |
Most invoices are of type subscription.
Invoice timing: immediate vs. arrears
The invoice_timing on a charge determines when that charge's fee appears:
arrears — the fee is invoiced at period end, after usage is known. The
invoice is generated when the SubscriptionMeter alarm fires at current_period_end.
Use this for metered charges (email volume, API calls) and VPS compute billed after use.
immediate — the fee is invoiced at period start, before the period runs. Use
this for domain registrations, annual commitments, or anything paid in advance.
A single plan can mix immediate and arrears charges. At period start, an invoice is generated for immediate charges only. At period close, an invoice is generated for arrears charges (and usage fees).
Statuses
Invoice status
| Status | Meaning |
|---|---|
draft |
Not yet issued; may be modified. Not used in MVP — all invoices are issued immediately. |
outstanding |
Issued; payment pending. |
overdue |
Past due_date and not paid. Set by dunning job. |
succeeded |
Fully paid. |
voided |
Cancelled with no payment collected. |
disputed |
Customer has disputed the charge. |
Payment status
| Status | Meaning |
|---|---|
pending |
No payment recorded yet. |
succeeded |
Payment recorded and confirmed. |
failed |
Payment attempted and failed. |
Invoice structure
An invoice has:
- A
number— unique per organization, e.g.INV-2026-0042. period_startandperiod_end— the billing period this invoice covers.issuing_date— when the invoice was issued.due_date— when payment is expected.subtotal_centsandtotal_cents— in the customer's currency.- A list of fees — the line items.
Fees (line items)
Each fee corresponds to one charge (or the base plan fee):
| Field | Description |
|---|---|
fee_type |
subscription (base fee) or charge (usage or flat-fee line item) |
billable_metric_code |
Set for usage-based fees; identifies the metric |
units |
Aggregated usage quantity (decimal string) |
amount_cents |
Computed total for this line (units × rate, rounded) |
properties |
Pricing snapshot: the rate/price applied at invoice time |
The properties snapshot is critical: if you change a plan's pricing later, issued
invoices are unaffected because the fee rows already carry the price that was in
effect when the invoice was generated.
Viewing invoices
dtab inv list
NUMBER TYPE STATUS TOTAL ISSUED
INV-2026-0001 subscription outstanding $8.47 2026-07-01
INV-2026-0002 addon succeeded $12.96 2026-06-15
dtab inv get INV-2026-0001
The get response includes the full fee breakdown.
Recording a payment
Driptab does not process payments. When your payment provider confirms a payment, record it in Driptab:
dtab payments record \
--invoice INV-2026-0001 \
--amount 847 \
--currency USD \
--provider stripe \
--provider-id pi_3abc123
Or via the API:
POST /v1/payments
{
"invoice_id": "uuid-of-invoice",
"amount_cents": 847,
"currency": "USD",
"provider": "stripe",
"provider_payment_id": "pi_3abc123",
"paid_at": "2026-07-05T14:22:00Z"
}
Recording a payment:
- Creates a payment row linked to the invoice.
- Updates
invoice.payment_statustosucceeded. - Updates
invoice.statustosucceededif the amount equalstotal_cents. - Fires a
payment.succeededwebhook.
Dunning (overdue handling)
Driptab does not suspend or terminate subscriptions automatically. Instead, it fires
webhooks at overdue milestones defined in driptab.yaml. Your system acts on those
webhooks:
dunning:
steps:
- days_after_due: 3
webhook_event: invoice.payment_overdue_reminder_1
- days_after_due: 7
webhook_event: invoice.payment_overdue_reminder_2
- days_after_due: 14
webhook_event: subscription.suspend_requested
- days_after_due: 30
webhook_event: subscription.terminate_requested
At day 14, your system receives subscription.suspend_requested and calls
POST /v1/subscriptions/:id/suspend. At day 30, it receives
subscription.terminate_requested and calls POST /v1/subscriptions/:id/terminate.
Driptab fires the signal; your system decides what to do.
See Webhooks for the full event reference.