How the diagnoser is tested
60 payment decline scenarios across card, UPI, UPI Autopay and NACH. Each one has a hand-written correct answer: the root cause, whether to retry, when, and what to tell the customer. Every version of the diagnoser is scored against this set.
50
Development scenarios
10
Held-out scenarios
18
Root causes
200
Codes in the reference
How I built it
- 1
I started from the codes, not the model. I researched ~200 decline codes from NPCI, ISO 8583, Razorpay, Cashfree and Stripe, grouped them into 18 root causes, and defined the right merchant action for each.
- 2
I designed scenarios around real failure modes. I covered different rails, repeated failures, retry timing, advice codes, customer-reported debits, and deliberately unknown codes to test hallucination.
- 3
I wrote the expected answer for every scenario myself. For each case, I determined the correct root cause, merchant action and retry recommendation using the source documentation and transaction context. I used AI occasionally to help draft or sanity-check answers, but reviewed and finalized every label myself.
- 4
I kept 10 scenarios completely separate from prompt tuning. These are my holdout set. I don't use them while improving the prompt, so I can use their final score to see whether the model actually generalizes.
- 5
I validated the final labels against the source documentation. I rechecked the cases where the answer depended on rail-specific or provider-specific rules, and documented any changes to the expected answers.
BY SCENARIO TYPE
BY RAIL
Scenarios
S01Card · code 51 · ₹799 · recurring · attempt 1
Reason: Insufficient funds
Context: Monthly OTT subscription renewal, debit card on file
EXPECTED ROOT CAUSE
Insufficient funds
RETRY VERDICT
TIMING
Retry after 3 days; if that fails, retry around the 1st–7th (likely salary credit)
WHY
First failure, specific code, small amount — soft decline. Card retry is simple.
S02Card · code 54 · ₹2,499 · recurring · attempt 1
Reason: Expired card
Context: Annual SaaS renewal; card saved three years ago
EXPECTED ROOT CAUSE
Card expired
RETRY VERDICT
TIMING
Never retry on the expired card; retry after customer updates card details
WHY
Preventable — expiry date is known; send reminder ~30 days before (grace period for annual plan)
S03Card · code 41 · ₹4,999 · one-off · attempt 1
Reason: Lost card
Context: Online electronics accessory purchase
EXPECTED ROOT CAUSE
Card lost stolen
RETRY VERDICT
TIMING
Never retry on this card
WHY
Hard decline + fraud signal: person at checkout may not be the cardholder; Merchant: flag session for review. Generic message only — safe for both a genuine customer and a fraudster. Fails if model retries or names the reason.
S04Card · code 91 · ₹1,299 · one-off · attempt 1
Reason: Issuer or switch inoperative
Context: Food delivery order at 11:45pm
EXPECTED ROOT CAUSE
Bank or network downtime
RETRY VERDICT
TIMING
Immediately, but only when customer retries with a different method; no scheduled retry
WHY
"retry in 1–4h" is useless for a food order at 11:45pm — order is lost and the same card likely fails while issuer is down.
S05Card · code 82 · ₹3,450 · one-off · attempt 1
Reason: CVV mismatch
Context: First purchase on a D2C apparel site
EXPECTED ROOT CAUSE
Payment details invalid
RETRY VERDICT
TIMING
Customer retries immediately with corrected details; never resubmit same details
WHY
Usually a typo — field-level error message recovers the sale. Merchant: don't clear the form; cap attempts at 2–3, since repeated CVV failures on a first purchase are a card-testing pattern. The model should give the specific fix, and ideally mention an attempt cap.
S06Card · code 1A · ₹8,999 · one-off · attempt 1
Reason: Additional customer authentication required
Context: Flight booking checkout
EXPECTED ROOT CAUSE
Auth not completed
RETRY VERDICT
TIMING
Retry immediately through the authentication flow while customer is at checkout
WHY
Card is fine; issuer wants authentication the request lacked. Merchant fix: resubmit with 3DS/AFA; hold fare during verification. In India, 1A suggests a flow that skipped AFA (e.g. international acquirer). Time pressure: fare may expire. Fails if model says "use another card".
S07Card · code card_disabled_for_online_payments · ₹1,899 · one-off · attempt 1
Context: Customer's first online purchase with a new debit card (Razorpay)
EXPECTED ROOT CAUSE
Instrument restricted
RETRY VERDICT
TIMING
Customer retries immediately after enabling online payments or switching method; no scheduled retry
WHY
New Indian cards often have online use off by default. Fixable in seconds: a specific checkout message saves the sale. Tests whether model gives a concrete fix instead of generic "contact your bank".
S08Card · code authentication_required · ₹1,199 · recurring · attempt 1
Context: Off-session monthly renewal of a design tool (Stripe)
EXPECTED ROOT CAUSE
Auth not completed
RETRY VERDICT
TIMING
No automatic retry (off-session retry fails again); retry only after customer authenticates
WHY
Customer isn't present — model must recommend bringing them back, not a timed retry. If every renewal hits this, it's a setup problem: check the card was registered with an RBI-compliant e-mandate (verify rule before freezing). Common for global SaaS billing Indian cards.
S09Card · code 94 · ₹649 · one-off · attempt 2
Reason: Duplicate transmission
Context: Grocery order; customer double-tapped Pay
EXPECTED ROOT CAUSE
Duplicate or already collected
RETRY VERDICT
TIMING
Never retry; check status of attempt 1 first
WHY
Decline is the system correctly blocking a double-tap. Merchant: reconcile — confirm order if attempt 1 succeeded, refund if both went through. Worst response is "payment failed, try again". Root fix: disable Pay after first tap + idempotency keys.
S10Card · code R1 · ₹999 · recurring · attempt 1
Reason: Revocation of authorization
Context: Monthly fitness app subscription
EXPECTED ROOT CAUSE
Mandate revoked or stopped
RETRY VERDICT
TIMING
Never retry; any new charge needs fresh customer consent
WHY
The customer went to their bank rather than just tapping a button in an app, which is about as clear as cancellation intent gets. High R1 rates often mean the merchant's cancel flow is hard to find.