> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# The invoice, statement, and subscription model

> What each billing document means in Orbit — invoices from the billing provider, statements from the prepaid wallet ledger, and recurring-agent subscriptions with mandate authorization — plus how statement balances reconcile and why tax on hosted checkouts is handled by the buyer, never estimated.

# The invoice, statement, and subscription model

Orbit surfaces three kinds of billing artifact, each with a precise meaning:

* **Invoice** — a paid-style receivable document issued by the downstream
  billing provider (Orb for metered usage, Stripe for card checkouts). Orbit
  reads and renders it; it never issues it.
* **Statement** — a calendar-month summary of your prepaid wallet, derived
  purely from the append-only wallet ledger. This is the document Orbit owns
  end to end.
* **Credit note / refund** — reversals (wallet credit entry or provider
  refund) that adjust a prior document; in Orbit they ride the same ledger
  channels rather than being separate artifact types.

Billing-recurring **subscriptions** enter two different senses of the word —
the tenant's own Orbit plan subscription (held on Stripe), and a *commerce
"subscribe & save"* recurring schedule an agent renews against a buyer's
payment mandate. This page models both, then the statement balance
reconciliation, then the tax semantics.

## Documents — invoice vs statement vs adjustment

**Invoices.** The invoices surface (`/billing/invoices`, and
`GET /api/v1/billing/invoices*`) projects the billing provider's read of
your receivable documents. An invoice carries a lifecycle `status` —
`draft` → `issued` → `paid` | `void` — plus `synced` for provider-side
finality. Orbit itself creates **no** subscription-style invoices; it lists
whatever the provider holds against your tenant id
(`external_customer_id`). When the provider read fails (or was never
provisioned — a new tenant sees a legitimately empty state), the surface
degrades to the durable recorded-invoice trail rather than a misleading
empty list.

**Statements.** A statement is a per-month (`YYYY-MM`) rollup computed from
the wallet ledger. Every top-up is a positive ledger entry; every usage
charge is a negative one; credits and clawbacks roll into an `adjustment`
line. The statement is therefore *derived*, not issued — deleting the
ledger rows is impossible, so a regenerated statement always agrees with
the ledger.

**Adjustments instead of credit notes.** Orbit does not mint separate
credit-note documents. Anything that reverses value — a card refund
against unused balance, a crypto payout, a residual credit — lands as a
signed ledger entry of type `topup` (positive) or `usage` (negative), and
the statement groups it under `adjustment`. Downstream providers (Orb /
Stripe) can issue their own credit notes on their side of the integration;
the Orbit statement reconciles them as ordinary signed lines.

## Generation — provider invoices, plus a cost breakdown rollup

Two generation paths converge on the same surface.

1. **Provider invoice detail.** A live fetch validates the provider's
   envelope and required money fields (status, currency, totals) at the
   boundary before projecting onto the summary/detail shapes — a partial
   provider body fails closed rather than surfacing `undefined` financial
   figures. The download route redirects to the provider-hosted PDF or
   hosted invoice page, so the accounting system follows a `302` to the
   provider's rendered document.
2. **Usage cost breakdown.** Because provider line items carry no
   channel/destination attribution, each invoice detail is enriched with a
   `cost_breakdown` — the same channel × country aggregation the live
   usage-by-channel surface runs, scoped to the invoice's billing period
   (line-item span first, then the subscription period). Sources: your
   tenant's message ledger plus voice call log. It is a *proportional showback*
   of usage for the period and intentionally excludes plan fees, minimums,
   discounts, and tax — so its rows need not sum to the invoice total. The
   enrichment is fail-open: a missing period or a database fault returns
   the invoice without a breakdown, never a 500.

Provider-rendered PDFs stay provider-rendered; Orbit supplies the raw
lines but does not re-render the document.

## Recurring subscriptions — two shapes, one gate

**The tenant's plan subscription.** The subscription-management service
(dashboard self-service, plan checkout, pay-by-link mint, portal) treats
the Stripe subscription as authoritative. Lifecycle actions are
`cancel` (schedules `cancel_at_period_end`), `reactivate`, and
`change_plan`; each mutation carries a deterministic idempotency key so a
retried operation cannot re-apply the change. Cancel sets a projected
`*-cancel:*` key; a price-swap uses `*-change:*`. The "Scheduled for
cancellation" bit is read from the subscription itself, not from a mutable
org flag — a webhook-only flip still renders correctly.

**Commerce "subscribe & save".** An agent can renew a recurring schedule
(weekly / biweekly / monthly / quarterly) on behalf of a buyer — the
commerce layer used by agentic checkouts. The schedule is a snapshot the
caller round-trips: `active` → `paused` (freeze) → `active` (re-anchor,
never fire a backlog) → `canceled` (terminal). Every renewal executes
against the SAME payment **mandate** the buyer consented to at
subscribe-time — a scoped, spend-capped, SHA-256–committed authorization.
A mandate is `active`, and leaves `active` only to one of the terminal
states `exhausted`, `revoked`, or `expired` — after which no further cycle
is ever authorized. A renewal that the mandate declines (per-transaction
cap, total cap, non-allowed merchant/category, expired/revoked) leaves
the schedule untouched so the caller can retry after fixing the mandate.

Mandate checking is the reason no outbound loop fires on a schedule the
buyer revoked: the scheduler can mint the hosted pay link, but the charge
authorization re-verifies the consent digest first. (The rendered
re-order message rides RCS or WhatsApp outbound per the commerce layer —
never voice/SMS per the platform's outbound invariant.)

## Statement balance arithmetic — reconciling the period

A statement row carries `opening_balance`, `total_topups`, `total_usage`,
and `closing_balance`. By construction the signed line items
(`topup`, `usage`, `adjustment`) sum to the delta:

```
closing_balance − opening_balance = Σ topup − Σ usage + Σ adjustment
```

The same line-item decomposition is what a reconciliation export
preserves: given the month's statement you can tie each row back to a
ledger entry (`reference`-prefixed charge lines, or the top-up session
id). The `usage_by_channel` rollup covers only negative debits —
statement `topup` lines never include usage, so a normal paid provider
invoice does not raise the wallet's issued-invoice subset.

When reconciling against the provider-side receivable (an invoice issued
against the wallet, or a pay-as-you-go statement), use the
[revenue recognition](/billing/revenue-recognition) schedule rather than
comparing raw totals — the two views converge once both period closes are
run to the same `as-of` date. Balance-owed on a customer account is not a
live computed figure; it is the closing-balance delta over the invoice
snapshot at period close.

## Tax semantics — scoped, never estimated

Orbit never estimates tax, and this is deliberate.

* **Hosted checkouts (top-up / pay-by-link).** Automatic tax and Adaptive
  Pricing are OFF by default. The buyer pays exactly the subtotal; the
  wallet credits exactly the subtotal. A "wrong total" is never silently
  inflated — if a tenant enables the optional provider tax flag, the
  buyer pays `subtotal + tax`, the wallet is still credited the subtotal,
  and the tax line is stamped onto the ledger entry so wallet↔ledger
  reconciliation stays exact.
* **Provider invoices.** The per-invoice tax total comes straight from
  the provider's document (`tax_amount`); Orbit never synthesizes it.
  A nil tax field means the provider assessed none — not that Orbit
  estimated zero.
* **Reseller/metered surfaces.** Where a tax line is modeled (usage-
  metering rollups a platform resells to its customers), it is a scoped
  optional parameter with an optional exemption certificate — only an
  `approved` certificate matching the jurisdiction suppresses it. Even
  there, the amount is computed from explicit inputs, never estimated
  from address or geography.

The rule of thumb: an Orbit surface either carries the provider-assessed
tax, an explicitly scoped tax parameter, or no tax line at all. It never
fills the gap with an estimate.

## Related

* [Billing ops: invoices, statements, and pay-by-link](/guides/billing-invoices-statements-and-pay-by-link)
  — the operator flow across the four surfaces; this page supplies the model.
* [Wallets, credits, and charges](/concepts/billing-and-wallet) — how a
  wallet debit is attributed to a channel.
* [Revenue recognition](/billing/revenue-recognition) — the per-period
  schedule for matching an invoice to the ledger.
* [Usage Metering API](/api-reference/usage-metering) — the scoped
  tax input on reseller rollups.
