Payment Gateway QRIS
Integrasi pembayaran QRIS untuk bot Telegram, web store, dan backend toko. Setiap pengguna wajib mendaftar di Web Portal untuk mendapatkan API Key toko sendiri (supaya transaksi & saldo terisolasi rapi antar toko).
https://YOUR-DOMAIN
Pengenalan
Gateway ini menyediakan sistem pembayaran QRIS otomatis terintegrasi. Setiap merchant yang terdaftar di Web Portal dapat membuat pembayaran dinamis, mendeteksi status lunas secara otomatis, dan menarik saldo lewat portal (Withdraw).
API Key per toko
Setiap pengguna punya key beda. Semua transaksi & saldo terpisah, tidak tabrakan.
Tanpa QRIS di bot
Sistem QRIS diproses otomatis oleh gateway. Bot cukup BASE_URL + API_KEY.
Saldo & Withdraw
Pembayaran success masuk saldo akun itu saja → tarik lewat portal Withdraw.
Env bot / web store (wajib per pengguna)
Setiap penyewa mendapat API Key unik di portal.
Taruh key itu di env bot / store masing-masing agar request terikat ke akun mereka:
transaksi, payment_id, dan saldo tidak campur dengan toko lain.
| Variabel | Keterangan | |
|---|---|---|
BASE_URL |
wajib | URL gateway (contoh domain kamu) |
API_KEY |
wajib | API Key unik per pengguna dari portal (Settings). Jangan saling pakai key orang lain. |
Autentikasi
Semua request (kecuali gambar QR) pakai header Bearer API Key dari portal.
Login di Portal untuk menampilkan API Key Anda di sini.
Daftar / Login PortalAuthorization: Bearer js_API_KEY_ANDA
Cara Mulai
- Daftar di /portal (OTP Telegram) → sistem buat API Key unik
- Salin API Key dari Settings → taruh di env bot/store:
API_KEY+BASE_URL - Setiap request pakai header
Authorization: Bearer API_KEY→ transaksi & saldo terpisah per toko - Panggil create QRIS → tampilkan ke pelanggan → cek bayar dengan
payment_id
Buat QRIS (Payment)
Membuat QRIS dinamis secara otomatis melalui gateway.
Response berisi payment_id dan nominal yang harus dibayar persis.
/gateaway/qris/create
Request Body
{
"amount": 50000,
"ref": "ORDER-123",
"note": "Top up user"
}
| Param | Tipe | Keterangan | |
|---|---|---|---|
amount | integer | wajib | Nominal order (IDR) yang akan masuk saldo setelah lunas |
ref | string | opsional | Referensi order di sistem kamu |
note | string | opsional | Catatan |
Response
{
"success": true,
"message": "QRIS created successfully (shared PG)",
"data": {
"payment_id": "pay_abc123",
"amount": 50550,
"requested_amount": 50000,
"credit_amount": 50000,
"qr_string": "00020101...",
"qr_url": "https://YOUR-DOMAIN/gateaway/qr/xxxxx",
"expiry_time": "2026-07-23 15:00:00",
"mode": "tenant_shared"
}
}
| Field | Keterangan |
|---|---|
amount | Nominal yang harus dibayar customer di QR — bayar persis |
requested_amount / credit_amount | Nominal order; yang masuk saldo setelah lunas |
payment_id | ID untuk cek status pembayaran |
expiry_time | Batas waktu bayar (~15 menit). Lewat → payment otomatis cancelled |
amount = harga order kamu. Server mengembalikan nominal bayar final di
field amount response — tampilkan itu ke customer.
Setelah lunas, saldo = credit_amount.
expiry_time, status otomatis cancelled.
Buat payment baru bila perlu.
Cek Pembayaran
Cek apakah customer sudah bayar. Jika success, saldo penyewa otomatis di-credit.
/gateaway/payment/check
{ "payment_id": "pay_abc123" }
Response (lunas)
{
"success": true,
"data": {
"paid": true,
"expired": false,
"cancelled": false,
"credit_amount": 50000,
"payment": { "id": "pay_abc123", "amount": 50350, "status": "paid" },
"balance": { "balance": 50000, "locked": 0, "available": 50000 }
}
}
Response (belum bayar)
{
"success": true,
"data": {
"paid": false,
"expired": false,
"cancelled": false,
"payment": { "id": "pay_abc123", "status": "pending", "expires_at": "..." }
}
}
Response (QRIS expired → auto cancelled)
{
"success": true,
"message": "QRIS expired — otomatis dibatalkan",
"data": {
"paid": false,
"expired": true,
"cancelled": true,
"payment": {
"id": "pay_abc123",
"status": "cancelled",
"cancel_reason": "expired",
"expires_at": "..."
}
}
}
paid === true untuk sukses.
Jika expired / cancelled true → hentikan polling, minta user buat QR baru.
Expire juga dijalankan periodik di server (~30 detik), tidak hanya saat /payment/check.
Status pembayaran & auto-cancel expire
Setelah qris/create, payment berstatus pending sampai lunas
atau lewat expiry_time (default ~15 menit, env
QRIS_EXPIRY_MINUTES).
| Status | Arti | Di bot / web store |
|---|---|---|
pending |
QR aktif, menunggu bayar | Tampilkan “Menunggu pembayaran…” · lanjut polling |
paid |
Lunas · saldo di-credit | Order sukses · hentikan polling |
cancelled |
Otomatis dibatalkan karena expire (atau dibatalkan sistem) | Tampilkan “QR kadaluarsa / dibatalkan” · buat payment baru |
status: "cancelled" dengan
cancel_reason: "expired". Tidak perlu cancel manual.
Response payment/check → paid: false,
expired: true, cancelled: true.
Kapan auto-cancel jalan?
- Saat ada yang memanggil
GET/POSTpayment (list / check) lewatfindById - Job periodik server (~setiap 30 detik) membatalkan semua pending yang lewat
expires_at
Setelah cancelled, nominal unik dibebaskan untuk payment baru.
Gambar QR (/gateaway/qr/:id) juga tidak valid lagi setelah expiry store QR.
Riwayat & Saldo
/gateaway/payments
Alias riwayat juga: GET /gateaway/transactions (mode shared PG otomatis).
QR Image
Gambar QR publik (tanpa API Key). ID random & berumur pendek (~15 menit).
/gateaway/qr/:id
| Query | Keterangan |
|---|---|
format=png | Default — image/png |
format=svg | SVG |
format=raw | String QRIS |
format=json | JSON metadata |
Contoh Bot / Web Store
POST /gateaway/qris/create→ dapatpayment_id,amount,qr_url,expiry_time- Tampilkan QR ke pelanggan — bayar persis
amountsebelum expire - Polling
POST /gateaway/payment/checksetiap 3–5 detik - Jika
paid: true→ order sukses (saldo =credit_amount) - Jika
expired/cancelled→ QR kadaluarsa, otomatis dibatalkan; buat payment baru
Node.js
Python
Error Umum
| Pesan / status | Arti | Solusi |
|---|---|---|
| 401 Unauthorized | API Key salah / kosong | Salin ulang dari portal Settings |
| Layanan QRIS belum siap | Server gateway belum siap | Hubungi admin gateway |
| paid: false | Belum bayar / nominal beda | Pastikan bayar persis amount di response |
| expired / cancelled: true | QRIS lewat expiry_time, auto-cancel | Buat QR baru lewat /qris/create |