StarQRIS API
REST API Reference v1
Dashboard | Tutorial |

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.

Base URL
https://starqris.web.id/api/v1
Content-Type
application/json
Rate limit
60 requests / minute per IP
Health check
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

  1. Buat akun merchant (dashboard atau POST /auth/register)
  2. Generate API Key di dashboard
  3. Di app StarQRIS: isi API URL + API Key → Register device
  4. Buat invoice via API atau dashboard → dapat qris_payload dinamis per order
  5. Customer scan QRIS dinamis (nominal sudah terisi = total_amount)
  6. App membaca notifikasi bank → POST /payments
  7. Invoice otomatis paid; webhook merchant terkirim jika dikonfigurasi
Register device — contoh request
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

POST /auth/register

Register merchant

Public — tidak perlu auth

Membuat merchant baru + user owner. Mengembalikan Sanctum token untuk integrasi dashboard/API user.

Request body
{
  "merchant_name": "Toko Saya",
  "name": "Admin Toko",
  "email": "admin@toko.test",
  "password": "secret-password"
}
Response 201
{
  "user": {
    "id": 1,
    "name": "Admin Toko",
    "email": "admin@toko.test",
    "merchant": { "id": 1, "name": "Toko Saya" }
  },
  "token": "1|abc..."
}
Register merchant — contoh request
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" }'
POST /auth/login

Login

Public

Login user merchant. Password salah → 401.

Request body
{
  "email": "admin@toko.test",
  "password": "secret-password"
}
Response 200
{
  "user": { "id": 1, "name": "Admin Toko", "email": "admin@toko.test", "merchant": { } },
  "token": "2|xyz..."
}
Login — contoh request
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

POST /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.

Request body
{
  "device_uid": "ef8a0b8f6386768c",
  "name": "hpjohan",
  "android_version": "14",
  "app_version": "0.1.0",
  "notification_listener_enabled": true
}
Response 201
{
  "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

Register device — contoh request
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 }'
POST /devices/heartbeat

Device heartbeat

Bearer device token

Update status koneksi device. Dashboard menampilkan Online jika last_seen_at ≤ 5 menit.

Request body
{
  "notification_listener_enabled": true,
  "app_version": "0.1.0"
}
Response 200
{
  "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.

Heartbeat — contoh request
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"}'
GET /devices/{id}

Get device

Bearer user token

Mengambil detail device milik merchant yang login.

Response 200
{
  "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"
  }
}
Get device — contoh request
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.

POST /invoices

Create invoice

X-Api-Key (merchant API key)

Membuat invoice pending. Response menyertakan qris_payload dinamis jika merchant sudah mendaftarkan QRIS statis.

Request body
{
  "order_id": "WC-1042",
  "amount": 50000,
  "unique_code": 137,
  "description": "Order #1042",
  "customer_reference": "1042",
  "expiration_hours": 48,
  "qris_account_id": 1
}
Response 201
{
  "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.

Create invoice — contoh request
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}'
GET /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.

Get invoice — contoh request
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"
GET /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

POST /payments

Submit payment event

Bearer device token

Dikirim oleh app StarQRIS saat notifikasi QRIS terdeteksi. Server match ke invoice pending berdasarkan amount = total_amount.

Request body
{
  "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"
  }
}
FieldRequiredKeterangan
event_idYaUUID unik per event
idempotency_keyYaCegah duplikat submit
fingerprintYaHash unik per notifikasi per device
amountYaInteger Rupiah, harus = invoice total_amount
received_atYaISO 8601 datetime
Response 201 — matched
{
  "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"
  }
}
Response 409 — duplicate
{
  "message": "Duplicate payment event.",
  "payment_event_id": 42,
  "payment_id": 15
}

402 — Transaction limit reached. Status lain: failed, ambiguous.

Submit payment — contoh request
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" }'
GET /payments/{id}

Get payment

Bearer device token atau user token

Response 200
{
  "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"
  }
}
Get payment — contoh request
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.

Payload payment.success
{
  "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/json
  • X-Webhook-Timestamp — Unix timestamp
  • X-Webhook-Idempotency-Key — Key unik per delivery
  • X-Webhook-Signature — HMAC-SHA256 dari {timestamp}.{raw_body}
Verifikasi webhook signature
# 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

POST /webhooks/test

Queue test webhook

Bearer user token

Request body (optional)
{
  "webhook_id": 1
}
Response 200
{
  "message": "Test webhook queued.",
  "delivery_id": 99
}

422 jika tidak ada webhook aktif.

Test webhook — contoh request
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

  1. Cari invoice pending dengan total_amount = amount dan belum expired
  2. 0 kandidat → payment failed
  3. 1 kandidat → invoice & payment paid, webhook dikirim
  4. 2+ kandidat → refinement; jika masih ambigu → ambiguous (resolve manual di dashboard)
Payment statusArti
paidMatched ke satu invoice
failedTidak ada invoice yang cocok
ambiguousLebih dari satu invoice cocok
pendingBaru dibuat

Errors & Limits

HTTPKondisi
401Unauthorized — API key/token invalid
403Forbidden — device revoked / wrong token type
402Plan limit (device atau transaksi)
409Duplicate event_id / idempotency_key / fingerprint
422Validation error
429Rate limit exceeded (60/min)
Validation error example
{
  "message": "The amount field is required.",
  "errors": {
    "amount": ["The amount field is required."]
  }
}