driptab/Docs

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_start and period_end — the billing period this invoice covers.
  • issuing_date — when the invoice was issued.
  • due_date — when payment is expected.
  • subtotal_cents and total_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:

  1. Creates a payment row linked to the invoice.
  2. Updates invoice.payment_status to succeeded.
  3. Updates invoice.status to succeeded if the amount equals total_cents.
  4. Fires a payment.succeeded webhook.

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.