Dokumentasi API MauPay

🔗 Dokumentasi Lanjutan: butuh panduan integrasi yang lebih lengkap? Kunjungi dokumentasi lanjutan kami →

Base URL & Autentikasi

Base URL — klik untuk membuka, atau gunakan tombol salin:

Semua endpoint mengembalikan JSON. Autentikasi memakai header X-API-Key.

Gunakan API key live (sk_live_...) untuk produksi dan key sandbox (sk_test_...) untuk pengujian.

Autentikasi

Kirim API key Anda lewat header X-API-Key pada setiap permintaan.

X-API-Key: sk_live_...

API key Anda (sk_live_... untuk produksi, sk_test_... untuk sandbox) dan webhook secret tersedia di halaman Beranda dashboard. Status pembayaran dipantau lewat webhook dan halaman Riwayat.

1. Payment Link & Gateway — QRIS

Buat pembayaran

POST https://app.maupay.online/api/v1/payments

Header: X-API-Key: sk_live_... (untuk sandbox pakai sk_test_...).

{ "amount": 132000, "customer_name": "Budi", "merchant_ref": "INV-2026-001", "metadata": { "key": "value" } }
ParameterTipeWajibKeterangan
amountintegerYaNominal dasar, 100 — 10.000.000
customer_namestringTidakNama pelanggan (maks 120 karakter)
merchant_refstringTidakNomor order/id dari sistem Anda (maks 100 karakter). Dikirim balik pada respons dan setiap webhook PAID untuk mencocokkan transaksi ke order Anda.
metadataobjectTidakObjek JSON bebas yang Anda pilih untuk identifikasi order (maks 2000 karakter). Contoh di atas (mis. "sku") hanyalah ilustrasi — sistem tidak menghasilkan atau mewajibkan kunci apa pun; isi terserah Anda dan hanya dikirim balik mentah pada webhook PAID.
AturanNilai
Nominal dasarinteger, 100 — 10.000.000
Masa berlaku30 menit — setelah itu status EXPIRED
Kredit saldoberdasar base_amount dikurangi MDR 0,7%
Kode uniksistem menambahkan angka unik acak (250 — 500) ke setiap transaksi untuk membedakan pembayaran bersamaan yang masuk ke QRIS admin bersama

Kode unik tersebut ditambahkan ke nominal dasar, sehingga jumlah yang harus dibayar pelanggan (total_amount) = base_amount + kode unik.

Respons sukses:

{ "success": true, "data": { "transactionId": "TXN-...", "base_amount": 132000, "unique_code": 480, "total_amount": 132480, "qris_string": "000201...6304ABCD", "qr_code_svg": "", "expires_at": "...", "status": "PENDING", "merchant_ref": "INV-2026-001", "metadata": { "key": "value" } } }

Penting: qris_string adalah teks QRIS mentah (format EMVCo) — untuk menampilkan QR di layar, integrasi Anda HARUS merender string tersebut menjadi gambar QR (mis. library qrcode/qrcode-generator). Ini bukan URL gambar.

qr_code_svg adalah gambar QR siap tampil (SVG self-contained, tidak bergantung aset eksternal) yang kami generate dari qris_string. Bisa dirender langsung sebagai data:image/svg+xml;base64,<...> atau data:image/svg+xml;utf8,<...>. Field ini opsional — jika kosong, render qris_string.

Webhook Pembayaran

Saat transaksi PAID, sistem mengirim POST ke URL webhook yang diatur di panel Pengaturan → Webhook (satu URL untuk live, satu untuk sandbox).

HeaderIsi
X-Webhook-SecretWebhook secret Anda (untuk akses cepat / sambungan langsung)
X-MauPay-Signaturesha256=<base64-HMAC-SHA256> dari body (tanpa _signature), pakai webhook secret Anda
_signature (di body)Nilai tanda tangan yang sama dengan X-MauPay-Signature, disertakan di dalam body JSON
Content-Typeapplication/json
User-AgentMauPay-Webhook/1.0
{ "transactionId": "TXN-...", "status": "PAID", "baseAmount": 132000, "uniqueCode": 480, "totalAmount": 132480, "paidAmount": 132480, "mdrFee": 924, "netAmount": 131076, "paidAt": "2026-01-01T10:00:00Z", "merchant_ref": "INV-2026-001", "metadata": { "key": "value" }, "_signature": "sha256=..." }

Keamanan: verifikasi tanda tangan _signature = 'sha256=' + base64(HMAC-SHA256(sisa body, webhook_secret)), dan header X-Webhook-Secret serta X-MauPay-Signature.

Potongan MDR 0,7%: dari setiap transaksi sukses (live), kami memotong biaya MDR 0,7% dari base_amount sebelum mengkredit saldo merchant. Field mdrFee = nominal potongan, dan netAmount = jumlah bersih yang benar-benar masuk ke saldo Anda (base_amount − mdrFee). Contoh: base Rp 132.000 → MDR Rp 924 → saldo masuk Rp 131.076. Transaksi sandbox tidak dipotong, dan angka di atas hanya ilustrasi.

Penting: _signature dihitung dari body tanpa kunci _signature itu sendiri, dihitung dengan webhook_secret Anda (diatur di Pengaturan → Webhook). Selalu verifikasi signature sebelum memproses webhook untuk memastikan berasal dari MauPay. Buat handler webhook Anda idempoten (aman terhadap webhook berulang, mis. dengan memeriksa transactionId sebelum mengkredit/mengerjakan order).

Contoh verifikasi signature

// Node.js — verifikasi webhook di server Anda const crypto = require('crypto'); // body = string JSON mentah yang diterima (BUKAN hasil JSON.parse). // Ambil _signature di dalam body, lalu hapus untuk menghitung ulang. const { _signature, ...rest } = JSON.parse(rawBody); const webhookSecret = '...'; // dari Pengaturan → Webhook const expected = 'sha256=' + crypto .createHmac('sha256', webhookSecret) .update(JSON.stringify(rest)) .digest('base64'); // Bandingkan dengan timing-safe (mis. crypto.timingSafeEqual) if (hashEqual(_signature, expected)) { // aman — proses transaksi PAID // console.log(rest.merchant_ref, rest.transactionId, rest.paidAmount); } else { // JANGAN proses — webhook tidak autentik }

Contoh integrasi

// Node.js (axios) const res = await axios.post('https://app.maupay.online/api/v1/payments', { amount: 132000, customer_name: 'Budi', merchant_ref: 'INV-2026-001', metadata: { key: 'value' } }, { headers: { 'X-API-Key': 'sk_live_...' } }); console.log(res.data.data.total_amount); // 132480 console.log(res.data.data.qris_string); console.log(res.data.data.merchant_ref); // INV-2026-001 (untuk mencocokkan order Anda)
// PHP (cURL) $ch = curl_init('https://app.maupay.online/api/v1/payments'); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['amount'=>132000])); curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: sk_live_...', 'Content-Type: application/json']); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); echo curl_exec($ch);
# Python (requests) import requests r = requests.post('https://app.maupay.online/api/v1/payments', json={'amount': 132000}, headers={'X-API-Key': 'sk_live_...'}) print(r.json())

2. Sandbox

Gunakan API key sk_test_.... Buat transaksi seperti biasa; respons menyertakan simulatePayUrl untuk menandai transaksi sebagai PAID dan memicu webhook sandbox ke sandbox_webhook_url Anda.

POST https://app.maupay.online/api/sandbox/simulate-payment/:txId

Header: X-API-Key: sk_test_... milik pemilik transaksi.

Status transaksi (lifecycle)

Setiap perubahan status diberitahukan lewat webhook. Status yang mungkin:

StatusKeteranganPemicu
PENDINGMenunggu pembayaranTransaksi dibuat
PAIDPembayaran diterima, saldo dikreditUang masuk cocok (atau simulate-payment di sandbox)
EXPIREDKedaluwarsa, tidak dapat dibayar lagiMelebihi 30 menit tanpa pembayaran
FAILEDGagal / dibatalkanKondisi gagal (mis. pembayaran tidak valid)
Alur normal: PENDINGPAID. Jika tidak dibayar dalam 30 menit: PENDINGEXPIRED.

3. Dashboard & Status

Operasi selain pembuatan pembayaran dilakukan di dalam dashboard (app.maupay.online):

FiturCaraKeterangan
Status transaksiMenu Transaksi & RiwayatStatus per transaksi dan riwayat lengkap. Perubahan status penting (mis. PAID / EXPIRED / FAILED) juga dikirim lewat webhook
Tarik danaMenu Tarik DanaMinimal Rp 20.000, fee Rp 3.000. E-wallet DANA / OVO / GoPay / ShopeePay / LinkAja
Webhook URLMenu PengaturanURL webhook untuk notifikasi pembayaran (live & sandbox)
Webhook LogsMenu Webhook LogsRiwayat pengiriman webhook ke server Anda
Akun & authHalaman register / masuk / lupa password / ganti password di aplikasiDaftar dengan OTP email; sesi login valid 30 hari
API keysHalaman Berandask_live_…, sk_test_…, webhook secret
Integrasi Anda cukup memakai: POST /api/v1/payments untuk membuat pembayaran, halaman status/pay dari respons untuk menampilkan QRIS, dan webhook untuk mengetahui transaksi PAID.

4. Kode Error

KodeArti
200 / 201Sukses
400Parameter salah / validasi gagal (mis. amount tidak integer, metadata bukan objek)
401API key salah / tidak valid
403Akses ditolak (bukan transaksi Anda)
404Sumber daya tidak ditemukan
429Terlalu banyak request — pembayaran dibatasi 30/menit per IP & per API key; penarikan 5×/5 menit; verifikasi OTP 5×/10 menit.
500Kesalahan internal server

Respons error dikembalikan sebagai JSON:

{ "error": "Terlalu banyak request. Coba lagi 1 menit lagi." }