Backend APIs & PaymentsFull-Stack Web Apps
Payment Gateway Migration to Xendit Payments API v3
Moved an edtech checkout to Xendit Payments API v3 without breaking the Midtrans channels running next to it.
- Request
- Payment
- Deploy
- Event
- AI
Context
Satu Persen sells courses, psychological consultations, and public trainings to Indonesian learners.
Problem
Xendit asked us to move off its legacy per-channel APIs: staying meant extra maintenance fees and a weaker security model than Payments API v3. The migration had to happen while payments kept flowing, with Midtrans channels running next to it, and customers saw no clear message when a gateway rejected a channel.
What I did
- Implemented Xendit Payments API v3 payment requests in the Spring Boot commerce module for OVO, DANA, LinkAja, BSI and Sampoerna virtual accounts, and Indomaret, behind a per-channel switch.
- Built the v3 webhook handler: verifies the callback token with a constant-time compare, re-confirms success with Xendit, and never downgrades a finished order, so retried webhooks are safe.
- Extended the change-payment-method flow so the customer’s draft carries over when the old order is replaced by a new one on the chosen channel.
- On the Nuxt checkout, hid channels the gateway rejects, added per-channel amount limits, and added a clear popup when the gateway declines a channel (currently on staging).
- Verified with staging smoke tests and read-only production database audits.
Next case study
Checkout & Payment Webhook Performance