Buat transaksi QRIS — Partner Transactions API
Membuat QRIS dengan nominal yang sudah ditentukan (dynamic QRIS). QR string yang dihasilkan
hanya bisa dibayar satu kali dan akan kedaluwarsa sesuai expiredAt.
Setelah dibuat, transaksi diteruskan ke payment provider yang dipilih berdasarkan groupId.
Status pada response ini bukan status final transaksi; status akan diperbarui secara asinkron
melalui webhook dari provider.
Autentikasi
Kirim header Authorization: Bearer <accessToken>, memakai accessToken yang didapat dari
Partner Auth API. Butuh permission transactions:create.
Idempotency
Wajib kirim header Idempotency-Key (string non-kosong apa pun -- rekomendasi kami: UUID v4) di
setiap request. Request kedua dengan key yang sama dan body yang sama persis mengembalikan
response yang identik tanpa memproses ulang. Body berbeda dengan key yang sama menghasilkan
409 Conflict. Lihat panduan lengkap di Idempotency.
| Header | Wajib | Deskripsi |
|---|---|---|
Idempotency-Key | Ya | Unik per percobaan transaksi (BUKAN per retry -- gunakan key yang sama untuk retry dari transaksi yang sama). Rekomendasi: UUID v4. |
Request body
| Field | Tipe | Wajib | Deskripsi |
|---|---|---|---|
externalReference | string (maks 100) | Ya | ID unik transaksi dari sisi kamu, untuk rekonsiliasi. Harus unik per partner. |
amount | integer (Long) | Ya | Nominal dalam Rupiah (bilangan bulat, tidak ada sen). Minimum 100 (= Rp 100). Contoh: 15000 = Rp 15.000. |
description | string (maks 500) | Tidak | Keterangan transaksi, bisa ditampilkan ke customer. |
groupId | UUID | Ya | Group tujuan. Provider yang dipakai ditentukan oleh Routing Configuration yang di-setup untuk group ini (gateway Primary dengan weight, Backup dengan urutan priority buat failover) -- request ini sendiri tidak punya parameter untuk memaksa provider tertentu, tapi kamu bisa atur pool provider & prioritasnya lewat Routing Configuration. |
expiredAt | ISO-8601 UTC | Tidak | Waktu kedaluwarsa QRIS. Kalau kosong, ditentukan provider (biasanya 30 menit). |
Contoh request
- cURL
- Node.js
- Java
curl -X POST '{{BASE_URL}}/api/v1/transactions/qris' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"externalReference": "INV-2026-001234",
"amount": 150000,
"description": "Pembayaran order #INV-2026-001234",
"groupId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"expiredAt": "2026-07-07T10:30:00Z"
}'
import { randomUUID } from "node:crypto";
const response = await fetch("{{BASE_URL}}/api/v1/transactions/qris", {
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Idempotency-Key": randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
externalReference: "INV-2026-001234",
amount: 150000,
description: "Pembayaran order #INV-2026-001234",
groupId: "3fa85f64-5717-4562-b3fc-2c963f66afa6",
expiredAt: "2026-07-07T10:30:00Z",
}),
});
const data = await response.json();
console.log(data);
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.UUID;
String requestBody =
"""
{
"externalReference": "INV-2026-001234",
"amount": 150000,
"description": "Pembayaran order #INV-2026-001234",
"groupId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"expiredAt": "2026-07-07T10:30:00Z"
}
""";
HttpClient client = HttpClient.newHttpClient();
HttpRequest request =
HttpRequest.newBuilder()
.uri(URI.create("{{BASE_URL}}/api/v1/transactions/qris"))
.header("Authorization", "Bearer " + accessToken)
.header("Idempotency-Key", UUID.randomUUID().toString())
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
Response sukses
201 Created
{
"code": "00",
"message": "Success",
"data": {
"transactionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"partnerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"groupId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"externalReference": "INV-2026-001234",
"platformReference": "TXN-20260707-A1B2C3",
"transactionType": "PAYMENT",
"paymentMethod": "QRIS_DYNAMIC",
"status": "PENDING",
"amount": 150000,
"currency": "IDR",
"providerCode": "GDC",
"providerReference": null,
"qrString": "00020101021226...",
"expiredAt": "2026-07-07T10:30:00Z",
"description": "Pembayaran order #INV-2026-001234",
"createdAt": "2026-07-07T09:00:00Z",
"updatedAt": "2026-07-07T09:00:00Z"
},
"correlationId": "9f8e7d6c-5b4a-3210-fedc-ba9876543210",
"requestId": "1a2b3c4d-5e6f-7890-abcd-ef1234567890",
"timestamp": "2026-08-13T09:15:30.123Z"
}
providerCode di atas hanya contoh -- provider yang benar-benar dipakai ditentukan otomatis saat
runtime berdasarkan groupId kamu, bisa berbeda dari contoh ini.
Render data.qrString sebagai kode QR untuk ditampilkan ke customer. Pantau data.status lewat
polling Detail transaksi sampai berstatus SUCCESS, FAILED, atau EXPIRED.
Response error
| HTTP Status | code | Kapan terjadi |
|---|---|---|
| 400 | VALIDATION_ERROR | Field wajib kosong/format salah, ATAU header Idempotency-Key tidak dikirim sama sekali. |
| 400 | IDEMPOTENCY_KEY_REQUIRED | Header Idempotency-Key dikirim tapi isinya kosong/blank. |
| 401 | INVALID_TOKEN | Authorization header tidak ada, JWT tidak valid, atau kadaluarsa. |
| 403 | ACCESS_DENIED | Tidak punya permission transactions:create. |
| 403 | GROUP_NOT_OWNED | groupId tidak ditemukan atau bukan milik partner ini. |
| 403 | GROUP_INACTIVE | groupId valid tapi statusnya sudah tidak aktif. |
| 409 | DUPLICATE_TRANSACTION | externalReference sudah pernah dipakai partner ini sebelumnya. |
| 409 | IDEMPOTENCY_KEY_CONFLICT | Idempotency-Key sudah dipakai sebelumnya dengan body request yang berbeda. |
| 409 | IDEMPOTENCY_REQUEST_IN_PROGRESS | Request lain dengan Idempotency-Key yang sama masih diproses -- coba lagi sebentar. |
| 422 | NO_GATEWAY | Tidak ada gateway pembayaran yang eligible untuk groupId ini saat ini. |
| 422 | NO_CREDENTIAL | Gateway ditemukan tapi belum ada credential yang terpasang untuk groupId ini. |
| 500 | INTERNAL_ERROR | Gateway/provider pembayaran tidak bisa dihubungi atau timeout -- aman di-retry dengan Idempotency-Key yang sama. |
{
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"data": {
"amount": "must not be null",
"groupId": "must not be null"
},
"correlationId": "9f8e7d6c-5b4a-3210-fedc-ba9876543210",
"requestId": "1a2b3c4d-5e6f-7890-abcd-ef1234567890",
"timestamp": "2026-08-13T09:15:30.123Z"
}
{
"code": "IDEMPOTENCY_KEY_CONFLICT",
"message": "Idempotency-Key 'a1b2c3d4-...' sudah pernah dipakai dengan request body yang berbeda.",
"correlationId": "9f8e7d6c-5b4a-3210-fedc-ba9876543210",
"requestId": "1a2b3c4d-5e6f-7890-abcd-ef1234567890",
"timestamp": "2026-08-13T09:15:30.123Z"
}
{
"code": "DUPLICATE_TRANSACTION",
"message": "External reference sudah digunakan: INV-2026-001234",
"correlationId": "9f8e7d6c-5b4a-3210-fedc-ba9876543210",
"requestId": "1a2b3c4d-5e6f-7890-abcd-ef1234567890",
"timestamp": "2026-08-13T09:15:30.123Z"
}