# Handoff — after backend-phase-12 (BNPL: provider-financed installments) **BNPL checkout is live.** A family can now pay for a booking with a provider-financed installment plan (SnappPay / Digipay / Tara / Torob Pay). The decisive, verified truth: an Iranian provider-financed BNPL order **settles the full booking amount to Balinyaar in one lump, net of the provider's merchant commission**, and the provider owns the customer's installments and **100% of default risk**. So in our books a BNPL order is **a card payment that lands net-of-fee** — one `bnpl_transactions` row (1:1 with its `payment_transaction`), a forward-only `eligible → token_issued → verified → settled → reverted` state machine, and a settle that posts the card-capture ledger legs **plus** a `bnpl_fee_expense` leg so escrow reflects the *net* cash. **The nurse's payout is invariant to payment method.** We do **not** model the customer's repayment schedule. ## What the frontend (f11-b12) can now build - **"Pay with installments" option at checkout** — `POST checkout_bnpl/eligibility` returns `eligible`/`not_eligible`/`ceiling_exceeded` + the plan summary ("4 interest-free installments, provider-financed", `installmentCount`, `creditCeilingIrr`). On anything but `eligible`, **fall back to card**. - **Start the plan + provider handoff** — `POST checkout_bnpl/initiate` → `token_issued` + `externalPaymentToken` + `redirectUrl` (send the customer to the provider). Carries an `Idempotency-Key` header. - **Order status** — `GET checkout_bnpl/{id}` (customer, own order only): status, gross/net/commission, the **non-instant** `settledAt`, and the revert audit + async customer ETA. - **Admin BNPL console** — `POST admin_bnpl/{id}/verify|settle`, `POST admin_bnpl/{id}/revert` (full or partial), `GET admin_bnpl/{id}`. The revert surfaces `expectedCustomerRefundEta` (~7–10 business days) and opens a `refund_channel='bnpl_revert'` refund (visible via the b11 `GET refunds/{id}/status`). ## Live endpoints / contract - Contract: **`dev/contracts/domains/bnpl.md`** (enums, DTO shapes, IRR digit-strings, nullable `settled_at`, failure codes, the net-of-fee settle + customer↔provider↔Balinyaar refund routing). Machine schema: `dev/contracts/openapi/swagger.v1.json` **refreshed**. - All money is IRR integer, on the wire as a **digit-string**; `settled_at` is **nullable** (not instant); `expectedCustomerRefundEta` is a **date**. - Checkout is customer-scoped + **rate-limited**; the webhook is anonymous (signature-verified) + rate-limited; admin endpoints are behind the admin policy + rate-limited. ## What is mocked / waiting - **The provider + currency are mocked** behind **`IBnplProvider`** (per `provider_code` via **`IBnplProviderResolver`**) and **`ICurrencyNormalizer`** — deterministic, no network; the settle commission is a configurable mock % (`Seams:Bnpl:CommissionRate`, default 10%). See `reports/mocks-registry.md` for the exact real-provider steps (SnappPay/Digipay verb sets, encrypted creds). - **Settlement timing is not modelled as instant** — `settled_at` is nullable and read from the settlement (`Seams:Bnpl:SettlementInstant` toggles the mock). **b13 must not assume BNPL cash funds a payout.** - **`bnpl_settlement_entries`** (tranched settlement) is **DEFERRED — modeled-but-not-built**; adding it later is a purely additive migration. - **Multi-provider routing / failover** is DEFERRED — one active route, config-driven selection. - The revert reuses the **b11 refund path**; `provider_commission_reversed_amount` is left null there (reconciled from the provider response later). ## Notes for the next backend phases - **b13 (payouts):** the `settled_at`-gates-payout coupling lives here — add the `require_bnpl_settlement_for_payout` config flag and gate a BNPL booking's payout on `bnpl_transactions.settled_at` actually being set (never pay a nurse before Balinyaar holds the cash). The `nurse_payable` accrual is already identical to the card path, so payout amounts need no BNPL-specific logic. - **Shared conversion:** b10's booking-creation was extracted to `Features/Bookings/BookingConversion` — both the card capture and the BNPL settle use it. Reuse it, don't fork.