PT Gajah Nusantara Raya (Internal Platform) · 2026
Building a reliable payment gateway integration with idempotent transaction handling
How idempotent API design and a retry-safe webhook handler made a financial transaction module resilient to third-party gateway failures and duplicate payment events.
Problem
A financial module needed to handle deposits, withdrawals, and payment gateway transactions reliably. Third-party payment gateways can send webhooks out of order, fail to deliver them, or send duplicates — any of which could result in a double charge, a missing transaction record, or an inconsistent wallet balance.
Solution
Designed all mutation endpoints with idempotency keys so that retries are safe by default. Built a webhook handler that validates, deduplicates, and processes payment events against the database state — and falls back to querying the gateway API directly when a webhook is missing or ambiguous.
Architecture
RESTful API built with Express.js and TypeScript. Wallet and transaction state lives in MySQL for relational integrity. Transaction metadata (gateway responses, webhook payloads) is stored in MongoDB for flexible schema. The API is deployed on a Linux server behind Nginx with PM2 for process management. CI/CD runs through GitHub Actions for automated deployments.
Challenges
Webhooks arriving out of order or not at all
Payment gateways don't guarantee webhook delivery order or even delivery at all. Implemented a reconciliation flow: if a transaction is pending for more than N seconds, the system polls the gateway API for the current status and updates accordingly.
Wallet balance consistency under concurrent requests
Concurrent withdrawal requests against the same wallet could result in a negative balance if both reads happen before either write. Solved with database-level locking and transactional update patterns to ensure balance checks and deductions are atomic.
Results
Deposit, Withdrawal, Transfer
Transaction types
Zero
Duplicate charge incidents
Fully automated via GitHub Actions
Deployment pipeline
Lessons Learned
- Idempotency is not a nice-to-have in financial systems — it's the difference between a recoverable bug and a customer support disaster.
- Don't trust webhooks alone. Always build a fallback reconciliation path against the source of truth (the gateway API).
- Database transactions and proper locking are non-negotiable when money changes hands.