Behind the scenes: Preventing double charges in payment gateway integrations
Idempotency architecture and webhook handlers to keep invoice statuses accurate even through network glitches.
Integrating a payment gateway to accept virtual accounts or QRIS payments looks deceptively straightforward on paper: a customer pays, the gateway fires an asynchronous webhook, and your application marks the invoice as “Paid”.
In the real world of banking networks and mobile telecommunications in Indonesia, clean conditions are the exception rather than the rule. A gateway server might send duplicate webhooks because network congestion triggered its retry logic, or an end user might tap the payment button multiple times on an unstable cellular connection.
If your backend is not designed for these edge cases, your business risks deducting stock twice, duplicating customer account balances, or corrupting general ledger entries.
Engineering an idempotent architecture
To guarantee flawless financial reconciliation without requiring finance teams to resolve daily discrepancies by hand, we engineer three technical safety layers:
1. Deterministic idempotency keys
Every payment intent sent from the client carries a unique deterministic key. If a customer repeatedly taps the submission button during momentary lag, the server processes only the first request and safely discards identical subsequent payloads.
2. Strict state machines and row-level locking
Order progression is guarded by an unyielding state machine: Pending → Processing → Completed. Any transaction that reaches Processing or Completed establishes an atomic lock on the corresponding database record. When a delayed duplicate webhook arrives seconds later, the system verifies the existing state and responds with a successful acknowledgment without triggering duplicate inventory deductions or accounting credits.
3. Raw payload audit logs
Every inbound webhook payload is archived verbatim in an immutable audit table prior to execution. This allows accounting and treasury teams to audit any monthly bank statement against the raw gateway transaction reference at any moment down to the last rupiah.
Systems engineered for messy data
This resilience is why internal business systems should never assume that networks will behave cleanly. True engineering quality reveals itself in how gracefully a system handles edge cases without puzzling the end user.
If your company struggles with manual payment reconciliation or needs to integrate rock-solid automated billing, explore our business systems solutions, read how we handled data architecture in the Hailmary Terminal case study, or reach out to our engineers.