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

# Wallet-First Billing

> On renewal, spend the customer's prepaid wallet balance before ever touching a card — the recovery play that stops a decline before it happens.

The cheapest failed charge is the one that never runs. If a customer has topped up their [wallet](/identity/wallet), a renewal should spend that balance first — no gateway round-trip, no decline, no dunning. That's **wallet-first billing**: the renewal engine tries the wallet, and only falls back to the card if the wallet can't cover the charge.

## The order of preference

```mermaid theme={null}
flowchart TD
    DUE["renewal due<br/>(currentPeriodEnd ≤ now)"] --> INV["create open invoice<br/>(idempotency key per period)"]
    INV --> EMAIL{"customer has<br/>an account email?"}
    EMAIL -->|"no"| CARD
    EMAIL -->|"yes"| WALLET{"wallet debit covers<br/>the full amount?"}
    WALLET -->|"yes"| PAIDW["invoice paid · rail = wallet<br/>period advances"]
    WALLET -->|"no / no wallet"| CARD["charge saved card<br/>(rail = card)"]
    CARD --> OK{"succeeded?"}
    OK -->|"yes"| PAIDC["invoice paid · rail = card<br/>period advances"]
    OK -->|"no"| DUN["hand to dunning →"]
```

The sequence is **wallet → card → dunning**, and it runs on every renewal cycle:

1. The engine creates the next-period invoice (idempotent on `renewal_{subId}_{periodStart}`, so a double-scan can't double-bill).
2. If the subscription's customer has a matching [`CustomerAccount`](/identity/universal-identity) by email, it attempts a **wallet debit** for the plan amount, referenced by the invoice id.
3. **Wallet covered it** → the invoice is marked paid with `rail: wallet`, no gateway is called at all.
4. **Wallet short or absent** → it falls back to charging the saved card (`rail: card`).
5. **Card declines** → it hands the invoice to the [dunning engine](/billing/dunning) exactly as before.

<Note>
  The wallet debit is **all-or-nothing** — it only succeeds if the balance covers the *whole* plan amount. Duro never part-pays an invoice from the wallet and charges the remainder to a card; a partial balance simply falls through to the card path untouched.
</Note>

## Why this is a recovery feature, not just a payment feature

Duro is recovery-first: the whole system is built to turn *money-at-risk* into *money-recovered*. Wallet-first billing moves that fight **upstream of the failure**. A customer who tops up ₦20,000 has pre-funded their next four ₦5,000 renewals — those four charges will never decline, never enter dunning, never send a "your card failed" email, and never risk an involuntary churn. The best dunning campaign is the one that never has to start.

## Idempotency carries through

The debit is referenced by the invoice id (`walletdebit_{invoiceId}`), so the wallet's `(account, reference)` uniqueness guarantees a given invoice draws from the balance **at most once** — even if the renewal job is retried after a wallet debit succeeded but before the invoice was marked paid. The retry finds the debit already applied and proceeds to settle the same invoice, rather than double-charging the balance.

## What the ledger records

A wallet-funded renewal posts to the finance [ledger](/architecture/data-model) with the wallet as the funding source: the renewal is recorded as recognised revenue, and the wallet balance is drawn down via a `wallet_debit` entry. Reporting sees the same MRR it always did — the *source* of the cash changed, not the revenue.

Next: the [dunning engine](/billing/dunning) that still catches the renewals the wallet couldn't cover.
