Alfin
WorkCase StudiesExperienceAboutContact
Resume

Alfin

Full Stack Developer

WorkCase StudiesExperienceAboutContact

© 2026 Alfin. Built with Next.js.

All Case Studies

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.

Next.jsNode.jsExpress.jsTypeScriptMongoDBMySQLJWTNginxPM2

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.