Symptom
Payments intermittently return the previous transaction's result; or a customer is charged twice; or requests behave as if the terminal "remembered" an old transaction.
Root cause
The ServiceID was reused within a session. The terminal uses ServiceID to pair requests and responses and to protect against duplicates — send a request with an already-used ServiceID and the terminal may return the stored response for that ID instead of processing a new transaction. The classic bug: hardcoding ServiceID: "0" (or "1") on every request. It appears to work in single-shot tests and corrupts everything in sequence.
Fix
- Generate a unique ServiceID per request within the session — a monotonic counter is fine; persist it across POS restarts or re-Login on restart (a new session resets the rule).
- Audit every code path that builds a MessageHeader — copy-pasted request builders are how a hardcoded ID escapes into one operation.
- Re-run a sequential test: several payments back-to-back, verifying each response's ServiceID matches its request and each result is genuinely new.
The double-charge variant
If a customer was charged twice, the usual chain is: timeout → POS re-sent the payment with a new ServiceID (bypassing duplicate protection). The rule that prevents it lives in Timeout failures: never re-send; resolve with TransactionStatus.