# Billing & Ledger Service div strong Key idea: br Billing & Ledger stores em pricing instructions (rates, discounts, allocations, subscriptions) and uses them to create em charges that are strong mutable until invoiced/settled . When charges are invoiced or settled, they become strong immutable and are moved to code SettledCharges . Billing & Ledger is the **financial backbone** of Nelnet Payment Services (NPS) billing platform. It defines pricing, models discounts and prorations, routes financial responsibility through allocation rules, and produces audit-safe records that downstream services (Invoices, Recurring Billing, Payment Widget, Remittance) can use to invoice, settle, and reconcile. ## What Billing & Ledger is (and is not) **Billing & Ledger *is* responsible for:** - **Rates** (debits and discounts) - **Rate Cards** (catalog grouping for UI discovery) - **Allocation configurations** (how responsibility is distributed) - **Subscriptions** (billing intent for a billable entity or account) - **Charges** (invoice-ready billing instructions, mutable pre-invoice) - **Ledger posting primitives** (journal entries and balances, as part of settlement flows) **Billing & Ledger is *not* responsible for:** - Rendering invoices (Invoices service) - Orchestrating recurring execution (Recurring Billing service) - Capturing payments (Payments API) - Storing payment credentials (Tokenization + Profile) - Acting as a merchant’s general ledger (it’s a sub-ledger and an instruction engine) ## Core domain concepts ### Quick reference table | Concept | What it is | Why it matters | Key IDs you’ll use | | --- | --- | --- | --- | | **Billable Entity** | *Who the service was rendered to* (e.g., a participant, student, dependent, member) | Most charges are tied to the billable entity for traceability and allocation validation | `billableEntityId` (from Profile Service) | | **Account** | *Who is financially responsible* (e.g., household, agency, sponsor) | Allocations split or route responsibility across one or more accounts | `accountId` (from Profile Service) | | **Rate** | A pricing instruction for a debit or discount | Defines “what it costs” (or “how much to discount”) | `rateId` | | **Rate Card** | UI/catalog grouping of rates | Helps humans and UIs find rates quickly; not used directly by charge calculations | `rateCardId` | | **Allocation Configuration** | A set of ordered rules describing responsibility distribution | Controls splits, caps, transfers, and write-offs at settlement | `allocationConfigurationId` | | **Subscription** | Billing intent for a billable entity or account | Ties together rate + discounts + allocation + billing frequency & anchor | `subscriptionId` | | **Charge** | An invoice-ready billing instruction | Stores *inputs* and *version snapshots*; mutable until invoiced | `chargeId` | | **Settled Charge** | Immutable, resolved version of a charge | Stores resolved amounts and splits after invoicing/settlement | `settledChargeId` | ### Billable entity vs account (required mental model) A **Billable Entity** represents *who services were rendered to* (e.g., a dependent receiving care, a student receiving instruction, a participant in a program). An **Account** represents *who is financially responsible*. A **charge must target either:** - a `billableEntityId` (most common), **or** - an `accountId` when you want to bill directly to an account (e.g., a registration fee that isn’t tied to a single service recipient). These are mutually exclusive for a charge and for a subscription. (Subscriptions also support either `billableEntityId` or `accountId`.) ## How the pieces fit together > This diagram is intentionally “conceptual” (client-facing). The actual storage model includes audit history and settlement tables. div div div Configuration (versioned) div div strong Rate br Debit or Discount div strong Allocation Configuration br Ordered rules div strong Subscription br Intent + schedule + references div strong Rate Card br Catalog grouping (UI) div div Charge lifecycle div div strong Charge br Mutable pre-invoice br Stores instructions + version snapshots div ↓ div strong Settled Charge br Immutable post-invoice/settlement br Stores resolved amounts + splits div div Profile references div div strong Billable Entity (Profile) div strong Account (Profile) div Allocation validation may require that the billable entity is associated to the accounts in the allocation. ## Rates A **Rate** is a single pricing instruction. Rates can represent: - **Debits** (what you charge), and - **Discounts** (credits) using `type=DISCOUNT`. Rates **do not store resolved outcomes**—they store instructions. Charges reference rates and compute the derived fields from those instructions. ### Rate behaviors - Rates are **versioned**. Updating a rate creates a new version. - Existing charges and subscriptions do **not** automatically change when a rate changes. - You must explicitly update a charge or subscription if you want it to use a newer version later. ## Rate cards A **Rate Card** is a **catalog grouping** of rates for UI discovery and organization. div strong Important: You cannot “charge a rate card.” Charges require explicit code rateId (and optionally code discountRateIds and an code allocationConfigurationId ). Rate cards exist to help humans/UIs choose those values. ## Discounts Discounts are modeled as rates (`type=DISCOUNT`). A discount rate can be: - percentage-based (e.g., 10% off), or - fixed-amount (e.g., $25.00 off) Discount rates are applied in order and can be combined with a debit rate, or exist as standalone credits. ## Allocation configurations and rules Allocation configurations describe **how financial responsibility is distributed** for a charge. They contain an **ordered list** of rules that are evaluated deterministically and resolved at settlement time into ledger/journal lines. Examples: - Split 50/50 across two accounts. - A sponsor pays the first $50, the responsible party pays the remainder. - A cap is applied, and any remainder is written off. Allocation configuration updates are versioned. Invoiced/settled charges keep their original allocation snapshot. ## Subscriptions A **Subscription** represents *billing intent*, not execution. Subscriptions define: - **who** is being billed (`billableEntityId` or `accountId`) - **what** to bill (rate + discounts) - **how** responsibility is routed (allocation configuration) - **how often** and **when** to bill (frequency + anchor day + timezone) - optional validity window (`startDate` / `endDate`) div strong Common misconception: Creating a subscription does em not automatically enroll someone into recurring billing. A subscription expresses intent. Recurring billing is executed by an orchestrator (often the Recurring Billing service) that creates charges on a schedule. ## Charges (mutable instructions) A **Charge** is an invoice-ready billing instruction. It is **mutable** until it is invoiced/settled. Charges: - store *inputs* and references (rate IDs, allocation IDs, discount IDs) - snapshot **versions** of referenced configuration at creation time - can be recalculated and updated while they are in mutable states - become immutable when invoiced/settled and are moved to **Settled Charges** ### Single vs combined vs standalone discount A charge can represent: - a single debit rate - a debit rate + one or more discounts - a standalone discount (credit) - a prorated debit/discount (via proration factor) ### Why charges store instructions (not resolved amounts) Charges intentionally store the instruction set rather than a fully resolved “final amount” so that: - charges can be edited during the billing window - you can correct quantity/discount selections without rewriting ledger - the system can deterministically resolve the final outcome at settlement time using the snapshotted versions ## Billing cycles and mutability Billing cycles determine **when charges are finalized**. **Key behavior:** - Charges remain mutable during the billing window (for example: `PENDING` or `BILLED`) - Once a charge is **invoiced/settled**, it becomes immutable (`INVOICED`) The API enforces mutability rules (updates/deletes are allowed only for mutable statuses; invoiced charges return conflict errors). ## Versioning (how pricing stays audit-safe) Every charge snapshots the versions of the configuration used at charge creation time, including: - rate version - discount rate versions - allocation configuration version - subscription version (if applicable) That means: - Updating a rate, allocation, or subscription does **not** retroactively change existing charges. - To apply new configuration, you must explicitly update the charge or create a new one. ## Tagging Billing & Ledger supports tags on configuration and stores derived tags on downstream records. Tags originating from Profile entities are nested under `profile` (for example `profile.billableEntity.*`) while billing configuration tags are nested under `billing.*`. See the **Tagging** section for details on nesting and consolidation rules.