Skip to navigation

Prepaid and postpaid billing

Plans, balances, invoices and the ledger behind them.

Every customer is billed under a plan, and every plan has one of two billing modes. Settlement works the same way in both.

PrepaidPostpaid
The customer paysUp front, through checkout or a contractAt the end of each period, on an invoice
Balance unitOne credit type, such as ai_creditsThe plan currency, in minor units
Ratescredits_per_unitunit_amount_decimal
Limitoverdraft_limit, how far below zero the balance may gocredit_limit, how much may go unbilled
A reversal after confirmationRestores the creditsComes off the draft invoice, or is credited on the next one

Plans

A plan sets the billing mode, currency, interval (month or year) and the rates. Each rate prices either a usage event (event_name, per unit of quantity) or an outcome (outcome_definition, per confirmed outcome). Prepaid plans can also include credits each period, with rollover of none, all or capped, and allow top-ups at a price per credit. For more control, a prepaid plan can have allowances that refill credits on a schedule or cap their use, and named pools that keep included and purchased credits apart. Plans can charge per seat (per_seat), and give each new subscription a default spend limit. A postpaid rate can include a quantity of free units each period (included_quantity) and bill the units past it at an overage_unit_amount_decimal. Postpaid plans can set a minimum_commitment, billed as a shortfall line when charges fall below it, and an invoice_grace_period so late events land on the right invoice.

Pricing, allowances, pools and per_seat can change until the first customer subscribes. After that, create a new plan and move customers with change_plan, which takes effect at the start of their next period. A plan’s default_spend_limit is the exception: it can change at any time and applies to subscriptions created afterwards.

A subscription on a per_seat plan has a quantity. Set it when you create the subscription and change it with PATCH /v1/subscriptions/{id}. The recurring fee and included credits use the new quantity from the next period.

Subscriptions

A customer has at most one active subscription. Self-serve customers start one through checkout() in subscription mode, which creates it once payment succeeds. For sales-led contracts, create it with POST /v1/subscriptions and choose charge_automatically (the saved card) or send_invoice (a payment link from the customer’s payment provider). A subscription goes past_due when an invoice is unpaid, and checks are denied until it’s paid.

Balances

Both modes use one formula:

available = posted - held + limit
  • Prepaid: posted is credits on hand, held is active holds plus pending and disputed outcome charges, and limit is the overdraft allowance.
  • Postpaid: posted is zero or negative, the confirmed charges not yet invoiced, and limit is the credit limit. A positive postpaid balance is a credit waiting for the next invoice.

Read balances with GET /v1/customers/{id}/balances, or as they stood at any past time with as_of.

Credit types

A credit type is the unit a prepaid plan counts in. key names it (ai_credits), kind is custom for your own unit or monetary for a prepaid balance held in a currency, decimal_places sets its precision (up to 9), and unit_label is the word you show customers. Create credit types with POST /v1/credit_types or in the credit_types section of a configuration document.

An account can have several, and each prepaid plan uses exactly one. Balances in different credit types are never added together. To keep credits apart that share a unit but follow different rules, use pools, not extra credit types.

Credits

Prepaid credits arrive as grants: from checkout top-ups, automatic top-ups, a plan’s included credits and allowances, or from POST /v1/credit_grants for contract prepayments and goodwill. Each grant has a pool, an expiry and a priority (top-up credits expire after one year unless the plan or checkout sets another length), and is either paid, with a cost basis per credit, or promotional. Credit expiry covers how long credits last, the warning before they lapse, and the breakage report.

Credits are drawn pool by pool, in the order the plan lists its pools. Inside a pool they are drawn in this published order:

  1. Lowest priority number first.
  2. Then the soonest expiry, with grants that have no expiry last. Top-up grants always have one, one year by default.
  3. Then promotional before paid.
  4. Then the oldest grant.

The cost basis values each credit when it is used, so revenue and margin reports show money, not credits. Unused paid credits are deferred revenue until they are used or expire. The credits report shows how many paid credits were sold, consumed and expired over time, and how many are outstanding at cost basis.

Invoices

Postpaid subscriptions get one invoice per period. The current period’s invoice is a draft that fills as charges confirm and usage is tracked, so you can show customers their bill so far. It finalizes at finalizes_at, the period end plus the plan’s grace period, and then never changes.

  • Pending outcome charges are billed in the period they confirm. A charge that is still pending when the period closes goes on the next invoice.
  • Late events go on the next invoice. An event dated inside a period whose invoice is already final is billed on the next one.
  • Reversals after finalization become credits. The next invoice carries a reversal_credit line listing the reversals it covers.
  • Totals never go below zero. If credits exceed charges, the rest carries to the following invoice.
  • Rounding happens once, per line, half up to the currency’s minor unit.

The customer’s payment provider collects the invoice, and invoice.paid or invoice.payment_failed fires. With charge_automatically it charges the saved card. With send_invoice the invoice carries hosted_payment_url, a payment page at the provider that lasts at most 24 hours; Runledger doesn’t email it, so send it to the customer yourself. POST /v1/invoices/{id}/pay charges the saved card again.

Checkout

checkout() creates a hosted payment page at one of your connected payment providers and returns its url. The provider is the customer’s own payment_provider if you set one, then the first matching routing rule, then the account default, unless the request names one.

modeForOn success
top_upBuying credits on a prepaid planA paid grant with the top-up price as its cost basis, expiring after one year unless the plan or the session sets another length
subscriptionStarting a planAn active subscription, and its included credits
payment_methodSaving a card for postpaid invoicesThe card is used for charge_automatically

Runledger never holds the money. It sits at your payment provider, under your account, and every top-up and invoice payment is reconciled each day, once per connected provider, against that provider’s records. Each payment also has a provider-neutral payment record with the provider’s own reference.

The ledger

Every balance is the sum of immutable ledger entries, readable with GET /v1/ledger_entries. Each entry has a type (grant, grant_expired, grant_voided, hold, usage, outcome, outcome_reversed or invoiced) and a status:

  • pending entries count as held: active holds, and outcome charges that haven’t confirmed.
  • posted entries are final and carry the balance after them.
  • archived entries were pending and released without posting.

Entries are never edited. A correction is a new entry that links to the one it corrects. Each entry has an effective_at (business time, which can be in the past for a backdated event) and a posted_at. To keep your own copy, POST /v1/exports writes every customer’s balance, ledger entries, outcome charges or revenue states to a file, at any time. GET /v1/exports lists every export in the environment, newest first, including the ones made in the dashboard or by an agent. Each export’s source is dashboard, api or agent. The file is kept for seven days, and GET /v1/exports/{export_id} signs a fresh download link, good for an hour, each time it is called; after the seven days the export is expired, and a new one takes a minute to make.

Limits

  • Reversals after an invoice is final become a credit on the next invoice. Runledger doesn’t issue credit notes or refund cash; refund cash in your payment provider.
  • Invoices can’t be voided or marked uncollectible.
  • Plan changes take effect at the next period. There is no proration in the middle of a period.
  • Rates are per unit. Plans don’t have tiered or volume pricing across a period. A postpaid rate has one included quantity, then a flat overage price.
  • Credit grants apply to prepaid plans. A postpaid plan doesn’t draw down a commitment, and Runledger doesn’t bill a shortfall against a prepaid commitment at the end of its term.
  • Top-ups are started by you or your customer through a checkout session, or happen automatically with an auto top-up. Your customers can see their usage and manage their limits on the customer view.
  • Seats. A change in seats applies from the next period. Runledger doesn’t prorate seats added in the middle of one.

Next steps