# Domain 8 — BNPL / Installments

← Database Model

Related: business requirements — Installments / BNPL. Settlement and reversal detail are explained in depth in the payments docs — BNPL landscape and Cancellation & payout.

Resolved. Because verified research shows Iranian provider-financed BNPL settles the full amount to the merchant in one lump (provider owns the customer's installments and default risk), a BNPL order is — in our books — a card payment that lands net-of-fee. The original `installment_plans` + `installment_entries` subsystem (which tried to track the customer's repayment schedule and default) is deleted: it modeled a receivable Balinyaar never owns and a risk it never bears.

### `bnpl_transactions` [MVP] — NEW (replaces `installment_plans`) #

Role: One row per BNPL order, 1:1 with its `payment_transaction` — the single inbound settlement to reconcile, plus the revert path. Why one row, not a plan+entries tree: there is nothing to amortize on our side; we track the settlement, the provider's commission, and the reversal.

Field | Type | Notes
--- | --- | ---
`id` | BIGINT PK |
`payment_transaction_id` | BIGINT FK UNIQUE | 1:1
`provider_code` | NVARCHAR(50) | `snapppay` / `digipay` / `tara` / `torobpay`
`merchant_of_record` | NVARCHAR(40) | Balinyaar entity or partner center
`external_payment_token` | NVARCHAR(200) | For verify/settle/revert
`external_transaction_id` | NVARCHAR(200) |
`eligibility_status` | NVARCHAR(30) |
`order_amount_irr` | BIGINT | Gross order
`settled_amount_irr` | BIGINT | Net of provider commission actually received
`bnpl_commission_irr` | BIGINT | Provider's merchant discount = platform expense (never the nurse's)
`currency` | NVARCHAR(5) | `IRR`/`TOMAN` at boundary; convert in
`installment_count` | TINYINT | Informational (default 4) — owned by the provider
`status` | NVARCHAR(30) | State machine: `eligible`/`token_issued`/`verified`/`settled`/`reverted`/`cancelled`/`failed`
`settled_at` | DATETIME2 NULL | Per-transaction — timing is contract-defined (daily/T+1-3/weekly), never assumed instant
`revert_transaction_id`, `reverted_amount_irr`, `reverted_at` | … | Reversal path
`refund_channel` | NVARCHAR(20) |
`callback_payload_json` | NVARCHAR(MAX) | Raw verify/settle payload
timestamps | … |

Relations: 1:1 → `payment_transactions`. State-machine guard on `status` for idempotency.

### `bnpl_settlement_entries` [DEFERRED] #

Role/Why: Only needed if a future provider uses tranched settlement (pays the platform over time). No mainstream Iranian provider does today, so it's modeled-but-inactive; adding it later is a purely additive migration.

↑ Back to top