Portal →
Dokumentasi API · docs QRIS (Publik)

docs QRIS (Publik)

Integrasi pembayaran QRIS untuk bot Telegram, web store, dan backend toko. Setiap pengguna wajib pakai API Key sendiri di env bot/store (supaya transaksi & saldo tidak tabrakan antar toko). Yang tidak perlu di env: QRIS static & token merchant (sudah di server admin).

Base URL https://YOUR-DOMAIN

Pengenalan

Gateway ini memakai QRIS merchant admin di server. Setiap penyewa yang punya lisensi aktif dapat membuat pembayaran, mendeteksi lunas, 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

QRIS static & token merchant di server admin. 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.

env

        
VariabelKeterangan
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.
Penting: API Key hanya di backend / bot server, jangan di JavaScript frontend publik. Satu toko = satu API Key. Regenerasi key di portal mematikan key lama.

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 Portal
http
Authorization: Bearer js_API_KEY_ANDA

Cara Mulai

  1. Daftar di /portal (OTP Telegram) → sistem buat API Key unik
  2. Salin API Key dari Settings → taruh di env bot/store: API_KEY + BASE_URL
  3. Setiap request pakai header Authorization: Bearer API_KEY → transaksi & saldo terpisah per toko
  4. Panggil create QRIS → tampilkan ke pelanggan → cek bayar dengan payment_id
Lisensi tidak diperlukan untuk Payment Gateway (QRIS admin). Cukup daftar portal + API Key unik di env bot/store.

Buat QRIS (Payment)

Membuat QRIS dinamis memakai QRIS admin di server. Response berisi payment_id dan nominal yang harus dibayar persis.

POST /gateaway/qris/create

Request Body

json
{
  "amount": 50000,
  "ref": "ORDER-123",
  "note": "Top up user"
}
ParamTipeKeterangan
amountintegerwajibNominal order (IDR) yang akan masuk saldo setelah lunas
refstringopsionalReferensi order di sistem kamu
notestringopsionalCatatan
cURL

        

Response

json
{
  "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"
  }
}
FieldKeterangan
amountNominal yang harus dibayar customer di QR — bayar persis
requested_amount / credit_amountNominal order; yang masuk saldo setelah lunas
payment_idID untuk cek status pembayaran
checkout_urlHalaman checkout siap pakai untuk customer (/pay/:id) lengkap dengan timer, salin nominal, unduh QR, & auto-redirect
expiry_timeBatas waktu bayar (~15 menit). Lewat → payment otomatis cancelled
Parameter opsional saat POST /gateway/qris/create:
  • callback_url — URL webhook server Anda (menerima POST JSON + header X-Signature HMAC-SHA256 saat lunas).
  • redirect_url — URL tujuan redirect otomatis setelah pembeli melunasi di halaman checkout_url.
  • Header Idempotency-Key — Mencegah pembuatan QR ganda bila bot/server Anda melakukan retry request yang sama.
Kirim amount = harga order kamu. Server mengembalikan nominal bayar final di field amount response — tampilkan itu ke customer. Setelah lunas, saldo = credit_amount.
Auto-cancel saat expire: Jika belum bayar sampai expiry_time, status otomatis cancelled. Buat payment baru bila perlu.

Cek Pembayaran

Cek apakah customer sudah bayar. Jika success, saldo penyewa otomatis di-credit.

POST /gateaway/payment/check
json
{ "payment_id": "pay_abc123" }
cURL

        

Response (lunas)

json
{
  "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)

json
{
  "success": true,
  "data": {
    "paid": false,
    "expired": false,
    "cancelled": false,
    "payment": { "id": "pay_abc123", "status": "pending", "expires_at": "..." }
  }
}

Response (QRIS expired → auto cancelled)

json
{
  "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": "..."
    }
  }
}
Polling bot/store: cek 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).

StatusArtiDi 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
Buat QRIS lalu tidak bayar sampai expire: Server otomatis set 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/POST payment (list / check) lewat findById
  • 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

GET /gateaway/payments
cURL

        

Alias riwayat juga: GET /gateaway/transactions (mode shared PG otomatis).

QR Image

Gambar QR publik (tanpa API Key). ID random & berumur pendek (~15 menit).

GET /gateaway/qr/:id
QueryKeterangan
format=pngDefault — image/png
format=svgSVG
format=rawString QRIS
format=jsonJSON metadata

Contoh Bot / Web Store

Alur
  1. POST /gateaway/qris/create → dapat payment_id, amount, qr_url, expiry_time
  2. Tampilkan QR ke pelanggan — bayar persis amount sebelum expire
  3. Polling POST /gateaway/payment/check setiap 3–5 detik
  4. Jika paid: true → order sukses (saldo = credit_amount)
  5. Jika expired / cancelled → QR kadaluarsa, otomatis dibatalkan; buat payment baru

Node.js

javascript

        

Python

python

        

PHP / Laravel (cURL)

php

        

Webhook & Verifikasi Signature (HMAC-SHA256)

Selain polling, Anda dapat menyertakan callback_url saat membuat QRIS (atau mengatur Default Callback URL di Portal → Pengaturan). Begitu pembayaran lunas, server kami mengirim HTTP POST JSON dengan header tanda tangan kriptografi:

HeaderIsi
X-Signaturesha256=<hex HMAC-SHA256(webhook_secret, timestamp + "." + rawBody)>
X-Signature-Simplesha256=<hex HMAC-SHA256(webhook_secret, rawBody)>
X-Webhook-TimestampUnix timestamp detik saat pengiriman
X-Webhook-Eventpayment.success atau binance.payment.success
Jika server Anda sedang down / mengembalikan HTTP 5xx, sistem otomatis melakukan retry bertahap hingga 5x (30 detik, 2 menit, 10 menit, 30 menit). Anda juga bisa menekan tombol Kirim Ulang di Portal.
Verifikasi Signature di Express / Node.js
const crypto = require('crypto');

app.post('/webhook/janspay', express.raw({ type: 'application/json' }), (req, res) => {
  const secret = process.env.WEBHOOK_SECRET; // dari Portal → Pengaturan
  const ts = req.headers['x-webhook-timestamp'];
  const sig = req.headers['x-signature'];
  const expected = 'sha256=' + crypto.createHmac('sha256', secret)
    .update(`${ts}.${req.body.toString('utf8')}`)
    .digest('hex');

  if (sig !== expected) return res.status(401).send('Invalid signature');
  const event = JSON.parse(req.body.toString('utf8'));
  // Proses order lunas: event.payment_id, event.credit_amount, event.ref
  res.json({ ok: true });
});

Integrasi PHP & Laravel

Contoh lengkap integrasi payment gateway di PHP native (cURL) dan framework Laravel (Guzzle / HTTP Client).

1. PHP Native (cURL) — Buat Tagihan & Redirect

create_payment.php

        

2. Laravel Framework (HTTP Client) — Controller & Checkout

PaymentController.php

        

3. Verifikasi Webhook Signature (HMAC-SHA256) di PHP

webhook.php

        

⚡ Interactive API Playground (Coba Langsung)

Live Simulator

Uji simulasi pembuatan tagihan QRIS secara langsung dari browser Anda tanpa perlu koding. Jika Anda belum punya API Key, sistem otomatis menggunakan Demo Sandbox publik.

Error Umum

Pesan / statusArtiSolusi
401 UnauthorizedAPI Key salah / kosongSalin ulang dari portal Settings
QRIS admin belum di-setServer admin belum siapHubungi admin gateway
paid: falseBelum bayar / nominal bedaPastikan bayar persis amount di response
expired / cancelled: trueQRIS lewat expiry_time, auto-cancelBuat QR baru lewat /qris/create