Introduction
StarQRIS REST API memungkinkan integrasi payment bridge Android, pendaftaran device, pencatatan pembayaran QRIS,
dan webhook ke sistem merchant. Semua endpoint menggunakan JSON dan prefix versi /api/v1.
https://starqris.web.id/api/v1
application/json
https://starqris.web.id/up
Setiap endpoint utama menyertakan contoh kode dalam cURL, JavaScript, Python, PHP, dan Go. Klik tab bahasa untuk melihat implementasinya.
Authentication
StarQRIS menggunakan tiga jenis kredensial tergantung siapa yang memanggil API.
| Credential | Header | Digunakan untuk |
|---|---|---|
| Merchant API Key | X-Api-Key: qris_xxx |
Register device dari app StarQRIS |
| Device token | Authorization: Bearer {device_token} |
Heartbeat & kirim payment dari Android |
| User token | Authorization: Bearer {user_token} |
Login API, lihat device/payment, test webhook |
API Key dibuat di dashboard → API Keys. Device token dikembalikan saat register device dan harus disimpan di app.
Quick Start
- Buat akun merchant (dashboard atau
POST /auth/register) - Generate API Key di dashboard
- Di app StarQRIS: isi API URL + API Key → Register device
- Buat invoice via API atau dashboard → dapat qris_payload dinamis per order
- Customer scan QRIS dinamis (nominal sudah terisi = total_amount)
- App membaca notifikasi bank →
POST /payments - Invoice otomatis
paid; webhook merchant terkirim jika dikonfigurasi
curl -X POST https://starqris.web.id/api/v1/devices/register \
-H "Content-Type: application/json" \
-H "X-Api-Key: qris_your_merchant_key" \
-d '{
"device_uid": "ef8a0b8f6386768c",
"name": "Kasir Utama",
"android_version": "14",
"app_version": "0.1.0",
"notification_listener_enabled": true
}'
curl -X POST https://starqris.web.id/api/v1/devices/register \
-H "Content-Type: application/json" \
-H "X-Api-Key: qris_your_merchant_key" \
-d '{
"device_uid": "ef8a0b8f6386768c",
"name": "Kasir Utama",
"android_version": "14",
"app_version": "0.1.0",
"notification_listener_enabled": true
}'
Auth
/auth/register
Register merchant
Public — tidak perlu auth
Membuat merchant baru + user owner. Mengembalikan Sanctum token untuk integrasi dashboard/API user.
{
"merchant_name": "Toko Saya",
"name": "Admin Toko",
"email": "admin@toko.test",
"password": "secret-password"
}
{
"user": {
"id": 1,
"name": "Admin Toko",
"email": "admin@toko.test",
"merchant": { "id": 1, "name": "Toko Saya" }
},
"token": "1|abc..."
}
curl -X POST https://starqris.web.id/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{
"merchant_name": "Toko Saya",
"name": "Admin Toko",
"email": "admin@toko.test",
"password": "secret-password"
}'
curl -X POST https://starqris.web.id/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{
"merchant_name": "Toko Saya",
"name": "Admin Toko",
"email": "admin@toko.test",
"password": "secret-password"
}'
/auth/login
Login
Public
Login user merchant. Password salah → 401.
{
"email": "admin@toko.test",
"password": "secret-password"
}
{
"user": { "id": 1, "name": "Admin Toko", "email": "admin@toko.test", "merchant": { } },
"token": "2|xyz..."
}
curl -X POST https://starqris.web.id/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"admin@toko.test","password":"secret-password"}'
curl -X POST https://starqris.web.id/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"admin@toko.test","password":"secret-password"}'
Devices
/devices/register
Register device
X-Api-Key (merchant) atau Bearer user token
Mendaftarkan atau re-register device Android. Re-register akan rotate device token (token lama invalid).
device_uid harus stabil per perangkat. App StarQRIS mengirim heartbeat setiap ~2 menit saat terhubung.
{
"device_uid": "ef8a0b8f6386768c",
"name": "hpjohan",
"android_version": "14",
"app_version": "0.1.0",
"notification_listener_enabled": true
}
{
"device": {
"id": 1,
"device_uid": "ef8a0b8f6386768c",
"name": "hpjohan",
"status": "active",
"connection_status": "online",
"notification_listener_enabled": true,
"last_seen_at": "2026-09-10T13:00:00+00:00"
},
"token": "3|device_token_simpan_di_app"
}
402 — Device limit reached for current plan
curl -X POST https://starqris.web.id/api/v1/devices/register \
-H "Content-Type: application/json" \
-H "X-Api-Key: qris_your_merchant_key" \
-d '{
"device_uid": "ef8a0b8f6386768c",
"name": "Kasir Utama",
"android_version": "14",
"app_version": "0.1.0",
"notification_listener_enabled": true
}'
curl -X POST https://starqris.web.id/api/v1/devices/register \
-H "Content-Type: application/json" \
-H "X-Api-Key: qris_your_merchant_key" \
-d '{
"device_uid": "ef8a0b8f6386768c",
"name": "Kasir Utama",
"android_version": "14",
"app_version": "0.1.0",
"notification_listener_enabled": true
}'
/devices/heartbeat
Device heartbeat
Bearer device token
Update status koneksi device. Dashboard menampilkan Online jika last_seen_at ≤ 5 menit.
{
"notification_listener_enabled": true,
"app_version": "0.1.0"
}
{
"device": { "id": 1, "connection_status": "online", "last_seen_at": "2026-09-10T13:02:00+00:00" },
"server_time": "2026-09-10T13:02:00+00:00"
}
403 — Device revoked atau bukan device token.
curl -X POST https://starqris.web.id/api/v1/devices/heartbeat \
-H "Content-Type: application/json" \
-H "Authorization: Bearer {device_token}" \
-d '{"notification_listener_enabled": true, "app_version": "0.1.0"}'
curl -X POST https://starqris.web.id/api/v1/devices/heartbeat \
-H "Content-Type: application/json" \
-H "Authorization: Bearer {device_token}" \
-d '{"notification_listener_enabled": true, "app_version": "0.1.0"}'
/devices/{id}
Get device
Bearer user token
Mengambil detail device milik merchant yang login.
{
"device": {
"id": 1,
"device_uid": "ef8a0b8f6386768c",
"name": "hpjohan",
"status": "active",
"connection_status": "online",
"last_seen_at": "2026-09-10T13:00:00+00:00",
"last_payment_at": "2026-09-10T12:55:00+00:00"
}
}
curl -X GET https://starqris.web.id/api/v1/devices/1 \
-H "Authorization: Bearer {user_token}"
curl -X GET https://starqris.web.id/api/v1/devices/1 \
-H "Authorization: Bearer {user_token}"
Invoices
StarQRIS mengkonversi QRIS statis merchant menjadi QRIS dinamis per invoice dengan nominal total_amount sudah terisi di payload EMV.
/invoices
Create invoice
X-Api-Key (merchant API key)
Membuat invoice pending. Response menyertakan qris_payload dinamis jika merchant sudah mendaftarkan QRIS statis.
{
"order_id": "WC-1042",
"amount": 50000,
"unique_code": 137,
"description": "Order #1042",
"customer_reference": "1042",
"expiration_hours": 48,
"qris_account_id": 1
}
{
"invoice": {
"id": 1,
"invoice_number": "INV-ABC12345",
"order_id": "WC-1042",
"amount": 50000,
"unique_code": 137,
"total_amount": 50137,
"status": "pending",
"description": "Order #1042",
"customer_reference": "1042",
"expires_at": "2026-09-12T13:00:00+00:00",
"paid_at": null,
"qris_account_id": 1,
"qris_payload": "00020101021226570011ID.DANA...6304A1B2",
"qris_base64": "data:image/png;base64,iVBORw0KGgo..."
}
}
qris_base64 opsional — PNG QR code siap tampil. Gunakan qris_payload untuk render QR di frontend.
curl -X POST https://starqris.web.id/api/v1/invoices \
-H "X-Api-Key: qris_your_merchant_key" \
-H "Content-Type: application/json" \
-d '{"order_id":"WC-1042","amount":50000,"unique_code":137}'
curl -X POST https://starqris.web.id/api/v1/invoices \
-H "X-Api-Key: qris_your_merchant_key" \
-H "Content-Type: application/json" \
-d '{"order_id":"WC-1042","amount":50000,"unique_code":137}'
/invoices/by-order/{orderId}
Get invoice by order ID
X-Api-Key
Mengambil invoice terbaru untuk merchant + order_id. Termasuk qris_payload dinamis jika tersedia.
curl -X GET https://starqris.web.id/api/v1/invoices/by-order/WC-1042 \
-H "X-Api-Key: qris_your_merchant_key"
curl -X GET https://starqris.web.id/api/v1/invoices/by-order/WC-1042 \
-H "X-Api-Key: qris_your_merchant_key"
/qris-accounts
List QRIS accounts
X-Api-Key
Daftar akun QRIS statis merchant (sumber template untuk generate QR dinamis). Field qris_payload berisi EMV statis.
Payments
/payments
Submit payment event
Bearer device token
Dikirim oleh app StarQRIS saat notifikasi QRIS terdeteksi. Server match ke invoice pending berdasarkan amount = total_amount.
{
"event_id": "550e8400-e29b-41d4-a716-446655440000",
"idempotency_key": "550e8400-e29b-41d4-a716-446655440000_abc123",
"fingerprint": "sha256-hash-unik-per-notif",
"amount": 50137,
"currency": "IDR",
"source_package": "id.bmri.livin",
"source_app": "Livin' by Mandiri",
"sender_name": "JOHN DOE",
"payment_source": "QRIS",
"received_at": "2026-09-10T13:05:00+00:00",
"raw_notification": {
"title": "Transfer masuk",
"text": "Rp50.137,00",
"source_package": "id.bmri.livin"
}
}
| Field | Required | Keterangan |
|---|---|---|
event_id | Ya | UUID unik per event |
idempotency_key | Ya | Cegah duplikat submit |
fingerprint | Ya | Hash unik per notifikasi per device |
amount | Ya | Integer Rupiah, harus = invoice total_amount |
received_at | Ya | ISO 8601 datetime |
{
"payment_event_id": 42,
"payment": {
"id": 15,
"invoice_id": "INV-ABC123",
"order_id": "ORDER-001",
"amount": 50137,
"status": "paid",
"sender_name": "JOHN DOE",
"paid_at": "2026-09-10T13:05:00+00:00"
}
}
{
"message": "Duplicate payment event.",
"payment_event_id": 42,
"payment_id": 15
}
402 — Transaction limit reached. Status lain: failed, ambiguous.
curl -X POST https://starqris.web.id/api/v1/payments \
-H "Content-Type: application/json" \
-H "Authorization: Bearer {device_token}" \
-d '{
"event_id": "550e8400-e29b-41d4-a716-446655440000",
"idempotency_key": "550e8400_abc123",
"fingerprint": "sha256-unik",
"amount": 50137,
"currency": "IDR",
"source_app": "Livin by Mandiri",
"sender_name": "JOHN DOE",
"received_at": "2026-09-10T13:05:00+00:00"
}'
curl -X POST https://starqris.web.id/api/v1/payments \
-H "Content-Type: application/json" \
-H "Authorization: Bearer {device_token}" \
-d '{
"event_id": "550e8400-e29b-41d4-a716-446655440000",
"idempotency_key": "550e8400_abc123",
"fingerprint": "sha256-unik",
"amount": 50137,
"currency": "IDR",
"source_app": "Livin by Mandiri",
"sender_name": "JOHN DOE",
"received_at": "2026-09-10T13:05:00+00:00"
}'
/payments/{id}
Get payment
Bearer device token atau user token
{
"payment": {
"id": 15,
"invoice_id": "INV-ABC123",
"order_id": "ORDER-001",
"amount": 50137,
"status": "paid",
"source_application": "Livin' by Mandiri",
"sender_name": "JOHN DOE",
"event_id": "550e8400-e29b-41d4-a716-446655440000",
"paid_at": "2026-09-10T13:05:00+00:00"
}
}
curl -X GET https://starqris.web.id/api/v1/payments/15 \
-H "Accept: application/json" \
-H "Authorization: Bearer {user_or_device_token}"
curl -X GET https://starqris.web.id/api/v1/payments/15 \
-H "Accept: application/json" \
-H "Authorization: Bearer {user_or_device_token}"
Outbound Webhooks
Saat payment status paid, StarQRIS POST ke URL webhook aktif di dashboard.
{
"event": "payment.success",
"invoice_id": "INV-ABC123",
"order_id": "ORDER-001",
"amount": 50137,
"status": "paid",
"paid_at": "2026-09-10T13:05:00+00:00",
"payment_id": 15,
"source_application": "Livin' by Mandiri"
}
Headers
Content-Type: application/jsonX-Webhook-Timestamp— Unix timestampX-Webhook-Idempotency-Key— Key unik per deliveryX-Webhook-Signature— HMAC-SHA256 dari{timestamp}.{raw_body}
# Webhook diterima di server merchant — contoh header masuk:
# X-Webhook-Timestamp: 1725978300
# X-Webhook-Signature: a1b2c3...
# Body: {"event":"payment.success",...}
# Webhook diterima di server merchant — contoh header masuk:
# X-Webhook-Timestamp: 1725978300
# X-Webhook-Signature: a1b2c3...
# Body: {"event":"payment.success",...}
Retry hingga 5x dengan exponential backoff (30s → max 1 jam).
Webhook Test
/webhooks/test
Queue test webhook
Bearer user token
{
"webhook_id": 1
}
{
"message": "Test webhook queued.",
"delivery_id": 99
}
422 jika tidak ada webhook aktif.
curl -X POST https://starqris.web.id/api/v1/webhooks/test \
-H "Content-Type: application/json" \
-H "Authorization: Bearer {user_token}" \
-d '{"webhook_id": 1}'
curl -X POST https://starqris.web.id/api/v1/webhooks/test \
-H "Content-Type: application/json" \
-H "Authorization: Bearer {user_token}" \
-d '{"webhook_id": 1}'
Payment Matching
- Cari invoice
pendingdengantotal_amount = amountdan belum expired - 0 kandidat → payment
failed - 1 kandidat → invoice & payment
paid, webhook dikirim - 2+ kandidat → refinement; jika masih ambigu →
ambiguous(resolve manual di dashboard)
| Payment status | Arti |
|---|---|
paid | Matched ke satu invoice |
failed | Tidak ada invoice yang cocok |
ambiguous | Lebih dari satu invoice cocok |
pending | Baru dibuat |
Errors & Limits
| HTTP | Kondisi |
|---|---|
401 | Unauthorized — API key/token invalid |
403 | Forbidden — device revoked / wrong token type |
402 | Plan limit (device atau transaksi) |
409 | Duplicate event_id / idempotency_key / fingerprint |
422 | Validation error |
429 | Rate limit exceeded (60/min) |
{
"message": "The amount field is required.",
"errors": {
"amount": ["The amount field is required."]
}
}