Reversal: One Nuance That Actually Matters
Table of contents
This is the first of two short unhappy-path posts following the approved payment walkthrough – same mock, same Postman collection, same PIN-entry mechanic for the original payment this reverses. Setup is already covered in the mock terminal post; not repeated here.
Objective
Reverse a previously authorised payment, confirm the response shape, and check what the mock actually validates about the transaction being reversed.
Request sent
POST {baseUrlMock}/sync, MessageCategory: Reversal, referencing the prior Payment’s identifiers (auto-filled by the collection’s chaining variables, confirmed populated in the previous post):
"ReversalRequest": {
"ReversalReason": "MerchantCancel",
"OriginalPOITransaction": {
"POIID": "{poiId}",
"POITransactionID": {
"TransactionID": "{lastTransactionId}",
"TimeStamp": "{lastTimestamp}"
}
}
}
Actual result
200 OK, immediate (no PIN-entry wait – only Payment requests block on that):
{
"SaleToPOIResponse": {
"ReversalResponse": {
"POIData": { "POITransactionID": { "TimeStamp": "2013-06-12T12:08:36+00:00", "TransactionID": "21f1268f-9126-4bce-b127-9c2d5ffa024e" } },
"Response": { "Result": "Success", "AdditionalResponse": ".+" },
"PaymentReceipt": [ "fake cashier + cardholder receipt, TOTAL €10.99, card ending 9990" ]
},
"MessageHeader": { "SaleID": "SALE_ID_42", "ServiceID": "1234567890AB", "POIID": "V400m-123456789", "MessageCategory": "Reversal", "MessageType": "Response" }
}
}
Same static-fixture pattern as the approved payment – full proof already in the previous post’s appendix; not repeated here.
Screenshot

Request body showing {lastTransactionId}/{lastTimestamp} referencing the prior Payment, response 200 OK in 3ms (no PIN wait), Result: Success.
Test mode vs. real life
The important nuance here is ID reuse. In this test, OriginalPOITransaction.POITransactionID (TransactionID + TimeStamp) is populated automatically from the last Payment, but confirmed in the mock’s own routing code that it’s never actually checked – the mock returns Success for a Reversal referencing any value, including one that never existed.
In real life, this is exactly backwards: OriginalPOITransaction must precisely match a real, previously-authorised transaction on that terminal – it’s how the terminal (and Adyen behind it) identifies which transaction to reverse. Get it wrong and a real terminal returns an error (e.g. “original transaction not found”), not a silent success. TransactionID/TimeStamp from a genuine prior authorisation are mandatory inputs, not decorative fields – same category as ServiceID in the main flow, just enforced at a different layer (the terminal/Adyen, not the message schema).
Also worth knowing generally (not verified against this mock, since it doesn’t implement any timing logic at all): real reversals are typically only valid for a limited window – before the original transaction is captured/settled. Once settled, a refund is needed instead, which is a different message/flow entirely. Worth confirming against Adyen’s own docs when this becomes relevant against a real terminal.
Net takeaway: this test confirms the request/response shape for Reversal and that the collection’s chaining variables wire up correctly – it does not, and cannot, tell us anything about real transaction-matching behaviour. Familiarization with the message contract only.
See also
Insufficient balance decline – the other short unhappy-path scenario in this series, using the same approved-payment request with one digit changed.
Until next time, peace and love!