Bogor GMT+7

Consultation
← All articles

Behind the scenes

Behind the scenes: Preventing double charges in payment gateway integrations

Idempotency architecture and webhook handlers to keep invoice statuses accurate even through network glitches.

Published
Reading time
3 min read
Author
Hailmary Studio
Customer making a cashless digital payment at a tablet checkout counter

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.