ISO 8583 Parser
Free Β· Deep dive Β· ~15 min read

Reversals, Timeouts & Repeats: The ISO 8583 Failure Paths

Anyone can code the happy path: request in, approve, respond. What actually wakes you at 3 a.m. is the failure path β€” a response that timed out, a message that got re-sent, money debited with no order created, a hold that never clears. ISO 8583 has explicit machinery for all of it: 0400 / 0420 reversals, the MTI repeat digit, DE90 original data elements and DE95 replacement amounts. This guide covers the mechanics, what each side must implement, and ends with a production troubleshooting checklist.

1. Why reversals have to exist

An authorization carries state. The instant the issuer approves a 0100, the cardholder's available balance drops by that amount (a hold), and it stays held until the transaction clears or the auth expires. That creates one fundamental problem:

Approved β€” but the acquirer never learned it was approved. The issuer believes funds are held and the transaction happened; the acquirer timed out, decided it failed, and told the merchant "declined". The two sides now disagree, and the cardholder always loses: money held, nothing bought.

A reversal is the mechanism that removes that disagreement: the originator tells the other side "that last one didn't happen β€” roll the state back." It is not a refund and not a new purchase; it is an instruction to undo one specific original transaction.

2. The message family: 0400 / 0410 / 0420 / 0430

Line up the MTI's second digit (message class) first: x1xx = authorization, x2xx = financial, and x4xx = reversal / chargeback. The third digit (function) separates a request from an advice:

MTINameMeaning / when
0400Reversal requestAcquirer asks to undo the original and waits for an answer. The other side may in principle refuse (rare in practice).
0410Reversal responseThe answer to a 0400; DE39 carries the outcome.
0420Reversal adviceA notification of a done deal: "I have already reversed it; you must too." The receiver cannot refuse β€” only acknowledge.
0430Reversal advice responseAcknowledges the 0420. If it doesn't arrive, the advice must be re-sent.

Choosing 0400 vs 0420 is not a style preference. The test is: has the state change already happened on your side? If you merely *want* to undo it, send 0400 (a request). If you have already voided it locally, taken no money and booked it that way, you must send 0420 (an advice) β€” because you can no longer un-void it just because the other side said no. The classic failure is sending 0400, getting a decline, and being stuck: unable to reverse and unable not to.

The advice rule: keep sending until acknowledged. Delivery of an advice such as 0420 is the sender's responsibility β€” no 0430 means re-send with backoff (flagged as a repeat) until it lands. Which is exactly why the issuer side must be idempotent β€” see section 6.

3. A repeat is not a reversal: the MTI's fourth digit

This is the pair beginners conflate most often, and a rich source of incidents. A repeat re-sends the same transaction; a reversal sends a new message to undo it.

ISO 8583 marks repeats in the MTI's fourth digit (message origin):

4th digitMeaningExample
0Acquirer0400
1Acquirer repeat0401 / 0421
2Issuer0422
3Issuer repeat0423
4Other0424
5Other repeat0425
The repeat rule: nothing changes except the MTI's fourth digit. In particular DE11 (STAN) and DE7 (transmission date/time) must keep their original values. A great many "double charge" incidents trace back to a retry that helpfully generated a fresh STAN β€” to the receiver that is two distinct transactions, so it debits twice.

When to repeat, when to reverse? In one line: unsure whether they processed it β†’ repeat and ask again; sure they processed it but you no longer want it β†’ reverse. The common production pattern is "repeat N times, still nothing, then reverse" rather than reversing immediately β€” because a repeat is harmless if the receiver is idempotent.

4. DE90: how a reversal finds its original

A reversal cannot just say "undo the last one" β€” the issuer may be handling thousands in the same second. It must carry enough identity to locate the original, and that is DE90, Original Data Elements: a fixed 42-digit field made of five parts:

OffsetLenContent
1–44Original MTI (e.g. 0100 / 0200)
5–106Original DE11 STAN
11–2010Original DE7 transmission date & time, MMDDhhmmss
21–3111Original DE32 acquiring institution ID (zero-padded)
32–4211Original DE33 forwarding institution ID (zeros if none)

Paste those 42 digits into the parser and it splits them for you. Three frequent mistakes:

Beyond DE90, a reversal normally echoes DE2 (PAN), DE3 (processing code), DE4 (amount), DE37 (RRN) and DE41/42 (terminal/merchant) so the receiver can cross-check. On several networks DE37 RRN is the actual primary match key, with DE90 as the fallback β€” check the counterparty's spec.

5. Partial reversals and DE95

Not every reversal is all-or-nothing. Classic cases: a fuel pump pre-auth of 150 where the customer actually pumped 92.40, or a restaurant pre-auth padded for tip that settles lower. You want to release the over-held portion, not cancel the whole thing β€” that's a partial reversal.

It travels in DE95, Replacement Amounts β€” fixed 42 characters in four parts:

LenContent
12Replacement transaction amount (mirrors DE4)
12Replacement settlement amount (mirrors DE5)
12Replacement cardholder billing amount (mirrors DE6)
6Replacement cardholder billing fee (mirrors DE8)
Get the direction right: DE95 carries "what it should become", not "how much to take off". Pre-auth 150, actual 92.40 β†’ the transaction-amount part is 000000009240 (the remainder), not 60.60 (the difference). Sending the difference is a classic incident: the issuer resets the hold to 60.60 and the cardholder is left with 90 mysteriously held.

And amounts are always integers in the currency's minor unit, left zero-padded β€” the yen has no decimals, the dinar has three; never blanket-multiply by 100. See why amounts have no decimal point.

6. Timeouts: three cases, only one is safe to retry

To the acquirer a timeout is one symptom: sent, no answer. Underneath it can be three completely different states β€” and the acquirer cannot tell which:

CaseIssuer's actual stateCorrect action
A. Request lost in transitNothing happened, no holdRepeat is safe
B. Response lost on the way backApproved, funds heldMust reverse, else an orphaned hold
C. Issuer slow, response arrives lateApproved; arrives after you gave upMerchant already told "failed" β†’ reverse too

Since you can't distinguish them, the industry norm is to over-reverse rather than under-reverse: repeat first, then send a reversal if still nothing. Even if the original never reached the issuer (case A), the issuer receiving an unmatchable reversal still answers successfully and records it β€” an "unmatched reversal" is normal, not an error.

Key issuer-side design: a reversal should answer DE39=00 almost unconditionally. Even with no original to match, record an "unmatched reversal" and approve β€” do not answer 25 (unable to locate record). The practical reason: a failed reversal makes the acquirer retry forever, saturating your link, and the states still disagree. An unmatched reversal is something you resolve in reconciliation, not grounds for rejecting the other side.

Also mind stand-in processing (STIP) when the issuer is unavailable (DE39=91): the network decides on the issuer's behalf and informs it afterwards with a 0120 / 0220 advice. Those are likewise faits accomplis β€” the issuer must book them, not refuse them. See the DE39 reference.

7. Idempotency: choosing the dedup key

Since both repeats and reversals can arrive more than once, the receiving side must be idempotent. The question is what the unique key is. DE11 STAN alone is not enough: six digits, unique only within a day by definition, guaranteed to recycle across days and liable to collide between terminals at peak. The composite key used in practice:

The dedup window must cover the counterparty's retry policy plus the day cutover β€” 24–48 hours is typical β€” and it must cache the response too: a duplicate must get back byte-identical results (same DE39, same DE38 auth code), not a fresh decision. Re-deciding produces the bizarre inconsistency of "approved first time, insufficient funds on the retry".

8. Reversal vs void vs refund vs chargeback

These four get used interchangeably in conversation, but at the message level they are four different things, with different money paths and timing:

ActionMessageWhenOn the statement
Reversal0400/0420Before clearing, seconds to minutesThe original never appears; the hold just drops
VoidUsually 0400, or a 0200 with a void processing codeSame day, before captureSame β€” usually never hits the statement
Refund0200 with processing code 20xxxxAfter clearing, any timeTwo entries: the purchase and a credit
Chargeback0442/0432 and other dispute messagesAfter clearing, within network time limits (often 120 days)Two entries, plus a dispute process

The single most useful line for ops and support: reverse if you still can, refund only if you must. A reversal completes before clearing β€” the statement stays clean and the balance frees instantly. A refund is a new credit transaction that must clear in full: the cardholder waits days, sees two lines, and on cross-border transactions can lose money on the exchange rate because the amount is converted twice.

9. When a reversal is lost: the orphaned hold

If a reversal never lands β€” retries exhausted, or never sent at all β€” the issuer is left holding funds against a transaction that will never clear: an orphaned hold or dangling authorization. Symptoms:

The safety net is auth expiry: the issuer gives each hold a lifetime (7 days typically, 30 for hotels and car rental) and releases it automatically if nothing clears. But that's a backstop, not a fix β€” the cardholder waits a week. The real answer is all three of:

  1. A durable pending-reversal queue on the acquirer side: persist the intent the moment you decide to reverse, survive restarts, and let a background worker drive it to success β€” rather than a request thread retrying a few times and giving up.
  2. End-of-day handling of unmatched reversals on the issuer side: keep them, re-match against the auth log at cutoff (a late-arriving original will pair up then) and release when they do.
  3. Active monitoring: count hourly the authorizations with neither clearing nor reversal after N hours. When that curve lifts, some link is dropping reversals. If you wait for complaints, there are usually hundreds already.

10. Production troubleshooting checklist

Given a "reversal didn't work" message in hand, walk these in order β€” nine times out of ten it lands:

  1. Is the MTI right? 0400 or 0420 β€” is your case a request or a fait accompli? Is the fourth digit accidentally flagged as a repeat?
  2. Split DE90's 42 digits and check each part: is the MTI the original's? Is the STAN the original's or a new one? Did the date cross midnight? Are the institution IDs padded to 11?
  3. Does DE37 RRN match the original? Many networks match on RRN; a changed RRN guarantees a miss.
  4. Amount: full or partial? For a full reversal DE4 must equal the original. For a partial, check DE95 carries the remaining amount, not the difference, in minor units.
  5. What is the response DE39? 00 means they took it (so your own state machine is the issue); 25 means the match failed (back to steps 2–3); 91 means their host is down (switch to advice and re-send).
  6. Time window: is it past the counterparty's reversal deadline? Beyond it, refund or dispute is usually the only route left.
  7. Was a repeat treated as a new transaction? Diff DE11/DE7 across the two messages: if they differ, that wasn't a repeat β€” it was a genuine second transaction.
Check it yourself: paste the reversal and the original into the ISO 8583 parser separately, then line up DE90's five parts against the original's MTI / DE11 / DE7 / DE32 / DE33. Nearly every mismatch reveals itself immediately as one misaligned part.

In short

β†’ Decode a reversal in the parser