Skip to main content
Invoices look simple, but realized revenue, revenue per plan and paying-customer counts each depend on dropping the right rows.

Revenue: use amount_paid, not total

total is the gross amount before refunds, and it includes invoices that were never paid. Revenue you actually collected is what was paid, minus refunds, on paid invoices:
  • Amounts are in major units (dollars, not cents). Don’t divide by 100.
  • void invoices carry real-looking totals. Filter status = 'paid'.
  • Paid invoices can be negative (credit notes). The formula above handles them.
  • Group by currency if you bill in more than one.

Revenue per plan

An invoice can cover several plans, so plan_ids is a JSON array. To split by plan, sum the line items, which each name one plan. Line items have no currency of their own; take it from the invoice.
Line amounts are before discounts, tax and refunds, so on discounted invoices the split adds up to more than amount_paid. To filter invoices by plan without line items, parse plan_ids (see Querying → JSON columns).

Paying customers: active is not “paying”

Active subscriptions include your free plans and customers in a trial. A paying customer has a live, priced, non-trial base plan. Count distinct customers, because one customer can hold several subscription rows (a main plan and add-ons).
For a custom plan (is_custom = true) the catalog plan’s price may not be what the customer pays. Check the customer’s own prices through v2_6_customer_plan_items if custom plans matter for your count.