/obydul
Back
payments3 min read

Chargeback Evidence in One Lookup

Fighting a chargeback meant hours of copy-paste per dispute. Built a tool that fills a 10-section evidence packet from one lookup, with card scheme liability rules coded in because the gateway API does not tell you.

paymentsfraudautomation
Outcome
  • Packet build: hours of copy-paste down to one lookup plus review
  • 10 evidence sections filled automatically from order data and 3 gateway calls
  • Card scheme liability-shift rules coded in, not guessed per case

When a customer disputes a card payment, the money is taken back unless the merchant answers with evidence. That answer is called a representment packet. For digital goods it must prove the buyer is real, the product was delivered and the card holder authorized the payment.

The problem

Staff built each packet by hand. Query the database for the order, open the gateway dashboard for the 3DS data, dig through logs for delivery proof, paste everything into a document. Hours per dispute. Quality depended on who wrote it. Disputes never stop coming.

One lookup

I built an internal page that takes a payment id and fills a 10-section packet automatically: case summary, 3DS authentication, card checks, account history, device and session data, delivery proof, KYC records, internal fraud review, prior-purchase evidence and a closing statement.

flowchart LR L[One lookup] --> DB[(Order data)] L --> API[3 live gateway calls<br/>in parallel] DB --> P[10-section packet] API --> P P --> PDF[Print to PDF<br/>+ audit trail]

Data comes from two places. Our own records cover the order, the customer's history, delivery logs and KYC. Three live gateway API calls fetch the payment, its action timeline and the dispute itself. Each call fails independently, so one slow endpoint never blocks the rest of the packet.

The rules the API does not give you

The strongest defense in a fraud dispute is liability shift: if the bank authenticated the payment with 3DS, the bank owns the fraud risk, not the merchant. The gateway API does not return a liability flag. So I coded the card scheme rules directly:

SignalResult
Auth response N, U, R or INo shift, overrides everything
Visa or Amex, ECI 05 or 06Shift to issuer
Mastercard, ECI 01 or 02Shift to issuer
ECI 00 or 07No shift

Same story with Visa CE 3.0, a rule that lets merchants win friendly-fraud cases by showing 2 or more prior undisputed orders from the same customer. The tool finds them automatically in the 120 to 365 day window. My first version accepted any 2 prior orders. Reading the actual rule showed it needs an IP or device match, so I tightened it. A packet that claims more than the rules allow loses credibility on every future case.

Small things that decide cases

  • Evidence must outlive the dispute. KYC images came as signed links that expire in hours, but a packet gets reviewed months later. Every image is copied to our own storage before it goes in.
  • A fill counter per section shows staff exactly what still needs manual input, so nothing ships half empty.
  • Every edit is logged. Who created, edited and submitted each packet sits in an audit trail next to the evidence itself.

Result

Building a packet went from hours of copy-paste to one lookup plus a short manual review. Every packet has the same structure, cites the same scheme rules and prints to a clean PDF the bank reviewer can follow.