← All case studies
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