Integrasi QRIS Dinamis di Aplikasi Kasir dengan Midtrans dan Laravel
Cara Integrasi QRIS di Aplikasi Kasir dengan Midtrans dan Laravel
Punya toko kafe, resto, atau minimarket dan mau terima pembayaran QRIS langsung dari aplikasi kasir kamu sendiri? Di 2026 ini, QRIS sudah punya sekitar 66 juta pengguna dan lebih dari 44 juta merchant di seluruh Indonesia, dengan transaksi menembus 12,55 miliar di semester pertama saja (data Bank Indonesia). Artinya, kalau aplikasi kasirmu belum support QRIS, kamu kehilangan mayoritas pelanggan yang sudah nggak bawa cash. Nah, di tutorial ini kita bahas cara integrasi QRIS di aplikasi kasir dengan Midtrans dan Laravel — fokus ke mode POS (generate QR dinamis per transaksi), bukan Snap checkout yang biasa dipakai di website e-commerce.
QRIS statis vs dinamis: kenapa dinamis?
Sebelum ngoding, kamu wajib paham bedanya. Bank Indonesia membagi QRIS MPM (Merchant Presented Mode) jadi dua jenis:
- QRIS statis — satu kode QR yang sama untuk semua transaksi, biasanya dicetak jadi stiker. Pelanggan scan, lalu input nominal sendiri di aplikasi dompet digital. Sederhana, tapi rawan salah ketik nominal dan susah dilacak per transaksi.
- QRIS dinamis — QR di-generate khusus untuk setiap transaksi, sudah memuat nominal. Satu QR hanya berlaku untuk satu pembayaran. Lebih aman (unik per transaksi), mengurangi risiko salah nominal, dan jauh lebih mudah direkonsiliasi.
Untuk aplikasi kasir POS, dinamis adalah pilihan yang benar. Alasannya sederhana: kasir butuh nominal terkunci, struk otomatis, dan audit yang rapi. Dengan QR dinamis, setiap QR punya order_id unik yang langsung cocok sama record transaksi di database. Kalau kamu belum punya aplikasi kasir sama sekali, mulai dulu dari tutorial membuat aplikasi kasir Laravel Vue.js yang sudah pernah kami tulis.
Sekarang, kenapa Midtrans? Karena Midtrans sudah terintegrasi sebagai acquirer GoPay dan ShopeePay untuk QRIS, sehingga satu QR dinamis yang kamu generate bisa di-scan oleh GoPay, ShopeePay, DANA, OVO, dan semua e-wallet QRIS-compliant lainnya. Kamu nggak perlu integrasi satu-satu ke tiap PSP. Detail lengkapnya ada di dokumentasi QRIS Midtrans.
Prasyarat: apa yang dibutuhkan
Sebelum mulai, pastikan kamu punya:
- Laravel 11 atau 12 terinstal (PHP 8.2+).
- Akun Midtrans — daftar di Midtrans dashboard, bisa pakai sandbox gratis untuk testing.
- Server Key dan Client Key dari Midtrans (Settings → Access Keys).
- Akun merchant QRIS yang sudah aktif di Midtrans (otomatis aktif kalau bisnis kamu sudah diverifikasi).
- Web server dengan HTTPS (wajib untuk webhook Midtrans). Untuk lokal, pakai ngrok atau expose.dev.
- Pengetahuan dasar Laravel: routing, controller, migration, dan queue jobs.
Kalau kamu mau langsung pakai sistem yang sudah jadi tanpa ngoding dari nol, ada aplikasi kasir POS siap pakai di Kios Koding yang bisa kamu jadikan baseline.
Langkah 1: Setup Midtrans dan API key
Pertama, tambahkan kredensial Midtrans ke .env Laravel kamu:
Pakai sandbox dulu (SB- prefix) selama development. Setelah production, ganti dengan production key dan set MIDTRANS_IS_SANDBOX=false.
Lalu buat service Midtrans sendiri (atau pakai package community seperti khumam/laravel-midtrans). Di tutorial ini, kita tulis service minimal supaya kamu paham alurnya:
Daftarkan binding di config/services.php:
Verifikasi koneksi dengan melakukan test charge kecil di sandbox. Kalau balik 201 dan ada transaction_status: pending, berarti setup kamu benar.
Langkah 2: Buat endpoint generate QR dinamis
Inti dari integrasi POS adalah memanggil POST /v2/charge dari backend Laravel. Setiap transaksi menghasilkan QR baru. Begini controllernya:
Beberapa hal penting dari kode di atas:
X-Override-Notificationwajib di-set kalau mau Midtrans kirim webhook ke URL spesifik (misalnya saat testing atau kalau kamu punya multiple environment). Ini khas mode POS, jarang dibahas di artikel Snap.acquirer: gopayberarti QR kamu bisa di-scan semua e-wallet QRIS — bukan hanya GoPay. Midtrans sebagai acquirer GoPay otomatis menerjemahkan ke standard QRIS nasional.order_idharus unik per transaksi. UUID + prefixTRX-sudah cukup.- Simpan
qr_stringke database supaya bisa di-render ulang kalau kasir butuh refresh tanpa call API lagi.
Response sukses mengembalikan actions array berisi URL gambar QR (generate-qr-code). Simpan URL itu — dipakai di langkah berikutnya.
Tambahkan route:
Alur lengkap POS integration ada di dokumentasi GoPay QRIS POS Integration Midtrans.
Langkah 3: Tampilkan QR di halaman kasir
Setelah endpoint generate jadi, frontend kasir tinggal POST ke /api/qris/generate, lalu render QR yang balik. Kalau kamu pakai Blade + sedikit JavaScript:
Untuk mode production yang serius, biasanya kasir auto-polling status transaksi tiap 2–3 detik sampai settlement. Tapi lebih efisien pakai webhook (langkah berikutnya) + WebSocket/Broadcast event ke kasir supaya real-time tanpa polling.
Tips praktis: tambahkan countdown timer berdasarkan validityPeriod QRIS (default 15 menit). Setelah expired, QR nggak bisa dibayar, jadi kasir harus generate ulang.
Langkah 4: Webhook untuk notifikasi pembayaran
Ini bagian yang sering bikin bug. Saat customer scan dan bayar, Midtrans akan POST HTTP notification ke URL yang kamu daftarkan (atau via X-Override-Notification). Berikut controller webhooknya:
Beberapa poin kritis:
- Signature key dihitung dengan
SHA512(order_id + status_code + gross_amount + server_key). Ini formula resmi Midtrans. Jangan skip verifikasi — tanpa ini, webhook kamu rentan dipalsukan. - Idempotency — Midtrans bisa kirim notifikasi yang sama berkali-kali (retry, atau settlement + fraud_status update). Cek status sekarang sebelum update.
- Return
200secepatnya. Midtrans expect response <30 detik. Kalau lambat, mereka retry. Kalau kamu butuh proses berat (cetak, kirim email), push ke queue. - Untuk production, daftarkan URL webhook di dashboard Midtrans (Settings → Configuration → Payment Notification URL) supaya Midtrans tahu ke mana POST.
Route webhook:
Penting: Laravel CSRF protection exclude route webhook. Tambahkan/api/midtrans/*ke$exceptdiapp/Http/Middleware/VerifyCsrfToken.php, atau pakaiapimiddleware group yang sudah tanpa CSRF.
Langkah 5: Cetak struk setelah settlement
Setelah webhook update status ke paid, langkah terakhir adalah cetak struk. Kalau kasir pakai thermal printer (misal Epson TM series), pakai escpos/php-printer:
Dispatch job ini dari event PaymentSettled:
Kenapa pakai queue? K karena thermal printer bisa nge-hang atau offline. Kalau synchronous, kasir stuck nunggu. Dengan queue, retry otomatis dan kasir bisa lanjut melayani customer berikutnya.
Tips: idempotency dan rekonsiliasi harian
Dua hal yang sering luput dari tutorial tapi kritikal di production:
Idempotency
Midtrans mengirim notification berkali-kali. Selalu cek status order sebelum update. Pakai pattern ini di webhook:
Atau lebih robust, simpan signature_key yang sudah diproses di cache:
Ini mencegah double-print struk, double-update inventory, dan double-emit receipt email.
Rekonsiliasi harian
Jangan cuma andalkan webhook. Webhook bisa gagal (network down, server maintenance). Bangun job rekonsiliasi harian yang membandingkan record database dengan status di Midtrans via API:
Jadwalkan dengan scheduler:
Tips tambahan
- Timeout handling — set
validityPeriodQR (default 15 menit). Kalau lewat, Midtrans kirim webhookexpire. - Logging — log semua webhook raw payload ke table
midtrans_notificationsuntuk audit trail. - Multi-outlet — kalau punya banyak cabang, gunakan satu Midtrans account tapi bedah
merchant_idper outlet, atau pakai akun terpisah. - MDR — QRIS transactions up to Rp 100.000 dapat MDR 0% dari Oktober 2026 (regulasi Bank Indonesia), jadi makin murah buat transaksi kecil.
Kesimpulan
Integrasi QRIS dinamis di aplikasi kasir Laravel kamu sebenarnya bukan hal yang rumit kalau paham alurnya: POST /v2/charge untuk generate QR → tampilkan di layar kasir → handle webhook settlement dengan signature verification → cetak struk via queue → jalankan rekonsiliasi harian untuk safety net. Yang membedakan implementasi POS dengan Snap checkout adalah per-transaksi QR generation, idempotency notification, dan coupling langsung ke proses fisik kasir (cetak struk, update inventory). Untuk developer Indonesia, ini skill yang high-demand karena QRIS sudah jadi standar pembayaran de facto — data Bank Indonesia mencatat transaksi QRIS tumbuh hampir 100% year-on-year di 2026.
Kalau kamu mau mulai dari source code yang sudah jadi dan tinggal kustomisasi, cek produk siap pakai di Kios Koding — termasuk aplikasi kasir POS yang sudah integrate QRIS. Atau kalau mau bangun sendiri, baca juga tutorial membuat aplikasi kasir Laravel Vue.js kami sebagai fondasi sebelum menambahkan payment gateway. Selamat ngoding, dan semoga transaksi QRIS di tokomu makin lancar!
Referensi & bacaan lanjutan:
Artikel Terkait
Mengapa UMKM Indonesia Butuh Aplikasi Mobile: Tren POS & E-Commerce Berbasis Flutter 2026
20 Sep 2026
7 Tech Stack Populer di Indonesia 2026 untuk Project UMKM & Startup
18 Sep 2026
Cara Deploy Laravel ke Shared Hosting cPanel: Panduan Lengkap 2026
18 Sep 2026
Build vs Buy: Kapan Pakai Source Code Siap Pakai vs Bangun dari Nol
18 Sep 2026