SaaS Recurring Billing in Indonesia: Midtrans and Xendit

Kepemilikan kartu kredit di Indonesia rendah, dan kebanyakan orang membayar lewat e-wallet atau QRIS. Default card-on-file akan mengecualikan mayoritas pelanggan kamu. Kamu butuh gateway yang menokenisasi instrumen lokal dan alur cadangan untuk rail yang hanya sekali bayar.
Ya. Midtrans punya Subscription API yang menarik dana otomatis pada interval tertentu memakai tokenisasi kartu dan tokenisasi GoPay. Xendit menawarkan produk Subscriptions dengan paket fixed-amount dan usage-based, pemulihan retry untuk pembayaran gagal, serta webhook untuk tiap siklus penagihan.
Tidak. QRIS adalah rail merchant-presented sekali bayar di mana pelanggan memindai dan menyetujui tiap pembayaran. Untuk pengguna QRIS kamu tidak bisa menagih ulang diam-diam, jadi kamu mengirim notifikasi perpanjangan dan tautan pembayaran baru tiap siklus alih-alih penarikan otomatis.
Dunning adalah proses otomatis untuk mencoba ulang penagihan perpanjangan yang gagal dan mengingatkan pelanggan. Di Indonesia, saldo e-wallet habis dan kartu kedaluwarsa cukup sering, jadi perpanjangan rutin gagal. Urutan retry-dan-pengingat dengan masa tenggang penting agar tidak kehilangan pelanggan berbayar.
Gateway mengirim hasil secara asinkron dan me-retry webhook, jadi event yang sama bisa datang dua kali atau tidak berurutan. Jika handler kamu tidak idempoten, kamu bisa menagih dua kali atau memberi akses ganda. Lakukan dedupe pada event id gateway dan buat pemrosesan ulang event yang sama menjadi no-op.

Ringkasan Utama
Artikel ini menjelaskan cara membangun billing langganan SaaS di Indonesia menggunakan gateway lokal Midtrans dan Xendit. Dibahas tokenisasi untuk card-on-file, mesin status langganan berupa aktif, past due, dan canceled, proration dan retry dunning, penanganan QRIS serta e-wallet yang sifatnya sekali bayar, plus webhook dan idempotency agar perpanjangan berjalan andal.
Menagih kartu satu kali itu mudah. Menagih pelanggan yang sama secara otomatis tiap bulan, terus-menerus, tanpa ada yang mengklik apa pun, adalah masalah yang berbeda. Itulah inti sebuah langganan, dan di Indonesia hal ini lebih sulit dari yang disiratkan tutorial Stripe.
Kebanyakan pelanggan Indonesia tidak membayar dengan kartu kredit tersimpan. Mereka membayar lewat QRIS, GoPay, OVO, DANA, ShopeePay, atau transfer bank. Rail ini dirancang untuk pembayaran sekali jalan, bukan untuk merchant yang menarik dana secara diam-diam bulan depan. Membangun billing SaaS di sini berarti memahami rail lokal mana yang mendukung tagihan berulang, dan merekayasa solusi untuk yang tidak mendukungnya.
Penetrasi kartu di Indonesia rendah, dan sebagian besar belanja digital mengalir lewat e-wallet dan QRIS ketimbang kartu kredit. Recurring billing mengasumsikan kebalikannya: instrumen tersimpan yang bisa ditagih merchant lagi tanpa kehadiran pelanggan. Ketika metode pembayaran dominan adalah kode QR yang dipindai pengguna setiap kali, model card-on-file yang jadi andalan SaaS Barat sama sekali tidak cocok.
Akibatnya, kamu tidak bisa sekadar menyalin alur langganan Stripe. Kamu butuh gateway yang mendukung merchant-initiated transaction di rail lokal, cara untuk tokenisasi instrumen apa pun yang dimiliki pelanggan, dan rencana cadangan untuk porsi besar pengguna yang metode bayarnya memang hanya bisa sekali pakai.
Dua gateway lokal menutupi sebagian besar pasar. Midtrans menyediakan Subscription API yang menarik dana otomatis pada interval tertentu; fitur recurring-nya dibangun di atas tokenisasi kartu, di mana alur One Click dan Two Clicks menyimpan detail kartu sebagai token, dan juga mendukung tokenisasi GoPay untuk tagihan berulang berbasis dompet. Secara teknis, Midtrans memperlakukan recurring dan one-click sebagai fitur token tersimpan yang sama, dan satu-satunya perbedaan adalah apa yang memicu penagihan.
Xendit menawarkan produk Subscriptions yang mengelola paket fixed-amount dan usage-based dengan jadwal mingguan, bulanan, atau tahunan. Kamu menentukan nominal, jadwal, dan opsi pemulihan untuk pembayaran gagal, lalu Xendit menangani penarikan dana sambil mengirim webhook seperti event retrying saat percobaan gagal dan event succeeded saat satu siklus berhasil; ia butuh minimal satu payment channel yang mendukung merchant-initiated transaction. QRIS sendiri, yang distandarkan Bank Indonesia, adalah rail merchant-presented sekali bayar, sehingga tidak ada gateway yang bisa menagih ulang scan QRIS secara diam-diam dan ia menjadi titik perpanjangan manual, bukan instrumen recurring sejati.
Gateway mana pun yang kamu pilih, simpan token dan subscription id milik gateway terhadap pengguna kamu sendiri, jangan pernah menyimpan kredensial kartu atau dompet mentah. Tokenisasi menjaga data sensitif tetap di luar server kamu dan justru itulah yang membuat penagihan merchant-initiated di kemudian hari menjadi mungkin.
Sebuah langganan adalah mesin status kecil, dan menetapkan status serta transisinya dengan benar adalah sebagian besar pekerjaannya. Modelkan secara eksplisit, bukan menyimpulkan status dari baris pembayaran yang berserakan.
Pembayaran bersifat asinkron. Pelanggan menyetujui di aplikasi dompet atau memindai QR, dan server kamu baru mengetahui hasilnya belakangan lewat webhook, bukan lewat respons API sinkron. Perlakukan webhook sebagai sumber kebenaran apakah satu siklus berhasil, dan jangan pernah menandai langganan aktif hanya karena kamu mengirim permintaan penagihan.
Webhook melakukan retry dan bisa datang lebih dari sekali atau tidak berurutan, jadi setiap handler harus idempoten: lakukan dedupe berdasarkan event atau order id dari gateway dan buat pemrosesan event yang sama dua kali menjadi no-op. Midtrans mendukung idempotency key saat membuat langganan, sehingga permintaan create yang di-retry mengembalikan hasil yang sama alih-alih duplikat. Lakukan rekonsiliasi harian dengan menarik daftar transaksi gateway dan membandingkannya dengan ledger kamu sendiri untuk menangkap webhook yang terlewat.
Jangan pernah mempercayai webhook tanpa memverifikasi tanda tangannya, dan jangan pernah mengubah pengguna menjadi berbayar hanya berdasarkan permintaan. Webhook palsu atau yang di-replay dan kamu proses membabi buta bisa memberi akses gratis atau menagih pelanggan dua kali.
Mode kegagalan di sini spesifik untuk pasar lokal. Rancang untuk menghadapinya sejak awal, bukan menambal setelah perpanjangan pertama gagal.
Recurring billing SaaS di Indonesia lebih soal kenyataan bahwa kebanyakan pelanggan tidak bisa ditagih ulang secara diam-diam ketimbang soal API pembayaran. Pilih gateway yang menokenisasi instrumen yang benar-benar dimiliki pengguna, modelkan langganan sebagai mesin status yang eksplisit, dan buat setiap webhook idempoten serta terekonsiliasi. Ketika card-on-file mustahil, ubah perpanjangan menjadi alur notifikasi-plus-tautan yang andal.