QRIS Dinamis & Payment Gateway API
Generate kode QRIS dinamis ber-nominal otomatis dengan timer kedaluwarsa, URL redirect callback, polling cek status pembayaran realtime, dan notifikasi Webhook instan.
โก Aturan Biaya Kuota API & Ketentuan Paket Langganan
-
Syarat Paket Langganan: Layanan QRIS Dinamis mewajibkan akun memiliki langganan aktif
Paket P3 (1 QRIS Toko - Rp 20.000 / bln) atau
Paket P5 (Multi-QRIS Bebas / Banyak Toko - Rp 35.000 / bln).
Jika akun belum berlangganan atau paket telah kedaluwarsa, sistem akan menolak permintaan dengan response
403 PLAN_P3_REQUIRED. -
Biaya Kuota API Pembuatan QRIS: Setiap request pembuatan QRIS dinamis yang berhasil (status
201 Created) memotong 6 Hit Point dari saldo kuota akun Anda. -
Pengecekan Status Realtime (Polling): Endpoint pengecekan status pembayaran via token (
/qris/check-status/{token}) adalah 0 Hit Point (GRATIS) dan tidak memotong kuota sama sekali. -
Whitelist IP Server: Pastikan IP VPS / server aplikasi Anda sudah didaftarkan pada
Slot IP Dashboard
untuk menghindari penolakan akses
403 IP_NOT_ALLOWED.
Alur Integrasi & Siklus Pembayaran
User login ke web panel lalu mengunggah gambar QRIS statis toko (GoPay, BRI Merchant, DANA Bisnis, Mandiri Livin', ShopeePay, dll) pada menu QRIS Dinamis. Sistem memvalidasi CRC dan menyimpan payload EMVCo sebagai sumber default.
Aplikasi/bot Anda mengirim HTTP POST ke /api/qris/create dengan nominal transaksi, batas waktu (menit), dan URL redirect. Sistem membuat QRIS dinamis instan dan mengembalikan payload mentah, gambar PNG, token, serta link checkout.
Pelanggan memindai QRIS dinamis menggunakan e-wallet atau mobile banking apa saja dengan nominal yang sudah terkunci otomatis, atau diarahkan langsung ke halaman pembayaran siap pakai Cutiezy (/pay/{token}).
Sistem mencocokkan mutasi transaksi masuk secara realtime. Anda dapat memverifikasi via polling berkala /qris/check-status/{token} atau menerima notifikasi instan via HTTP POST Webhook event qris.payment.success.
Autentikasi API
Setiap request ke endpoint pembuatan QRIS dinamis wajib menyertakan API Key akun Anda. Disarankan menggunakan header:
X-API-Key: YOUR_API_KEY
Content-Type: application/json
Accept: application/json
Fallback juga didukung via header Authorization: Bearer YOUR_API_KEY atau query parameter URL ?apikey=YOUR_API_KEY.
1. Generate QRIS Dinamis (Create Invoice)
Membuat kode QRIS dinamis dengan nominal transaksi tertentu dari sumber QRIS yang tersimpan di akun Anda.
POST
https://api.cutiezy.id/api/qris/create
https://api.cutiezy.id/api/qris/generate| Parameter | Tipe | Wajib | Keterangan |
|---|---|---|---|
| amount | integer | Wajib | Nominal pembayaran rupiah, bilangan bulat > 0 (contoh: 25000). Alias: total. |
| source_id | integer | Opsional | ID spesifik sumber QRIS toko milik Anda jika memiliki banyak QRIS (contoh: 7). Jika dikosongkan, otomatis menggunakan QRIS default akun Anda. Alias: qris_id. |
| expiry_minutes | integer | Opsional | Durasi masa aktif tagihan dalam menit. Pilihan durasi yang didukung: 3, 5, 10, 12, atau 15 menit (default: 15 menit). Menggunakan arsitektur Smart Active Window untuk verifikasi mutasi presisi secara realtime dan hemat daya. Alias: expired_minutes, valid_minutes, minutes. |
| redirect_url | string | Opsional | URL redirect pengalihan otomatis pembeli setelah pembayaran berhasil di halaman checkout (contoh: https://tokoanda.com/order/inv-123/success). Alias: return_url, callback_url, link. |
{
"success": true,
"ok": true,
"message": "QRIS dinamis berhasil dibuat.",
"hit_points_deducted": 6,
"data": {
"id": 142,
"token": "4f9b8c2d1e0a3f5b7c9d1e2f3a4b5c6d",
"source_id": 7,
"label": "Toko Utama Cabang 1",
"merchant_name": "CUTIEZY STORE",
"amount": 25000,
"qris_string": "00020101021226590014ID.LINKAJA.WWW01189360001400000000000208123456785204581253033605405250005802ID5913CUTIEZY STORE6007JAKARTA62070703A016304ABCD",
"image_url": "https://api.cutiezy.id/public/generated/qris/20261011/qris_4f9b8c2d1e0a3f5b7c9d1e2f3a4b5c6d.png",
"payment_url": "https://api.cutiezy.id/pay/4f9b8c2d1e0a3f5b7c9d1e2f3a4b5c6d",
"checkout_url": "https://api.cutiezy.id/qris/pay/4f9b8c2d1e0a3f5b7c9d1e2f3a4b5c6d",
"redirect_url": "https://tokoanda.com/order/inv-123/success",
"expiry_minutes": 15,
"expires_at": "2026-10-11 11:15:00",
"status": "pending"
},
"remaining_quota": {
"type": "membership",
"remaining": 494,
"limit": 500
}
}
Penjelasan Field Output Data:
token: Token acak unik 32 karakter hexadesimal sebagai kunci identifikasi tagihan pembayaran. Digunakan pada endpoint cek status dan URL halaman checkout.qris_string: String payload mentah standar EMVCo QRIS dinamis (Tag 01 = '12' Dynamic, Tag 54 = nominal, dengan CRC16 checksum valid). Dapat langsung dirender di frontend Anda menggunakan library barcode/QR.image_url: URL file gambar PNG QRIS resolusi tinggi yang siap ditampilkan ke pembeli atau dicetak.payment_url/checkout_url: Halaman web pembayaran siap pakai dari Cutiezy yang dapat langsung dibuka oleh pelanggan di browser handphone atau desktop.expires_at: Tanggal dan jam kedaluwarsa tagihan sesuai parameterexpiry_minutes.hit_points_deducted: Jumlah hit point yang terpotong pada pembuatan QRIS ini (6 hit point).
2. Cek Status Pembayaran Realtime (Polling)
Memeriksa apakah tagihan QRIS dengan {token} tertentu sudah dibayar oleh pelanggan atau belum. Endpoint ini otomatis mencocokkan mutasi transaksi merchant secara realtime dan tidak memotong kuota Hit Point (0 Hit Point / GRATIS).
GET / POST
https://api.cutiezy.id/qris/check-status/{token}
{token} dengan token 32 karakter dari respon pembuatan QRIS.{
"ok": true,
"status": "paid",
"paid_at": "2026-10-11 10:45:12",
"amount": 25000,
"mutation_ref": "202610110987654321",
"redirect_url": "https://tokoanda.com/order/inv-123/success",
"message": "Pembayaran berhasil diverifikasi via mutasi!"
}
{
"ok": true,
"status": "pending",
"remaining_seconds": 840,
"redirect_url": "https://tokoanda.com/order/inv-123/success",
"message": "Menunggu pembayaran dari pelanggan..."
}
{
"ok": true,
"status": "expired",
"remaining_seconds": 0,
"redirect_url": "https://tokoanda.com/order/inv-123/success",
"message": "Waktu pembayaran telah habis."
}
{
"ok": true,
"status": "canceled",
"remaining_seconds": 0,
"redirect_url": "https://tokoanda.com/order/inv-123/failed",
"message": "Tagihan QRIS telah dibatalkan."
}
{
"ok": false,
"status": "not_found",
"message": "Tagihan QRIS tidak ditemukan."
}
3. Pembatalan Tagihan QRIS (Cancel Invoice)
Membatalkan tagihan QRIS berstatus pending sebelum batas waktu kedaluwarsa habis. Gunakan endpoint ini saat pembeli membatalkan pesanan di kasir / checkout website Anda, mengganti nominal, atau menutup keranjang belanja. Pembatalan ini sekaligus mengistirahatkan gateway pemantau sehingga sistem tetap efisien dan cepat.
POST
https://api.cutiezy.id/api/qris/cancel
https://api.cutiezy.id/api/qris/cancel/{token}| Parameter | Tipe | Wajib | Keterangan |
|---|---|---|---|
| token | string | Wajib* | Token 32 karakter unik tagihan QRIS yang hendak dibatalkan. *Wajib jika memanggil POST /api/qris/cancel. Jika memanggil /api/qris/cancel/{token}, token dibaca otomatis dari path URL. |
{
"success": true,
"ok": true,
"status": "canceled",
"token": "4f9b8c2d1e0a3f5b7c9d1e2f3a4b5c6d",
"amount": 25000,
"redirect_url": "https://tokoanda.com/order/inv-123/failed",
"message": "Tagihan QRIS berhasil dibatalkan."
}
{
"success": false,
"ok": false,
"status": "paid",
"message": "Tagihan sudah dibayar dan tidak dapat dibatalkan."
}
4. Halaman Checkout Pembayaran Publik (No-Code UI)
Jika Anda tidak ingin membangun tampilan antarmuka kasir pembayaran sendiri, cukup arahkan pembeli ke link checkout publik Cutiezy. Halaman ini aman, responsif untuk layar handphone, dan dapat dibuka oleh siapa saja tanpa autentikasi.
GET
https://api.cutiezy.id/pay/{token}
https://api.cutiezy.id/qris/pay/{token}- Menampilkan nama toko/merchant, total tagihan rupiah pas, dan gambar barcode QRIS.
- Timer countdown realtime sesuai durasi
expiry_minutes. - Fitur polling background otomatis yang mengecek status pembayaran setiap beberapa detik.
- Jika pembayaran berhasil dan Anda menyertakan
redirect_url, pembeli akan otomatis dialihkan ke website Anda dalam 2 detik.
Notifikasi Webhook Realtime (qris.payment.success)
Selain menggunakan polling status, sistem Cutiezy otomatis mengirimkan HTTP POST Webhook ke server Anda seketika saat pembayaran QRIS dinamis berhasil diverifikasi mutasi rekening merchant.
qris.payment.success:
{
"event": "qris.payment.success",
"token": "4f9b8c2d1e0a3f5b7c9d1e2f3a4b5c6d",
"amount": 25000,
"merchant_name": "CUTIEZY STORE",
"qris_source_id": 7,
"user_id": 12,
"paid_at": "2026-10-11 10:45:12",
"reference": "202610110987654321",
"customer": "ANDI PRATAMA",
"redirect_url": "https://tokoanda.com/order/inv-123/success"
}
Setiap pengiriman webhook dilengkapi header X-Cutiezy-Signature menggunakan tanda tangan kriptografi HMAC SHA-256 dari raw body JSON menggunakan Secret Key webhook Anda. Selengkapnya lihat di
Dokumentasi Webhook Realtime.
Daftar Kode Error Resmi Sistem
| HTTP Code | Kode Error (error) | Penyebab / Keterangan | Solusi |
|---|---|---|---|
| 401 | UNAUTHORIZED / INVALID_API_KEY | Header API Key tidak dikirim atau API Key salah. | Pastikan menyertakan header X-API-Key: czw_... yang valid. |
| 403 | IP_NOT_ALLOWED | Alamat IP pengirim belum di-whitelist di akun Anda. | Daftarkan IP server Anda di menu Slot IP Dashboard. |
| 403 | PLAN_P3_REQUIRED | Akun belum memiliki paket langganan aktif minimal Paket P3. | Beli Paket P3 (Rp 20.000/bln) di menu Billing / Paket. |
| 409 | QRIS_SOURCE_REQUIRED | User belum mengunggah gambar QRIS statis sumber di panel web. | Buka menu QRIS Dinamis di web dan unggah QRIS toko Anda. |
| 422 | INVALID_QRIS_REQUEST | Nominal amount kosong, bernilai <= 0, atau format angka salah. |
Kirimkan nominal bilangan bulat positif (contoh: 25000). |
| 429 | QUOTA_EXCEEDED | Saldo kuota Hit Point akun Anda habis (dibutuhkan 6 Hit Point). | Lakukan perpanjangan paket atau isi kuota di menu Billing. |
| 429 | RATE_LIMITED | Terlalu banyak permintaan API dalam waktu singkat. | Tunggu beberapa saat (lihat nilai retry_after) sebelum mencoba lagi. |
| 503 | QRIS_GENERATOR_UNAVAILABLE | Modul generator QR atau ekstensi PHP GD server sedang bermasalah. | Hubungi tim dukungan teknis Cutiezy jika kendala berlanjut. |
Contoh Kode Integrasi
Salin dan sesuaikan contoh kode di bawah untuk bahasa pemrograman yang Anda gunakan.
๐ cURL (Terminal / Bash)
# 1. Generate QRIS Dinamis Rp 25.000 (Pilihan durasi: 3, 5, 10, 12, atau 15 menit)
curl -X POST "https://api.cutiezy.id/api/qris/create" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"amount": 25000,
"expiry_minutes": 15,
"redirect_url": "https://tokoanda.com/order/123/success"
}'
# 2. Cek Status Pembayaran Realtime (Polling)
curl -X GET "https://api.cutiezy.id/qris/check-status/YOUR_TRANSACTION_TOKEN" \
-H "Accept: application/json"
# 3. Batalkan Tagihan QRIS (Cancel Invoice)
curl -X POST "https://api.cutiezy.id/api/qris/cancel" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"token": "YOUR_TRANSACTION_TOKEN"}'
๐ PHP Native (cURL)
<?php
$apiKey = 'YOUR_API_KEY';
// 1. Buat Tagihan QRIS Dinamis (Pilihan durasi: 3, 5, 10, 12, atau 15 menit)
function createQrisInvoice($apiKey, $amount, $expiryMinutes = 15, $redirectUrl = null) {
$url = 'https://api.cutiezy.id/api/qris/create';
$payload = [
'amount' => (int)$amount,
'expiry_minutes' => $expiryMinutes,
];
if ($redirectUrl) {
$payload['redirect_url'] = $redirectUrl;
}
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 20,
CURLOPT_HTTPHEADER => [
'X-API-Key: ' . $apiKey,
'Content-Type: application/json',
'Accept: application/json',
],
CURLOPT_POSTFIELDS => json_encode($payload),
]);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
// 2. Fungsi Cek Status Pembayaran (Polling 0 Hit Point)
function checkQrisStatus($token) {
$url = 'https://api.cutiezy.id/qris/check-status/' . rawurlencode($token);
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 15,
CURLOPT_HTTPHEADER => ['Accept: application/json'],
]);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
// 3. Batalkan Tagihan QRIS (Cancel Invoice)
function cancelQrisInvoice($apiKey, $token) {
$url = 'https://api.cutiezy.id/api/qris/cancel';
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 15,
CURLOPT_HTTPHEADER => [
'X-API-Key: ' . $apiKey,
'Content-Type: application/json',
'Accept: application/json',
],
CURLOPT_POSTFIELDS => json_encode(['token' => $token]),
]);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
// Contoh Penggunaan:
$result = createQrisInvoice($apiKey, 25000, 15, 'https://tokoanda.com/order/success');
if (!empty($result['ok'])) {
$data = $result['data'];
echo "QRIS Dibuat!\n";
echo "Token Tagihan : " . $data['token'] . "\n";
echo "URL Gambar : " . $data['image_url'] . "\n";
echo "Link Checkout : " . $data['payment_url'] . "\n";
} else {
echo "Gagal: " . ($result['message'] ?? 'Error');
}
?>
โก JavaScript / Node.js (Fetch)
const API_KEY = "YOUR_API_KEY";
// 1. Generate QRIS Dinamis (Pilihan durasi: 3, 5, 10, 12, atau 15 menit)
async function generateQris(amount, expiryMinutes = 15, redirectUrl = null) {
const res = await fetch("https://api.cutiezy.id/api/qris/create", {
method: "POST",
headers: {
"X-API-Key": API_KEY,
"Content-Type": "application/json",
"Accept": "application/json"
},
body: JSON.stringify({
amount: amount,
expiry_minutes: expiryMinutes,
redirect_url: redirectUrl
})
});
return await res.json();
}
// 2. Polling Status Realtime (Panggil setiap 3 detik)
async function pollQrisStatus(token) {
const res = await fetch(`https://api.cutiezy.id/qris/check-status/${token}`, {
headers: { "Accept": "application/json" }
});
return await res.json();
}
// 3. Batalkan Tagihan QRIS (Cancel Invoice)
async function cancelQrisInvoice(token) {
const res = await fetch("https://api.cutiezy.id/api/qris/cancel", {
method: "POST",
headers: {
"X-API-Key": API_KEY,
"Content-Type": "application/json",
"Accept": "application/json"
},
body: JSON.stringify({ token })
});
return await res.json();
}
// Contoh Eksekusi:
(async () => {
const invoice = await generateQris(25000, 15, "https://tokoanda.com/success");
if (invoice.ok) {
console.log("QRIS Berhasil Dibuat:", invoice.data.token);
console.log("URL Gambar:", invoice.data.image_url);
console.log("Link Bayar:", invoice.data.payment_url);
// Mulai polling cek status
const timer = setInterval(async () => {
const check = await pollQrisStatus(invoice.data.token);
console.log("Status:", check.status);
if (check.status === "paid") {
clearInterval(timer);
console.log("โ
Lunas! Mutasi Ref:", check.mutation_ref);
} else if (check.status === "expired" || check.status === "canceled") {
clearInterval(timer);
console.log("โ Tagihan selesai dengan status:", check.status);
}
}, 3000);
}
})();
๐ Python (requests)
import requests
import time
API_KEY = "YOUR_API_KEY"
# 1. Generate QRIS Dinamis (Pilihan durasi: 3, 5, 10, 12, atau 15 menit)
def create_qris(amount, expiry_minutes=15, redirect_url=None):
url = "https://api.cutiezy.id/api/qris/create"
headers = {
"X-API-Key": API_KEY,
"Content-Type": "application/json",
"Accept": "application/json"
}
payload = {
"amount": amount,
"expiry_minutes": expiry_minutes,
"redirect_url": redirect_url
}
res = requests.post(url, json=payload, headers=headers, timeout=20)
return res.json()
# 2. Cek Status Polling
def check_status(token):
url = f"https://api.cutiezy.id/qris/check-status/{token}"
res = requests.get(url, timeout=15)
return res.json()
# 3. Batalkan Tagihan QRIS (Cancel Invoice)
def cancel_qris(token):
url = "https://api.cutiezy.id/api/qris/cancel"
headers = {
"X-API-Key": API_KEY,
"Content-Type": "application/json",
"Accept": "application/json"
}
res = requests.post(url, json={"token": token}, headers=headers, timeout=15)
return res.json()
# Contoh Penggunaan:
invoice = create_qris(25000, 15, "https://tokoanda.com/order/success")
if invoice.get("ok"):
data = invoice["data"]
token = data["token"]
print("QRIS Siap!")
print(f"Token: {token}")
print(f"Gambar: {data['image_url']}")
print(f"Link Checkout: {data['payment_url']}")
# Polling status loop
while True:
status = check_status(token)
if status.get("status") == "paid":
print(f"โ
Lunas via mutasi: {status.get('mutation_ref')}")
break
elif status.get("status") in ["expired", "canceled"]:
print(f"โ Tagihan selesai: {status.get('status')}")
break
print("Menunggu pembayaran...")
time.sleep(3)
else:
print("Gagal membuat QRIS:", invoice.get("message"))
Solusi Siap Pakai: Mode Kasir POS & Standee Meja
Selain integrasi via REST API, Cutiezy menyediakan antarmuka khusus siap pakai bagi merchant toko fisik, UMKM, cafe, dan kasir:
Buka /qris/kasir di tablet, iPad, atau HP kasir. Dilengkapi Numpad sentuh, tombol nominal cepat, hitung mundur, audio lonceng sukses, dan fullscreen.
Akses /qris/stand/{id} untuk mencetak standee akrilik (ukuran A5/A6/A4) berlogo resmi QRIS & GPN yang siap ditempel di meja/kasir toko.
Saat pembeli men-scan standee di meja, URL /kios/{id} terbuka di HP pembeli. Pembeli tinggal mengetik nominal belanja, dan QRIS dinamis langsung muncul di layar HP mereka.