Pengantar
API QRIS APIQris adalah REST API berbasis JSON untuk membuat QRIS dinamis dari QRIS milik Anda sendiri dan mengetahui kapan pembayaran masuk. Dana pembeli langsung masuk ke akun merchant QRIS Anda, APIQris hanya mengurus data tagihan, pencocokan, dan webhook.
https://api.apiqris.com/v1application/json, UTF-8Bearer API keyISO 8601, Asia/Jakarta (+07:00)IDR, bilangan bulat rupiahv1Mulai cepat
- Daftar dan upload QRISBuat akun, lalu unggah gambar QRIS merchant Anda.
- Pasang aplikasi pendampingPairing HP Android yang menerima notifikasi dana masuk dari aplikasi merchant.
- Ambil API keyMenu Developer: salin
AQ_TEST_untuk uji dan secret webhook. - Buat tagihan pertamaPanggil
POST /invoicesdan tampilkanqr_image_url. - Terima webhookVerifikasi tanda tangan, tandai pesanan lunas, balas 200.
curl -X POST https://api.apiqris.com/v1/invoices \
-H "Authorization: Bearer AQ_LIVE_xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"amount":50000,"order_id":"INV-1024"}'<?php
$ch = curl_init('https://api.apiqris.com/v1/invoices');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('APIQRIS_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'amount' => 50000,
'order_id' => 'INV-1024',
]),
]);
$qris = json_decode(curl_exec($ch), true);
echo $qris['qr_image_url']; // tampilkan ke pembeliuse Illuminate\Support\Facades\Http;
$qris = Http::withToken(config('services.apiqris.key'))
->post('https://api.apiqris.com/v1/invoices', [
'amount' => $order->total,
'order_id' => $order->number,
])
->throw()
->json();
return view('checkout.qris', ['qris' => $qris]);const res = await fetch('https://api.apiqris.com/v1/invoices', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.APIQRIS_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ amount: 50000, order_id: 'INV-1024' }),
});
const qris = await res.json();
console.log(qris.total_amount, qris.qr_image_url);import os, requests
r = requests.post(
"https://api.apiqris.com/v1/invoices",
headers={"Authorization": f"Bearer {os.environ['APIQRIS_KEY']}"},
json={"amount": 50000, "order_id": "INV-1024"},
timeout=15,
)
r.raise_for_status()
qris = r.json()
print(qris["total_amount"], qris["qr_image_url"])body := strings.NewReader(`{"amount":50000,"order_id":"INV-1024"}`)
req, _ := http.NewRequest("POST", "https://api.apiqris.com/v1/invoices", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("APIQRIS_KEY"))
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()Autentikasi
Setiap request wajib memakai HTTPS dan menyertakan API key di header Authorization. Request tanpa key yang valid akan ditolak dengan 401 UNAUTHORIZED.
Authorization: Bearer AQ_LIVE_xxxxxxxxxxxxxxxx
Content-Type: application/json
Accept: application/jsonMode uji & live
| Mode | Awalan key | Kegunaan |
|---|---|---|
| Uji | AQ_TEST_ | Development. Tagihan bisa disimulasikan lunas, tidak ada uang sungguhan. |
| Live | AQ_LIVE_ | Produksi. Lunas hanya bila pembayaran nyata terdeteksi. |
Objek tagihan
Semua endpoint tagihan mengembalikan objek berikut.
| Field | Tipe | Keterangan |
|---|---|---|
id | string | ID tagihan APIQris, diawali qr_. |
order_id | string | ID pesanan dari sistem Anda. |
amount | integer | Nominal asli yang diminta. |
unique_code | integer | Kode unik yang ditambahkan. |
total_amount | integer | Total yang harus dibayar pembeli (amount + unique_code). |
status | string | pending, paid, expired, atau cancelled. |
qris_string | string | String QRIS dinamis untuk dirender sendiri. |
qr_image_url | string | URL gambar QR PNG siap tampil. |
expires_at | string | Batas waktu pembayaran (ISO 8601, WIB). |
paid_at | string|null | Waktu lunas, null bila belum dibayar. |
Status tagihan
pendingMenunggu pembayaran.
paidPembayaran terdeteksi dan cocok.
expiredLewat masa berlaku tanpa pembayaran.
cancelledDibatalkan lewat API atau dashboard.
pending → paid atau pending → expired / cancelled. Status final tidak berubah lagi.
Kode unik
Notifikasi dana masuk hanya berisi nominal. Agar setiap pembayaran bisa dikenali, total tagihan ditambah kode unik kecil sehingga tidak ada dua tagihan pending di QRIS yang sama dengan total persis sama. Selalu tampilkan total_amount kepada pembeli, bukan amount.
Idempotensi
Pembuatan tagihan idempoten berdasarkan order_id. Jika koneksi terputus dan Anda mengulang request dengan order_id yang sama selama tagihan masih pending, APIQris mengembalikan tagihan yang sudah ada, bukan membuat yang baru. Aman untuk retry otomatis.
/invoicesBuat tagihan QRIS dinamis
Membuat QRIS dinamis dari QRIS Anda dengan nominal plus kode unik. Request dengan order_id yang sama saat tagihan masih pending mengembalikan tagihan yang sama (idempoten).
Body request
| Nama | Tipe | Wajib | Keterangan |
|---|---|---|---|
amount | integer | wajib | Nominal dalam rupiah, minimal 1.000. |
order_id | string | wajib | ID pesanan unik dari sistem Anda, maks 64 karakter. |
callback_url | string | opsional | URL webhook khusus tagihan ini. Default memakai URL di pengaturan toko. |
expired_minutes | integer | opsional | Masa berlaku 5 sampai 1440 menit. Default 30. |
qris_account_id | string | opsional | Pilih QRIS tertentu bila akun punya lebih dari satu. |
description | string | opsional | Keterangan tagihan, tampil di halaman bayar. |
customer_whatsapp | string | opsional | Nomor pembeli untuk notifikasi WhatsApp (format 62xxx). |
redirect_url | string | opsional | Halaman tujuan setelah lunas bila memakai halaman bayar. |
Contoh request
curl -X POST https://api.apiqris.com/v1/invoices \
-H "Authorization: Bearer $APIQRIS_KEY" \
-H "Content-Type: application/json" \
-d '{"amount":50000,"order_id":"INV-1024","expired_minutes":30}'const res = await fetch('https://api.apiqris.com/v1/invoices', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.APIQRIS_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({"amount":50000,"order_id":"INV-1024","expired_minutes":30}),
});
const data = await res.json();<?php
$ch = curl_init('https://api.apiqris.com/v1/invoices');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('APIQRIS_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'amount' => 50000,
'order_id' => 'INV-1024',
'expired_minutes' => 30,
]),
]);
$data = json_decode(curl_exec($ch), true);import os, requests
r = requests.post(
"https://api.apiqris.com/v1/invoices",
headers={"Authorization": f"Bearer {os.environ['APIQRIS_KEY']}"},
json={"amount": 50000, "order_id": "INV-1024", "expired_minutes": 30},
timeout=15,
)
data = r.json(){
"id": "qr_9KX2T7",
"order_id": "INV-1024",
"amount": 50000,
"unique_code": 123,
"total_amount": 50123,
"status": "pending",
"qris_string": "00020101021226...6304A1B2",
"qr_image_url": "https://api.apiqris.com/v1/qr/qr_9KX2T7.png",
"expires_at": "2026-10-17T10:15:00+07:00"
}{
"error": {
"code": "INVALID_REQUEST",
"message": "amount minimal 1000"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "API key tidak valid atau sudah dicabut"
}
}{
"error": {
"code": "RATE_LIMITED",
"message": "Terlalu banyak request, coba lagi setelah 1 detik"
}
}/invoices/{id}Ambil detail tagihan
Mengambil status terbaru tagihan. Parameter id bisa berupa id tagihan APIQris atau order_id milik Anda.
Path parameter
| Nama | Tipe | Wajib | Keterangan |
|---|---|---|---|
id | string | wajib | id tagihan (qr_xxx) atau order_id. |
Contoh request
curl -X GET https://api.apiqris.com/v1/invoices/INV-1024 \
-H "Authorization: Bearer $APIQRIS_KEY"const res = await fetch('https://api.apiqris.com/v1/invoices/INV-1024', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.APIQRIS_KEY}`,
},
});
const data = await res.json();<?php
$ch = curl_init('https://api.apiqris.com/v1/invoices/INV-1024');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('APIQRIS_KEY'),
'Content-Type: application/json',
],
]);
$data = json_decode(curl_exec($ch), true);import os, requests
r = requests.get(
"https://api.apiqris.com/v1/invoices/INV-1024",
headers={"Authorization": f"Bearer {os.environ['APIQRIS_KEY']}"},
timeout=15,
)
data = r.json(){
"id": "qr_9KX2T7",
"order_id": "INV-1024",
"amount": 50000,
"unique_code": 123,
"total_amount": 50123,
"status": "paid",
"qris_string": "00020101021226...6304A1B2",
"qr_image_url": "https://api.apiqris.com/v1/qr/qr_9KX2T7.png",
"expires_at": "2026-10-17T10:15:00+07:00",
"paid_at": "2026-10-17T10:03:12+07:00"
}{
"error": {
"code": "NOT_FOUND",
"message": "Tagihan tidak ditemukan"
}
}/invoices/{id}/cancelBatalkan tagihan
Membatalkan tagihan yang masih pending. Event invoice.cancelled dikirim ke webhook.
Path parameter
| Nama | Tipe | Wajib | Keterangan |
|---|---|---|---|
id | string | wajib | id tagihan atau order_id. |
Contoh request
curl -X POST https://api.apiqris.com/v1/invoices/INV-1024/cancel \
-H "Authorization: Bearer $APIQRIS_KEY"const res = await fetch('https://api.apiqris.com/v1/invoices/INV-1024/cancel', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.APIQRIS_KEY}`,
},
});
const data = await res.json();<?php
$ch = curl_init('https://api.apiqris.com/v1/invoices/INV-1024/cancel');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('APIQRIS_KEY'),
'Content-Type: application/json',
],
]);
$data = json_decode(curl_exec($ch), true);import os, requests
r = requests.post(
"https://api.apiqris.com/v1/invoices/INV-1024/cancel",
headers={"Authorization": f"Bearer {os.environ['APIQRIS_KEY']}"},
timeout=15,
)
data = r.json(){
"id": "qr_9KX2T7",
"order_id": "INV-1024",
"amount": 50000,
"unique_code": 123,
"total_amount": 50123,
"status": "cancelled",
"qris_string": "00020101021226...6304A1B2",
"qr_image_url": "https://api.apiqris.com/v1/qr/qr_9KX2T7.png",
"expires_at": "2026-10-17T10:15:00+07:00"
}{
"error": {
"code": "INVALID_STATE",
"message": "Tagihan sudah lunas dan tidak bisa dibatalkan"
}
}/invoices/{id}/simulateSimulasikan pembayaran
Hanya untuk API key mode uji (AQ_TEST_). Menandai tagihan lunas dan mengirim webhook seperti pembayaran sungguhan.
Path parameter
| Nama | Tipe | Wajib | Keterangan |
|---|---|---|---|
id | string | wajib | id tagihan atau order_id. |
Contoh request
curl -X POST https://api.apiqris.com/v1/invoices/INV-1024/simulate \
-H "Authorization: Bearer $APIQRIS_KEY"const res = await fetch('https://api.apiqris.com/v1/invoices/INV-1024/simulate', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.APIQRIS_KEY}`,
},
});
const data = await res.json();<?php
$ch = curl_init('https://api.apiqris.com/v1/invoices/INV-1024/simulate');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('APIQRIS_KEY'),
'Content-Type: application/json',
],
]);
$data = json_decode(curl_exec($ch), true);import os, requests
r = requests.post(
"https://api.apiqris.com/v1/invoices/INV-1024/simulate",
headers={"Authorization": f"Bearer {os.environ['APIQRIS_KEY']}"},
timeout=15,
)
data = r.json(){
"id": "qr_9KX2T7",
"order_id": "INV-1024",
"amount": 50000,
"unique_code": 123,
"total_amount": 50123,
"status": "paid",
"qris_string": "00020101021226...6304A1B2",
"qr_image_url": "https://api.apiqris.com/v1/qr/qr_9KX2T7.png",
"expires_at": "2026-10-17T10:15:00+07:00",
"paid_at": "2026-10-17T10:03:12+07:00"
}{
"error": {
"code": "FORBIDDEN",
"message": "Simulasi hanya tersedia untuk API key mode uji"
}
}/qris-accountsDaftar QRIS terhubung
Menampilkan QRIS yang terhubung ke akun beserta status HP pendeteksinya.
Contoh request
curl -X GET https://api.apiqris.com/v1/qris-accounts \
-H "Authorization: Bearer $APIQRIS_KEY"const res = await fetch('https://api.apiqris.com/v1/qris-accounts', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.APIQRIS_KEY}`,
},
});
const data = await res.json();<?php
$ch = curl_init('https://api.apiqris.com/v1/qris-accounts');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('APIQRIS_KEY'),
'Content-Type: application/json',
],
]);
$data = json_decode(curl_exec($ch), true);import os, requests
r = requests.get(
"https://api.apiqris.com/v1/qris-accounts",
headers={"Authorization": f"Bearer {os.environ['APIQRIS_KEY']}"},
timeout=15,
)
data = r.json(){
"data": [
{
"id": "qa_7Hf2",
"name": "GoPay Merchant Toko",
"merchant_name": "TOKO ANDA",
"nmid": "ID10xxxxxxxxx",
"device_online": true,
"is_default": true
}
]
}/meInfo akun
Mengecek API key dan melihat ringkasan akun, termasuk mode key (live/test).
Contoh request
curl -X GET https://api.apiqris.com/v1/me \
-H "Authorization: Bearer $APIQRIS_KEY"const res = await fetch('https://api.apiqris.com/v1/me', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.APIQRIS_KEY}`,
},
});
const data = await res.json();<?php
$ch = curl_init('https://api.apiqris.com/v1/me');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('APIQRIS_KEY'),
'Content-Type: application/json',
],
]);
$data = json_decode(curl_exec($ch), true);import os, requests
r = requests.get(
"https://api.apiqris.com/v1/me",
headers={"Authorization": f"Bearer {os.environ['APIQRIS_KEY']}"},
timeout=15,
)
data = r.json(){
"id": "usr_91aa",
"name": "Toko Anda",
"mode": "live",
"pending_invoices": 3,
"webhook_url": "https://tokoanda.com/webhook/qris"
}Event webhook
APIQris mengirim POST JSON ke callback URL setiap kali status tagihan berubah. Callback URL diatur per toko di dashboard atau per tagihan lewat callback_url.
| Event | Kapan dikirim |
|---|---|
invoice.paid | Tagihan lunas. Proses pesanan di sini. |
invoice.expired | Tagihan kedaluwarsa tanpa pembayaran. |
invoice.cancelled | Tagihan dibatalkan. |
ping | Uji koneksi dari dashboard. |
Contoh payload
POST /webhook/qris HTTP/1.1
Host: tokoanda.com
Content-Type: application/json
User-Agent: APIQris-Webhook/1.0
X-APIQris-Event: invoice.paid
X-APIQris-Signature: t=1760670192,v1=5f2b8c...e9d1
{
"event": "invoice.paid",
"id": "qr_9KX2T7",
"order_id": "INV-1024",
"amount": 50000,
"unique_code": 123,
"total_amount": 50123,
"status": "paid",
"paid_at": "2026-10-17T10:03:12+07:00",
"created_at": "2026-10-17T10:00:00+07:00"
}Verifikasi tanda tangan
Header X-APIQris-Signature berformat t=<timestamp>,v1=<hex>. Hitung ulang HMAC SHA-256 dari body mentah (sebelum di-parse) dan tolak bila tidak cocok atau timestamp lebih dari 5 menit.
signed_payload = timestamp + "." + raw_body
expected = HEX( HMAC_SHA256(webhook_secret, signed_payload) )
valid = constant_time_equal(expected, v1) AND |now - timestamp| <= 300<?php
$body = file_get_contents('php://input');
parse_str(str_replace(',', '&', $_SERVER['HTTP_X_APIQRIS_SIGNATURE'] ?? ''), $sig);
$expected = hash_hmac('sha256', $sig['t'] . '.' . $body, getenv('APIQRIS_SECRET'));
if (!hash_equals($expected, $sig['v1'] ?? '') || abs(time() - (int) $sig['t']) > 300) {
http_response_code(401);
exit;
}
$event = json_decode($body, true);
if ($event['event'] === 'invoice.paid') {
tandai_lunas($event['order_id']); // fungsi milik aplikasi Anda
}
http_response_code(200);Route::post('/webhook/qris', function (Request $request) {
parse_str(str_replace(',', '&', $request->header('X-APIQris-Signature')), $sig);
$expected = hash_hmac('sha256', $sig['t'].'.'.$request->getContent(), config('services.apiqris.secret'));
abort_unless(hash_equals($expected, $sig['v1'] ?? ''), 401);
if ($request->input('event') === 'invoice.paid') {
Order::where('number', $request->input('order_id'))->update(['status' => 'paid']);
}
return response()->noContent();
});import crypto from 'node:crypto';
import express from 'express';
const app = express();
app.post('/webhook/qris', express.raw({ type: 'application/json' }), (req, res) => {
const sig = Object.fromEntries(req.get('X-APIQris-Signature').split(',').map((p) => p.split('=')));
const expected = crypto.createHmac('sha256', process.env.APIQRIS_SECRET)
.update(`${sig.t}.${req.body}`).digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig.v1 ?? ''))) return res.sendStatus(401);
const event = JSON.parse(req.body);
if (event.event === 'invoice.paid') markPaid(event.order_id);
res.sendStatus(200);
});import hmac, hashlib, os
from flask import Flask, request, abort
app = Flask(__name__)
@app.post("/webhook/qris")
def webhook():
sig = dict(p.split("=", 1) for p in request.headers["X-APIQris-Signature"].split(","))
msg = f"{sig['t']}.".encode() + request.get_data()
expected = hmac.new(os.environ["APIQRIS_SECRET"].encode(), msg, hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, sig.get("v1", "")):
abort(401)
event = request.get_json()
if event["event"] == "invoice.paid":
mark_paid(event["order_id"])
return "", 200func webhook(w http.ResponseWriter, r *http.Request) {
body, _ := io.ReadAll(r.Body)
sig := map[string]string{}
for _, p := range strings.Split(r.Header.Get("X-APIQris-Signature"), ",") {
if k, v, ok := strings.Cut(p, "="); ok {
sig[k] = v
}
}
mac := hmac.New(sha256.New, []byte(os.Getenv("APIQRIS_SECRET")))
mac.Write([]byte(sig["t"] + "." + string(body)))
if !hmac.Equal([]byte(hex.EncodeToString(mac.Sum(nil))), []byte(sig["v1"])) {
http.Error(w, "invalid signature", http.StatusUnauthorized)
return
}
w.WriteHeader(http.StatusOK)
}# Header yang dikirim APIQris ke callback_url Anda
X-APIQris-Signature: t=1760670000,v1=5f2b...e9
Content-Type: application/json
{"event":"invoice.paid","id":"qr_9KX2T7","order_id":"INV-1024","total_amount":50123,"status":"paid"}Kirim ulang
Webhook dianggap berhasil bila server Anda membalas status 2xx dalam 10 detik. Bila gagal, APIQris mencoba lagi dengan jeda berikut:
Anda juga bisa melihat log respons dan menekan "kirim ulang" dari dashboard. Karena webhook bisa terkirim lebih dari sekali, pastikan proses Anda idempoten.
Kode error
Semua error memakai status HTTP yang sesuai dan body JSON berikut:
{
"error": {
"code": "INVALID_REQUEST",
"message": "amount minimal 1000"
}
}| HTTP | Kode | Arti & solusi |
|---|---|---|
| 400 | INVALID_REQUEST | Parameter salah atau kurang. Baca field message. |
| 401 | UNAUTHORIZED | API key tidak valid, salah format, atau sudah dicabut. |
| 403 | FORBIDDEN | Aksi tidak diizinkan untuk key ini (misalnya simulasi dengan key live). |
| 404 | NOT_FOUND | Tagihan atau sumber daya tidak ditemukan. |
| 409 | INVALID_STATE | Status tagihan tidak memungkinkan aksi tersebut. |
| 409 | NO_UNIQUE_SLOT | Kode unik untuk nominal ini sedang penuh. Coba lagi atau ubah nominal. |
| 429 | RATE_LIMITED | Terlalu banyak request. Ikuti header Retry-After. |
| 500 | INTERNAL_ERROR | Kesalahan di sisi kami. Aman untuk diulang dengan order_id yang sama. |
Batas request
| Jenis | Batas |
|---|---|
| Buat tagihan | 10 request/detik per akun |
| Endpoint lain | 120 request/menit per API key |
| Tagihan pending | Batas wajar per akun (lihat dashboard) |
Saat melewati batas, API membalas 429 RATE_LIMITED dengan header Retry-After (detik). Ulangi request setelah jeda tersebut.
Halaman bayar & redirect
Tidak ingin mendesain halaman QR sendiri? Arahkan pembeli ke halaman bayar APIQris yang menampilkan QR, total, dan hitung mundur. Setelah lunas, pembeli dikembalikan ke redirect_url.
// 1. Buat tagihan dengan redirect_url
const qris = await createInvoice({ amount: 50000, order_id: 'INV-1024', redirect_url: 'https://tokoanda.com/selesai' });
// 2. Arahkan pembeli ke halaman bayar APIQris
res.redirect(`https://app.apiqris.com/pay/${qris.id}`);
// 3. Setelah lunas pembeli kembali ke redirect_url,
// tetap andalkan webhook untuk menandai pesanan lunas.Checklist go-live
- Ganti API key uji (AQ_TEST_) dengan key live (AQ_LIVE_)
- Callback URL memakai HTTPS dan membalas 2xx dalam 10 detik
- Tanda tangan webhook diverifikasi sebelum memproses pesanan
- Proses webhook idempoten berdasarkan order_id
- API key disimpan di server, tidak di frontend atau aplikasi mobile
- HP pendamping online dan uji bayar Rp1.000 berhasil
Changelog
Rilis awal: tagihan QRIS dinamis, kode unik, webhook HMAC SHA-256 dengan kirim ulang, mode uji, multi QRIS.
Panduan per bahasa & platform
Belum yakin? Baca cara kerja dan FAQ, atau kembali ke halaman utama API QRIS gratis.