karawaci.kode

2026-06-10 · 7 min

QRIS Payment di SaaS Jakarta: Snap vs Direct Integration

Klien SaaS subscription Jakarta saya (B2B, ~600 paying tenant, MRR Rp 180jt) request QRIS sebagai alternative bank transfer 5 bulan lalu. Saya pilihan: Midtrans Snap (jalur cepat, MDR sedikit lebih mahal) atau direct integration ke acquirer (lebih murah, effort lebih). Saya try Snap dulu, lalu evaluate. Hasil real.

Setup awal: Midtrans Snap

Decision driver: ship dulu, optimize belakangan. Klien butuh QRIS live dalam 3 minggu.

Implementation:

  • Backend: webhook receiver di Bun + Hono (related: Bun 1.3 di payment gateway warung)
  • Frontend: Snap.js embed di Next.js
  • Reconciliation: cronjob nightly compare Midtrans report vs internal ledger

Effort: 4 hari. Saya billed Rp 16jt ke klien.

Yang Snap kasih:

  • QRIS dynamic (per-transaksi)
  • E-wallet (GoPay, ShopeePay, DANA, OVO)
  • Bank transfer virtual account
  • Card payment

Semua dalam satu integration. Klien tidak ribet daftar acquirer terpisah.

Cost: Midtrans Snap 5 bulan pertama

Volume transaksi: ~2,400 transaksi/bulan, average Rp 480k/transaksi (subscription monthly + annual).

Total volume bulanan: Rp 1,15 miliar.

Midtrans Snap MDR untuk QRIS: 0,77% (per 2026 rate card) Per transaksi avg fee: ~Rp 3,700 Monthly fee total: ~Rp 8,9jt

Plus Midtrans monthly minimum (saat itu Rp 0 untuk volume ini, tapi ada flat fee untuk Snap dashboard akses): Rp 200k/mo.

Total Midtrans cost: ~Rp 9,1jt/bulan

Latency Snap

Customer flow: click “bayar QRIS” → Snap popup → scan QR → payment app process → webhook ke server saya.

  • Snap popup load: P50 1,2 detik, P95 2,8 detik (depend on Indihome/Telkomsel client side)
  • QR generation: P50 1,8 detik (Snap call ke acquirer)
  • Webhook notification: P50 12 detik setelah user bayar (acquirer → Midtrans → my server)

Total time-to-confirmation user: median ~25 detik. Acceptable. Kompetitor saya yang langsung ke acquirer claim ~15 detik, tapi belum saya verify.

Decision: try direct integration

Setelah 4 bulan Snap, klien tanya: “bisa lebih murah?”. Volume sudah lumayan. Saya assess:

Direct integration ke acquirer (saya coba: BCA QRIS Merchant API):

  • MDR: 0,3% (cap BI untuk UMKM) — tapi klien bukan UMKM, jadi 0,7%
  • Setup fee BCA: Rp 5jt one-time
  • Monthly fee: Rp 350k untuk corporate account
  • Settlement: T+1 ke rekening BCA

Saya prototype 2 minggu (parallel project). Effort lebih besar:

  • BCA punya proprietary API yang dokumentasi-nya bisa diakses setelah onboarding
  • Webhook signing pakai HMAC, bukan setarakan Snap
  • Reconciliation file daily harus parse fixed-width format (lama-lama era)
  • Tidak ada SDK official untuk Node/Bun; saya nulis client dari scratch

Total effort prototype + production-ready: 14 hari. Billed Rp 56jt ke klien.

Cost: direct integration 1 bulan running

Bulan ke-5 saya cutover 50% traffic ke direct BCA. Result:

  • Volume direct: Rp 575jt
  • MDR direct: 0,7% = Rp 4jt
  • Plus BCA monthly: Rp 350k
  • Cost: Rp 4,35jt untuk 50% volume

Proyeksi full direct: Rp 8,7jt/bulan untuk 100% volume.

Saving vs Midtrans: Rp 9,1jt - 8,7jt = Rp 400k/bulan saving.

Hmm. Tidak signifikan. Break-even setup cost (Rp 56jt) di 140 bulan. Tidak masuk akal.

Reality check

Saya kasih klien data ini. Klien marah sebentar (sudah bayar Rp 56jt prototype), tapi paham. Keputusan: keep Midtrans Snap untuk most flow, BCA direct untuk B2B annual subscription (high-ticket, Rp 5jt+) where MDR saving lebih material.

Hybrid pattern:

  • Snap untuk transaksi < Rp 1jt: kemudahan + UX > saving
  • BCA direct untuk transaksi > Rp 5jt: 0,7% dari Rp 5jt = Rp 35k saving per transaksi, worth-it

Yang break (Snap)

  1. Webhook delivery delay: 2x dalam 5 bulan Midtrans webhook delay > 1 jam. User udah bayar, status di app pending. Customer support kena. Fix: tambah polling /v2/{order-id}/status setiap 30 detik sebagai backup.

  2. Snap popup blocked: 4 customer report popup di-block browser. Sebelum bayar mereka harus allow popup. Fix: kasih instruksi UI sebelum click “bayar”.

  3. Currency precision: Snap kirim amount as integer (cents-style). Saya pernah salah convert dan amount Rp 478,500 jadi Rp 47,850. Test case yang gak ketangkap. Customer marah, saya refund + apology.

Yang break (BCA direct)

  1. Settlement format: file rekonsiliasi harian dari BCA pakai EBCDIC-encoded fixed-width. Saya butuh parse khusus. Bug pertama: tanggal misalign 1 kolom. Manual reconcile 3 hari sampai fix.

  2. HMAC signature: saya salah pakai SHA-256 hex lowercase vs uppercase. Webhook saya validate gagal 100% selama 2 hari. Beruntung BCA retry webhook sampai 3x.

  3. Maintenance window: BCA punya maintenance Minggu 02:00-04:00 WIB. User yang bayar saat itu, QR expired silent. Saya tambah fallback ke Snap untuk window itu.

Verdict

Untuk SaaS Indonesia dengan volume < Rp 2 milyar/bulan: pakai aggregator (Midtrans, Xendit, Doku). Engineering cost saving > MDR saving.

Direct integration ke acquirer make sense kalau:

  • Volume > Rp 5 milyar/bulan
  • Punya tim engineering dedicated untuk maintain integration
  • Klien dengan transaksi high-ticket (B2B enterprise)

Bukan magic — saya buang effort Rp 56jt untuk discover ini. Kasih ke developer Indonesia lain supaya ga ulang mistake. Data dulu, bukan asumsi vendor selalu paling mahal.

Ditulis oleh Reza Pradipta