2.6 KiB
ADR 0013: Model bank-paid, verified, and merchant-fee semantics
- Status: Accepted
- Date: 2026-08-20
Context
The source exposes session states Paid, Verified, Failed, and Reversed, but names alone did not establish business meaning. Authoritative clarification from ZarinPal's CTO defines a two-step lifecycle: the buyer first completes payment at the bank, then the merchant calls verification. Paid means the bank payment succeeded and funds were deducted but merchant verification is incomplete. Verified means both steps completed. Reversed is possible but extremely rare; the dataset contains one such session.
The challenge field adjusted_fee was transformed/name-adjusted for participant confidentiality, but the product domain treats it as the merchant's real fee. Profiling found its value constant within every session: 150,450 repeated attempt rows and zero fee conflicts.
Decision
Use these canonical populations:
- bank-paid: session status in (
Paid,Verified); - verified/finalized: session status
Verified; - unverified paid: session status
Paid; - unsuccessful current outcome:
FailedorReversedfor the MVP success-rate denominator.
Define payment success rate as bank-paid sessions divided by sessions in (Paid, Verified, Failed, Reversed). Keep unknown future statuses out of numerator/denominator and report their coverage until explicitly classified. Define verification completion rate as Verified / (Paid + Verified).
Paid amount is the session amount summed once for (Paid, Verified). Also expose verified amount and unverified-paid amount as explicit subsets. Never call Paid a failure.
A retried session has more than one attempt. An eventually paid retry has final session status Paid or Verified and at least one lower-try_seq attempt whose status is neither Paid nor Verified; CSV row order is irrelevant.
Rename source adjusted_fee to canonical fee_amount_rial, store it once on the session, and present it as a real Rial merchant fee. Paid fee totals sum it once for bank-paid sessions. Fee rate is sum(paid session fee) / sum(paid session amount) with numerator, denominator, period, and unit visible.
Consequences
- Dashboard success combines
PaidandVerified, while verification health separates them. - The unverified-paid count/amount is an actionable merchant discrepancy, not a failed-payment metric.
- Retry recovery may end in either
PaidorVerified. - Fee aggregation uses session grain and cannot multiply fees by retry count.
- Unknown statuses require a metric-catalogue change rather than being guessed into success or failure.