Relay Merchant API
Selamat datang di dokumentasi Relay Merchant API — platform PPOB (Payment Point Online Bank) untuk merchant yang ingin mengintegrasikan layanan pembayaran, transfer dana, dan penerimaan pembayaran QRIS ke dalam sistem mereka.
Cakupan Dokumentasi
Dokumentasi ini mencakup seluruh endpoint API yang tersedia untuk merchant:
| Kategori | Deskripsi | Base Path |
|---|---|---|
| PPOB | Pulsa, e-wallet, token PLN, tagihan PLN, BPJS | /api/v1/merchant/ppob |
| Disbursement | Transfer dana ke rekening bank | /api/v1/merchant/disbursement |
| PayIn QRIS | Terima pembayaran via QRIS | /api/v1/merchant/payin |
| Utilitas | Cek saldo, katalog produk | /api/v1/balance, /api/v1/product |
Base URL
| Lingkungan | URL |
|---|---|
| Sandbox | https://api-sandbox.alfakios.com |
| Production | https://api.alfakios.com |
Gunakan lingkungan Sandbox untuk pengembangan dan pengujian. Transaksi sandbox tidak memotong saldo nyata.
Prasyarat Integrasi
Sebelum mulai mengintegrasikan API, pastikan Anda memiliki:
- Akun merchant yang telah aktif di CMS (backoffice).
- API Key yang di-generate dari menu API Keys di CMS.
- Signature Secret (opsional, jika fitur Signature Validation diaktifkan) — diberikan oleh tim support.
- Saldo deposit yang cukup untuk melakukan transaksi.
Cara Membaca Dokumentasi Ini
- Memulai Integrasi — baca bagian ini terlebih dahulu untuk memahami mekanisme autentikasi dan format request/response.
- Kategori API — setiap kategori memiliki halaman gambaran umum yang menjelaskan alur transaksi, diikuti halaman detail per endpoint.
- Lampiran — contoh integrasi end-to-end dalam berbagai bahasa pemrograman.
Konvensi Dokumen
- Field bertanda *Ya* pada tabel request wajib disertakan.
- Semua contoh menggunakan
apk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxsebagai placeholder API Key — ganti dengan API Key Anda yang sebenarnya. - Nominal (
amount) selalu berupa string digit dalam satuan IDR (contoh:"100000"= Rp 100.000).
Bantuan Teknis
Untuk pertanyaan teknis terkait integrasi, hubungi tim Backend API melalui grup WhatsApp yang dibuat oleh marketing.
Autentikasi API Key
Semua endpoint Merchant API menggunakan autentikasi berbasis API Key melalui header X-API-Key.
Generate API Key dari CMS
- Login ke CMS dengan akun merchant.
- Buka menu API Keys.
- Klik tombol Generate New API Key.
- Salin dan simpan API Key yang ditampilkan — nilai ini hanya ditampilkan sekali.
- API Key yang aktif dapat dinonaktifkan atau dihapus kapan saja dari halaman yang sama.
Keamanan: Jangan simpan API Key di repositori kode, file
.envyang di-commit, atau tempat yang dapat diakses publik. Jika API Key bocor, segera nonaktifkan dan generate ulang melalui CMS.
Format API Key
apk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Header Wajib
Setiap request ke Merchant API harus menyertakan header berikut:
| Header | Tipe | Wajib | Keterangan |
|---|---|---|---|
X-API-Key | String | Ya | API Key merchant dari CMS |
Content-Type | String | Ya | Harus bernilai application/json |
Header Opsional (jika Signature Validation aktif)
| Header | Tipe | Kondisi | Keterangan |
|---|---|---|---|
X-Signature | String | Jika aktif | Base64 HMAC-SHA256 signature dari request body |
X-Timestamp | String | Jika aktif | Unix timestamp dalam detik (integer) |
Lihat Signature Validation untuk detail lebih lanjut.
Contoh Request
POST /api/v1/merchant/ppob/phone-credit/transaction HTTP/1.1
Host: api-sandbox.alfakios.com
Content-Type: application/json
X-API-Key: apk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
{
"req_id": "TXN-20240501-001",
"product_id": "XL5",
"cust_id": "08123456789"
}
Response Error Autentikasi
API Key tidak ada atau tidak valid
{
"success": false,
"message": "Unauthorized",
"error": "Invalid or missing API Key"
}
HTTP Status: 401 Unauthorized
API Key tidak memiliki akses endpoint ini
{
"success": false,
"message": "Forbidden",
"error": "API Key does not have permission to access this resource"
}
HTTP Status: 403 Forbidden
Akun merchant tidak aktif
{
"success": false,
"message": "Forbidden",
"error": "Merchant account is inactive"
}
HTTP Status: 403 Forbidden
Validasi Tambahan
Selain API Key, sistem juga menerapkan:
- IP Restriction — jika merchant telah mendaftarkan IP whitelist, hanya request dari IP tersebut yang diterima.
- Rate Limiting — request dibatasi per merchant untuk mencegah abuse.
- Timeout — setiap request memiliki batas waktu pemrosesan 8 detik. Jika biller tidak merespons dalam 8 detik, sistem akan mengembalikan error.
Signature Validation
Signature Validation adalah lapisan keamanan tambahan menggunakan HMAC-SHA256 untuk memverifikasi integritas dan keaslian setiap request. Fitur ini opsional dan dapat diaktifkan per merchant oleh admin.
Cara Kerja
1. timestamp = unix timestamp saat ini (integer, dalam detik)
2. body_string = JSON string persis dari request body
3. string_to_sign = body_string + ":" + timestamp
4. signature = Base64( HMAC-SHA256( secret_key, string_to_sign ) )
Catatan penting:
body_stringharus identik byte-for-byte dengan body yang dikirim dalam request. Jangan pretty-print atau ubah urutan field JSON.
Signature Secret
secret_key adalah nilai terpisah dari X-API-Key. Nilai ini:
- Tidak ditampilkan di CMS
- Diberikan langsung oleh tim support saat aktivasi fitur Signature Validation
- Harus disimpan dengan aman dan tidak pernah di-commit ke repositori
Validasi Timestamp
Sistem menolak request jika:
- Timestamp lebih dari 300 detik (5 menit) di masa lalu
- Timestamp lebih dari 60 detik di masa depan
Hal ini mencegah replay attack.
Implementasi per Bahasa
PHP
<?php
$secretKey = "signature_secret_dari_support";
$body = ['product_id' => 'XL5', 'cust_id' => '08123456789', 'req_id' => 'TXN-001'];
$bodyString = json_encode($body, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$timestamp = time();
$toSign = $bodyString . ":" . $timestamp;
$signature = base64_encode(hash_hmac('sha256', $toSign, $secretKey, true));
// Kirim dalam header
// X-Signature: $signature
// X-Timestamp: $timestamp
?>
Node.js
const crypto = require('crypto');
const secretKey = 'signature_secret_dari_support';
const body = { product_id: 'XL5', cust_id: '08123456789', req_id: 'TXN-001' };
const bodyString = JSON.stringify(body); // urutan key harus sama dengan yang dikirim
const timestamp = Math.floor(Date.now() / 1000);
const toSign = `${bodyString}:${timestamp}`;
const signature = crypto
.createHmac('sha256', secretKey)
.update(toSign)
.digest('base64');
Python
import hmac, hashlib, base64, time, json
secret_key = "signature_secret_dari_support"
body = {"product_id": "XL5", "cust_id": "08123456789", "req_id": "TXN-001"}
body_string = json.dumps(body, separators=(',', ':'), ensure_ascii=False)
timestamp = int(time.time())
to_sign = f"{body_string}:{timestamp}"
signature = base64.b64encode(
hmac.new(secret_key.encode(), to_sign.encode(), hashlib.sha256).digest()
).decode()
Java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
String secretKey = "signature_secret_dari_support";
String bodyString = "{\"product_id\":\"XL5\",\"cust_id\":\"08123456789\",\"req_id\":\"TXN-001\"}";
long timestamp = System.currentTimeMillis() / 1000;
String toSign = bodyString + ":" + timestamp;
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(secretKey.getBytes("UTF-8"), "HmacSHA256"));
String signature = Base64.getEncoder().encodeToString(mac.doFinal(toSign.getBytes("UTF-8")));
Go
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"time"
)
secretKey := "signature_secret_dari_support"
body := map[string]string{
"product_id": "XL5",
"cust_id": "08123456789",
"req_id": "TXN-001",
}
bodyBytes, _ := json.Marshal(body)
timestamp := time.Now().Unix()
toSign := fmt.Sprintf("%s:%d", string(bodyBytes), timestamp)
mac := hmac.New(sha256.New, []byte(secretKey))
mac.Write([]byte(toSign))
signature := base64.StdEncoding.EncodeToString(mac.Sum(nil))
Rust
#![allow(unused)]
fn main() {
use hmac::{Hmac, Mac};
use sha2::Sha256;
use base64::{engine::general_purpose, Engine};
use std::time::{SystemTime, UNIX_EPOCH};
type HmacSha256 = Hmac<Sha256>;
let secret_key = "signature_secret_dari_support";
let body_string = r#"{"product_id":"XL5","cust_id":"08123456789","req_id":"TXN-001"}"#;
let timestamp = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
let to_sign = format!("{}:{}", body_string, timestamp);
let mut mac = HmacSha256::new_from_slice(secret_key.as_bytes()).unwrap();
mac.update(to_sign.as_bytes());
let signature = general_purpose::STANDARD.encode(mac.finalize().into_bytes());
}
Tambahkan ke
Cargo.toml:hmac = "0.12",sha2 = "0.10",base64 = "0.22"
Contoh Request dengan Signature
POST /api/v1/merchant/disbursement/payment HTTP/1.1
Host: api-sandbox.alfakios.com
Content-Type: application/json
X-API-Key: apk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
X-Signature: uW8tV+R6zKpN1234ABCDabcd==
X-Timestamp: 1714435200
{"req_id":"PAY-001","product_id":"DSTF","account_number":"1234567890","amount":"100000"}
Response Error Signature
{
"success": false,
"message": "Invalid signature",
"error": "Signature validation failed"
}
HTTP Status: 401 Unauthorized
Format Response
Semua endpoint Merchant API mengembalikan response dalam format JSON dengan struktur yang konsisten.
Envelope Response
{
"success": true,
"message": "Keterangan singkat hasil operasi",
"rc": "000",
"data": { ... }
}
| Field | Tipe | Keterangan |
|---|---|---|
success | Boolean | true jika request diproses tanpa error HTTP-level |
message | String | Pesan singkat yang mendeskripsikan hasil |
rc | String | Kode respon bisnis — "000" = sukses; kode lain lihat Kode Respon |
data | Object/Array/null | Payload hasil operasi; struktur bervariasi per endpoint |
Catatan:
success: trueberarti HTTP request berhasil diproses, bukan berarti transaksi bisnis berhasil. Selalu cek fieldrcdandata.statusuntuk status transaksi.
HTTP Status Codes
| HTTP Status | Kapan Terjadi |
|---|---|
200 OK | Request berhasil diproses (termasuk transaksi FAILED/PENDING) |
400 Bad Request | Format body tidak valid |
401 Unauthorized | API Key tidak valid atau signature gagal |
403 Forbidden | API Key valid tapi tidak punya akses, atau merchant nonaktif |
404 Not Found | Resource tidak ditemukan (contoh: transaksi tidak ada) |
422 Unprocessable Entity | Validasi field gagal (contoh: field wajib kosong, format salah) |
500 Internal Server Error | Error internal server |
Response Validasi Error (422)
{
"success": false,
"message": "Validation failed",
"errors": [
{
"field": "amount",
"message": "amount must be a positive integer (digits only)"
},
{
"field": "product_id",
"message": "product_id is required"
}
]
}
Response Transaksi Sukses
{
"success": true,
"message": "Transaction completed successfully",
"rc": "000",
"data": {
"req_id": "TXN-20240501-001",
"ref_id": "1777946295495371000",
"product_id": "XL5",
"cust_id": "08123456789",
"status": "SUCCESS",
"rc": "000",
"description": "Transaksi Sukses",
"message": "PULSA XL 5000 KE 08123456789 SUKSES",
"amount": "5000",
"unit_price": "5500",
"balance_used": "5500",
"balance": "494500",
"serial_no": "REF123456789",
"data": {}
}
}
Response Transaksi Gagal
{
"success": true,
"message": "Transaction completed",
"rc": "008",
"data": {
"req_id": "TXN-20240501-002",
"ref_id": "1777946295495372000",
"status": "FAILED",
"rc": "008",
"description": "Insufficient Balance",
"message": "Saldo deposit tidak mencukupi",
"balance": "1000",
"data": {}
}
}
Field data Umum
Hampir semua endpoint transaksi mengembalikan field berikut dalam data:
| Field | Tipe | Keterangan |
|---|---|---|
req_id | String | ID unik dari merchant (idempotency key) |
ref_id | String | ID referensi internal sistem |
product_id | String | Kode produk yang digunakan |
cust_id | String | ID customer / nomor tujuan |
status | String | SUCCESS, FAILED, atau PENDING |
rc | String | Kode respon biller atau sistem |
description | String | Keterangan RC |
message | String | Pesan detail dari biller/sistem |
amount | String | Nominal transaksi dalam IDR |
unit_price | String | Harga satuan produk |
balance_used | String | Saldo yang dipotong |
balance | String | Saldo merchant setelah transaksi |
serial_no | String | Nomor seri / token dari biller |
data | Object | Data tambahan dari biller (bervariasi) |
Idempotency
Semua endpoint transaksi berbayar mendukung idempotency via field req_id:
- Jika request gagal karena timeout atau error jaringan, kirim ulang dengan
req_idyang sama — sistem mengembalikan hasil transaksi pertama tanpa debit ganda. - Gunakan
req_idberbeda untuk setiap transaksi baru. - Format
req_idyang disarankan:{PREFIX}-{YYYYMMDD}-{SEQUENCE}— contoh:TXN-20240501-001.
Strict JSON
Semua endpoint menggunakan strict JSON parsing:
- Field yang tidak dikenal dalam request body akan ditolak dengan
422 Unprocessable Entity. - Kirim hanya field yang didokumentasikan.
Kode Respon (RC)
Field rc pada response menunjukkan hasil bisnis dari transaksi. Kode "000" selalu berarti sukses.
Kode Umum (Semua Kategori)
| RC | Status | Keterangan | Saldo Terpotong |
|---|---|---|---|
000 | SUCCESS | Transaksi berhasil | Ya |
002 | FAILED | Transaksi tidak ditemukan | Tidak |
005 | FAILED | Kode produk tidak dikenal / pricing tidak tersedia | Tidak |
006 | FAILED | Produk tidak aktif | Tidak |
007 | FAILED | Produk sedang maintenance | Tidak |
008 | FAILED | Saldo deposit tidak cukup | Tidak |
009 | FAILED | Error pada biller saat inquiry | Tidak |
021 | PENDING | Transaksi sedang diproses (menunggu konfirmasi) | Ya (menunggu final) |
022 | FAILED | Koneksi ke biller gagal (auto-refund) | Auto-refunded |
023 | FAILED | Response biller kosong (auto-refund) | Auto-refunded |
Kode Disbursement
| RC | Status | Keterangan | Saldo Terpotong |
|---|---|---|---|
051 | FAILED | Rekening tujuan tidak ditemukan / tidak aktif | Tidak |
00 | SUCCESS | Transfer sukses (RC dari biller) | Ya |
Kode PPOB
| RC | Status | Keterangan |
|---|---|---|
00 | SUCCESS | Transaksi sukses (RC dari biller APKITA/TEKTAYA) |
14 | FAILED | Nomor pelanggan tidak valid |
40 | FAILED | Produk tidak tersedia untuk operator ini |
68 | PENDING | Transaksi diproses, menunggu konfirmasi |
91 | FAILED | Biller tidak tersedia (maintenance) |
Kode RC dari biller pihak ketiga dapat bervariasi. Selalu cek field
descriptionuntuk keterangan yang lebih detail.
Kode QRIS PayIn
| RC | Status | Keterangan |
|---|---|---|
000 | SUCCESS | QRIS berhasil dibuat / dikonfirmasi |
021 | PENDING | Menunggu pembayaran dari pelanggan |
031 | FAILED | QRIS kedaluwarsa (expired) |
032 | FAILED | QRIS sudah dibayar sebelumnya |
Policy Refund Otomatis
| Kondisi | Saldo | Policy |
|---|---|---|
| RC 005, 006, 007, 008, 009 | Tidak pernah terpotong | Tidak ada refund |
| RC 051 (rekening tidak ditemukan) | Tidak terpotong | Tidak ada refund |
| RC 021 → konfirmasi SUCCESS | Terpotong, final sukses | Tidak ada refund |
| RC 021 → konfirmasi FAILED | Terpotong | Sistem otomatis refund |
| RC 022 (biller call failed) | Terpotong | Sistem otomatis refund |
| RC 023 (empty biller response) | Terpotong | Sistem otomatis refund |
Menangani Status PENDING
Ketika menerima rc: "021" atau status: "PENDING":
- Jangan mengirim ulang request payment — ini dapat menyebabkan debit ganda.
- Gunakan endpoint cek status (
/ppob/checkatau/disbursement/status) denganreq_idyang sama. - Polling dengan interval yang meningkat:
Attempt 1 : tunggu 30 detik
Attempt 2 : tunggu 60 detik
Attempt 3 : tunggu 120 detik
Attempt 4 : tunggu 300 detik
Attempt 5+: eskalasi ke tim support dengan menyertakan req_id
Gambaran Umum PPOB
PPOB (Payment Point Online Bank) API memungkinkan merchant untuk melakukan transaksi pembelian produk digital dan pembayaran tagihan melalui sistem Relay.
Endpoint yang Tersedia
| Endpoint | Metode | Keterangan |
|---|---|---|
POST /api/v1/merchant/ppob/check | POST | Cek status transaksi berdasarkan order_req_id |
POST /api/v1/merchant/ppob/phone-credit/transaction | POST | Beli pulsa / paket data |
POST /api/v1/merchant/ppob/ewallet/inquiry | POST | Inquiry sebelum top-up e-wallet |
POST /api/v1/merchant/ppob/ewallet/transaction | POST | Eksekusi top-up e-wallet |
POST /api/v1/merchant/ppob/pln/prepaid/inquiry | POST | Inquiry token listrik PLN prabayar |
POST /api/v1/merchant/ppob/pln/prepaid/transaction | POST | Beli token listrik PLN prabayar |
POST /api/v1/merchant/ppob/pln/postpaid/inquiry | POST | Inquiry tagihan PLN pascabayar |
POST /api/v1/merchant/ppob/pln/postpaid/transaction | POST | Bayar tagihan PLN pascabayar |
POST /api/v1/merchant/ppob/bpjs/inquiry | POST | Inquiry tagihan BPJS Kesehatan |
POST /api/v1/merchant/ppob/bpjs/transaction | POST | Bayar tagihan BPJS Kesehatan |
Autentikasi
Semua endpoint PPOB menggunakan API Key via header X-API-Key dan opsional Signature Validation. Lihat Autentikasi.
Alur Transaksi
Produk Tanpa Inquiry (Pulsa, Paket Data)
Merchant Sistem
│ │
│ POST /ppob/phone-credit/ │
│ transaction │
│────────────────────────────────>│
│ │ proses ke biller
│ 200 OK { status, serial_no } │
│<────────────────────────────────│
Produk Dengan Inquiry (E-Wallet, PLN, BPJS)
Merchant Sistem
│ │
│ POST /ppob/ewallet/inquiry │
│────────────────────────────────>│
│ 200 OK { amount, unit_price } │
│<────────────────────────────────│
│ │
│ POST /ppob/ewallet/transaction │
│────────────────────────────────>│
│ │ potong saldo, kirim ke biller
│ 200 OK { status, serial_no } │
│<────────────────────────────────│
Format Request Umum
Semua endpoint transaksi PPOB menerima JSON dengan field berikut (field spesifik per endpoint dijelaskan di halaman masing-masing):
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
req_id | String | Ya (untuk payment) | ID unik merchant — idempotency key |
product_id | String | Ya | Kode produk dari Katalog Produk |
cust_id | String | Ya | ID pelanggan (nomor HP, ID meter PLN, nomor BPJS, dll) |
Format Response Umum
{
"success": true,
"message": "...",
"rc": "000",
"data": {
"req_id": "TXN-20240501-001",
"ref_id": "1777946295495371000",
"product_id": "XL5",
"cust_id": "08123456789",
"status": "SUCCESS",
"rc": "000",
"description": "Transaksi Sukses",
"message": "...",
"amount": "5000",
"unit_price": "5500",
"balance_used": "5500",
"balance": "494500",
"serial_no": "SN123456",
"data": {}
}
}
Poin Penting
- Strict JSON — field yang tidak dikenal dalam request body ditolak dengan
HTTP 422. - Minimal Amount — nominal minimum transaksi adalah Rp 1.000 (
"1000"). - Idempotency — gunakan
req_idyang sama untuk retry jika terjadi timeout; jangan kirimreq_idbaru untuk transaksi yang sama. - Produk dengan
status: MAINTENANCEataustatus: CLOSEDpada katalog tidak dapat diproses.
Cek Status Transaksi
Mengecek status terkini dari transaksi PPOB berdasarkan order_req_id.
URL: POST /api/v1/merchant/ppob/check
Kapan Menggunakan
- Setelah menerima
status: "PENDING"dari endpoint transaksi. - Untuk memverifikasi hasil transaksi yang gagal karena timeout jaringan.
- Jangan kirim ulang transaksi sebelum mengecek status terlebih dahulu.
Request
Headers
| Header | Wajib | Keterangan |
|---|---|---|
X-API-Key | Ya | API Key merchant |
Content-Type | Ya | application/json |
Query Parameter
| Parameter | Tipe | Keterangan |
|---|---|---|
direct | Boolean | Jika true, juga query live status dari biller (action status) |
Body
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
order_req_id | String | Ya | req_id dari transaksi yang ingin dicek |
Contoh Request
{
"order_req_id": "TXN-20240501-001"
}
curl -X POST "https://api-sandbox.alfakios.com/api/v1/merchant/ppob/check" \
-H "Content-Type: application/json" \
-H "X-API-Key: apk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-d '{"order_req_id": "TXN-20240501-001"}'
# Dengan live check ke biller
curl -X POST "https://api-sandbox.alfakios.com/api/v1/merchant/ppob/check?direct=true" \
-H "Content-Type: application/json" \
-H "X-API-Key: apk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-d '{"order_req_id": "TXN-20240501-001"}'
Response
Spesifikasi
| Field | Tipe | Keterangan |
|---|---|---|
req_id | String | order_req_id yang dikirim |
ref_id | String | ID referensi internal sistem |
product_id | String | Kode produk |
cust_id | String | ID customer / nomor tujuan |
status | String | SUCCESS, FAILED, atau PENDING |
rc | String | Kode respon |
description | String | Keterangan RC |
message | String | Pesan detail |
unit_price | String | Harga produk |
balance_used | String | Saldo yang terpotong |
balance | String | Saldo merchant setelah transaksi |
serial_no | String | Nomor seri / token dari biller |
data | Object | Data tambahan dari biller |
biller | Object | (opsional) Payload live biller jika direct=true |
Contoh Response — Transaksi Ditemukan
{
"success": true,
"message": "Transaction status checked successfully",
"rc": "000",
"data": {
"req_id": "TXN-20240501-001",
"ref_id": "1777946295495371000",
"product_id": "XL5",
"cust_id": "08123456789",
"status": "SUCCESS",
"rc": "000",
"description": "Transaksi Sukses",
"message": "PULSA XL 5000 KE 08123456789 SUKSES",
"unit_price": "5500",
"balance_used": "5500",
"balance": "494500",
"serial_no": "REF123456789",
"data": {}
}
}
Contoh Response — Transaksi Tidak Ditemukan
{
"success": false,
"message": "Transaction not found",
"rc": "002"
}
HTTP Status: 400 Bad Request
Catatan Penting
- Endpoint ini hanya bisa mengecek transaksi yang dibuat oleh merchant yang sama (API Key yang sama).
- Parameter
direct=truemenyebabkan query langsung ke biller — gunakan dengan hati-hati karena dapat memperlambat response. - Jika
order_req_idtidak ditemukan, pastikan ejaan sudah benar dan transaksi memang pernah dibuat dengan merchant ini.
Pulsa & Paket Data
Membeli pulsa atau paket data untuk nomor pelanggan.
URL: POST /api/v1/merchant/ppob/phone-credit/transaction
Request
Headers
| Header | Wajib | Keterangan |
|---|---|---|
X-API-Key | Ya | API Key merchant |
Content-Type | Ya | application/json |
Body
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
req_id | String | Ya | ID unik transaksi dari merchant (idempotency key) |
product_id | String | Ya | Kode produk pulsa/paket (dari Katalog Produk) |
cust_id | String | Ya | Nomor HP tujuan (format: 08xxxxxxxxxx atau 628xxxxxxxxxx) |
Contoh Request — Pulsa
{
"req_id": "TXN-20240501-001",
"product_id": "XL5",
"cust_id": "08123456789"
}
Contoh Request — Paket Data
{
"req_id": "TXN-20240501-002",
"product_id": "TSEL1GB7",
"cust_id": "08211223344"
}
curl -X POST "https://api-sandbox.alfakios.com/api/v1/merchant/ppob/phone-credit/transaction" \
-H "Content-Type: application/json" \
-H "X-API-Key: apk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-d '{
"req_id": "TXN-20240501-001",
"product_id": "XL5",
"cust_id": "08123456789"
}'
Response
Spesifikasi
| Field | Tipe | Keterangan |
|---|---|---|
req_id | String | req_id yang dikirim merchant |
ref_id | String | ID referensi internal sistem |
product_id | String | Kode produk |
cust_id | String | Nomor HP tujuan |
status | String | SUCCESS, FAILED, atau PENDING |
rc | String | Kode respon |
description | String | Keterangan RC |
message | String | Pesan detail dari biller |
amount | String | Nominal produk (nilai pulsa) |
unit_price | String | Harga jual produk (yang dipotong dari saldo) |
balance_used | String | Saldo yang benar-benar terpotong |
balance | String | Saldo merchant setelah transaksi |
serial_no | String | Nomor referensi dari biller |
data | Object | Data tambahan |
Contoh Response Berhasil
{
"success": true,
"message": "PULSA XL 5000 KE 08123456789 SUKSES",
"rc": "000",
"data": {
"req_id": "TXN-20240501-001",
"ref_id": "1777946295495371000",
"product_id": "XL5",
"cust_id": "08123456789",
"status": "SUCCESS",
"rc": "000",
"description": "Transaksi Sukses",
"message": "PULSA XL 5000 KE 08123456789 SUKSES",
"amount": "5000",
"unit_price": "5500",
"balance_used": "5500",
"balance": "494500",
"serial_no": "REF123456789",
"data": {}
}
}
Contoh Response Gagal — Nomor Tidak Valid
{
"success": true,
"message": "PULSA XL 5000 KE 08123456789 GAGAL",
"rc": "14",
"data": {
"req_id": "TXN-20240501-003",
"ref_id": "1777946295495372000",
"product_id": "XL5",
"cust_id": "0812345678",
"status": "FAILED",
"rc": "14",
"description": "Nomor tidak valid",
"message": "Nomor HP tidak valid untuk operator ini",
"balance": "494500",
"data": {}
}
}
Contoh Kode Produk
Gunakan endpoint Katalog Produk untuk mendapatkan daftar lengkap. Beberapa contoh:
product_id | Deskripsi | Nominal |
|---|---|---|
XL5 | Pulsa XL Rp 5.000 | 5.000 |
XL10 | Pulsa XL Rp 10.000 | 10.000 |
TSEL5 | Pulsa Telkomsel Rp 5.000 | 5.000 |
TSEL1GB7 | Paket Data Telkomsel 1GB / 7 hari | — |
ISAT10 | Pulsa Indosat Rp 10.000 | 10.000 |
AXIS5 | Pulsa Axis Rp 5.000 | 5.000 |
Catatan
- Transaksi pulsa umumnya bersifat instan (tidak ada alur inquiry).
- Jika
status: "PENDING", gunakan Cek Status untuk memantau hasilnya. req_idberfungsi sebagai idempotency key — retry aman tanpa risiko pengiriman ganda.
E-Wallet
Top-up saldo e-wallet pelanggan (GoPay, OVO, Dana, ShopeePay, dll) menggunakan alur dua langkah: inquiry → payment.
Endpoint
| Endpoint | Keterangan |
|---|---|
POST /api/v1/merchant/ppob/ewallet/inquiry | Validasi transaksi sebelum eksekusi |
POST /api/v1/merchant/ppob/ewallet/transaction | Eksekusi top-up e-wallet |
Alur Transaksi
1. Inquiry — validasi nomor e-wallet dan cek harga
2. Payment — eksekusi top-up (potong saldo merchant)
Inquiry E-Wallet
Memvalidasi nomor e-wallet dan mendapatkan informasi harga sebelum eksekusi. Tidak memotong saldo.
URL: POST /api/v1/merchant/ppob/ewallet/inquiry
Request
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
product_id | String | Ya | Kode produk e-wallet (dari katalog) |
cust_id | String | Ya | Nomor HP / ID akun e-wallet tujuan |
amount | String | Ya | Nominal top-up dalam IDR (digits only, min "1000") |
req_id | String | Tidak | ID request untuk tracing (opsional pada inquiry) |
Contoh Request
{
"product_id": "GOPAY",
"cust_id": "08123456789",
"amount": "50000"
}
curl -X POST "https://api-sandbox.alfakios.com/api/v1/merchant/ppob/ewallet/inquiry" \
-H "Content-Type: application/json" \
-H "X-API-Key: apk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-d '{
"product_id": "GOPAY",
"cust_id": "08123456789",
"amount": "50000"
}'
Response Inquiry Berhasil
{
"success": true,
"message": "E-wallet inquiry completed successfully",
"rc": "000",
"data": {
"req_id": "",
"ref_id": "1777946295495371000",
"product_id": "GOPAY",
"cust_id": "08123456789",
"status": "SUCCESS",
"rc": "000",
"description": "Transaksi Sukses",
"message": "INQUIRY GOPAY 50000 KE 08123456789 SUKSES",
"amount": "50000",
"unit_price": "51500",
"balance_used": "0",
"balance": "500000",
"serial_no": "",
"data": {}
}
}
Payment E-Wallet
Mengeksekusi top-up e-wallet. Saldo merchant akan dipotong.
URL: POST /api/v1/merchant/ppob/ewallet/transaction
Request
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
req_id | String | Ya | ID unik transaksi (idempotency key) |
product_id | String | Ya | Kode produk e-wallet (sama dengan inquiry) |
cust_id | String | Ya | Nomor HP / ID akun e-wallet (sama dengan inquiry) |
amount | String | Ya | Nominal top-up (sama dengan inquiry) |
Contoh Request
{
"req_id": "TXN-20240501-010",
"product_id": "GOPAY",
"cust_id": "08123456789",
"amount": "50000"
}
curl -X POST "https://api-sandbox.alfakios.com/api/v1/merchant/ppob/ewallet/transaction" \
-H "Content-Type: application/json" \
-H "X-API-Key: apk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-d '{
"req_id": "TXN-20240501-010",
"product_id": "GOPAY",
"cust_id": "08123456789",
"amount": "50000"
}'
Response Payment Berhasil
{
"success": true,
"message": "E-wallet payment created successfully",
"rc": "000",
"data": {
"req_id": "TXN-20240501-010",
"ref_id": "1777946295495372000",
"product_id": "GOPAY",
"cust_id": "08123456789",
"status": "SUCCESS",
"rc": "000",
"description": "Transaksi Sukses",
"message": "TOPUP GOPAY 50000 KE 08123456789 SUKSES",
"amount": "50000",
"unit_price": "51500",
"balance_used": "51500",
"balance": "448500",
"serial_no": "GW123456789",
"data": {}
}
}
Response Saldo Tidak Cukup
{
"success": true,
"message": "Transaction failed",
"rc": "008",
"data": {
"req_id": "TXN-20240501-011",
"status": "FAILED",
"rc": "008",
"description": "Insufficient Balance",
"message": "Saldo deposit tidak mencukupi",
"balance": "10000",
"data": {}
}
}
Contoh Kode Produk E-Wallet
product_id | Operator | Keterangan |
|---|---|---|
GOPAY | GoPay | Top-up GoPay via nomor HP |
OVO | OVO | Top-up OVO via nomor HP |
DANA | DANA | Top-up DANA via nomor HP |
SHOPEEPAY | ShopeePay | Top-up ShopeePay |
LINKAJA | LinkAja | Top-up LinkAja |
Gunakan endpoint Katalog Produk untuk daftar lengkap yang tersedia di akun merchant Anda.
Catatan
- Inquiry tidak wajib dilakukan sebelum payment — Anda bisa langsung ke payment jika sudah mengetahui harganya dari katalog.
- Gunakan
req_idyang sama untuk retry jika terjadi timeout.
PLN Prabayar (Token Listrik)
Beli token listrik PLN prabayar untuk nomor meter pelanggan. Menggunakan alur dua langkah: inquiry → transaksi.
Endpoint
| Endpoint | Keterangan |
|---|---|
POST /api/v1/merchant/ppob/pln/prepaid/inquiry | Inquiry nomor meter, cek nama pelanggan & tarif |
POST /api/v1/merchant/ppob/pln/prepaid/transaction | Beli token listrik |
Inquiry PLN Prabayar
Memvalidasi nomor meter dan mendapatkan informasi pelanggan sebelum pembelian. Tidak memotong saldo.
URL: POST /api/v1/merchant/ppob/pln/prepaid/inquiry
Request
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
product_id | String | Ya | Kode produk PLN prabayar (dari katalog) |
cust_id | String | Ya | Nomor meter listrik atau ID pelanggan PLN |
Contoh Request
{
"product_id": "PLNPREP",
"cust_id": "12345678901"
}
curl -X POST "https://api-sandbox.alfakios.com/api/v1/merchant/ppob/pln/prepaid/inquiry" \
-H "Content-Type: application/json" \
-H "X-API-Key: apk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-d '{"product_id": "PLNPREP", "cust_id": "12345678901"}'
Response Inquiry Berhasil
{
"success": true,
"message": "PLN prepaid inquiry completed successfully",
"rc": "000",
"data": {
"req_id": "",
"ref_id": "1777946295495371000",
"product_id": "PLNPREP",
"cust_id": "12345678901",
"status": "SUCCESS",
"rc": "000",
"description": "Transaksi Sukses",
"message": "INQUIRY PLN PREPAID KE 12345678901 SUKSES",
"amount": "20000",
"unit_price": "21500",
"balance_used": "0",
"balance": "500000",
"serial_no": "",
"data": {
"nama_pelanggan": "BUDI SANTOSO",
"tarif": "R1/TR",
"daya": "1300 VA",
"nomor_meter": "12345678901"
}
}
}
Transaksi PLN Prabayar
Membeli token listrik. Saldo merchant akan dipotong.
URL: POST /api/v1/merchant/ppob/pln/prepaid/transaction
Request
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
req_id | String | Ya | ID unik transaksi (idempotency key) |
product_id | String | Ya | Kode produk PLN prabayar |
cust_id | String | Ya | Nomor meter (sama dengan inquiry) |
Contoh Request
{
"req_id": "TXN-20240501-020",
"product_id": "PLNPREP",
"cust_id": "12345678901"
}
curl -X POST "https://api-sandbox.alfakios.com/api/v1/merchant/ppob/pln/prepaid/transaction" \
-H "Content-Type: application/json" \
-H "X-API-Key: apk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-d '{
"req_id": "TXN-20240501-020",
"product_id": "PLNPREP",
"cust_id": "12345678901"
}'
Response Berhasil
{
"success": true,
"message": "PLN prepaid top-up created successfully",
"rc": "000",
"data": {
"req_id": "TXN-20240501-020",
"ref_id": "1777946295495372000",
"product_id": "PLNPREP",
"cust_id": "12345678901",
"status": "SUCCESS",
"rc": "000",
"description": "Transaksi Sukses",
"message": "TOKEN PLN 20000 KE 12345678901 SUKSES",
"amount": "20000",
"unit_price": "21500",
"balance_used": "21500",
"balance": "478500",
"serial_no": "0123-4567-8901-2345-6789",
"data": {
"token": "0123-4567-8901-2345-6789",
"kwh": "9.1",
"nama_pelanggan": "BUDI SANTOSO",
"tarif": "R1/TR"
}
}
}
Token Listrik tersedia di field
serial_nodandata.token. Tampilkan nilai ini kepada pelanggan untuk diinput ke meteran listrik.
Kode Produk PLN Prabayar
product_id | Denom | Keterangan |
|---|---|---|
PLNPREP | Dinamis | Token PLN Prabayar (harga sesuai nominal) |
PLN20 | 20.000 | Token PLN Rp 20.000 |
PLN50 | 50.000 | Token PLN Rp 50.000 |
PLN100 | 100.000 | Token PLN Rp 100.000 |
PLN200 | 200.000 | Token PLN Rp 200.000 |
PLN500 | 500.000 | Token PLN Rp 500.000 |
PLN1000 | 1.000.000 | Token PLN Rp 1.000.000 |
Gunakan endpoint Katalog Produk untuk daftar produk yang tersedia di akun Anda.
Catatan
- Token listrik tersedia di field
serial_nosetelah transaksi sukses. - Format token:
XXXX-XXXX-XXXX-XXXX-XXXX(20 digit). - Jika
status: "PENDING", gunakan Cek Status untuk polling.
PLN Pascabayar (Tagihan Listrik)
Bayar tagihan listrik PLN pascabayar. Menggunakan alur dua langkah: inquiry tagihan → pembayaran.
Endpoint
| Endpoint | Keterangan |
|---|---|
POST /api/v1/merchant/ppob/pln/postpaid/inquiry | Inquiry tagihan, cek jumlah yang harus dibayar |
POST /api/v1/merchant/ppob/pln/postpaid/transaction | Bayar tagihan listrik |
Inquiry PLN Pascabayar
Mengambil informasi tagihan listrik pelanggan. Tidak memotong saldo.
URL: POST /api/v1/merchant/ppob/pln/postpaid/inquiry
Request
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
product_id | String | Ya | Kode produk PLN pascabayar (dari katalog) |
cust_id | String | Ya | Nomor ID pelanggan PLN (bukan nomor meter) |
Contoh Request
{
"product_id": "PLNPOST",
"cust_id": "512345678901"
}
curl -X POST "https://api-sandbox.alfakios.com/api/v1/merchant/ppob/pln/postpaid/inquiry" \
-H "Content-Type: application/json" \
-H "X-API-Key: apk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-d '{"product_id": "PLNPOST", "cust_id": "512345678901"}'
Response Inquiry Berhasil
{
"success": true,
"message": "PLN prepaid inquiry completed successfully",
"rc": "000",
"data": {
"req_id": "",
"ref_id": "1777946295495371000",
"product_id": "PLNPOST",
"cust_id": "512345678901",
"status": "SUCCESS",
"rc": "000",
"description": "Transaksi Sukses",
"message": "INQUIRY PLN POSTPAID KE 512345678901 SUKSES",
"amount": "285000",
"unit_price": "291000",
"balance_used": "0",
"balance": "500000",
"serial_no": "",
"data": {
"nama_pelanggan": "SITI RAHAYU",
"tarif": "R2/TR",
"daya": "2200 VA",
"id_pelanggan": "512345678901",
"periode": "APR 2024",
"tagihan": "285000",
"admin": "6000"
}
}
}
Pembayaran PLN Pascabayar
Membayar tagihan listrik. Saldo merchant akan dipotong.
URL: POST /api/v1/merchant/ppob/pln/postpaid/transaction
Request
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
req_id | String | Ya | ID unik transaksi (idempotency key) |
product_id | String | Ya | Kode produk PLN pascabayar |
cust_id | String | Ya | ID pelanggan PLN (sama dengan inquiry) |
Contoh Request
{
"req_id": "TXN-20240501-030",
"product_id": "PLNPOST",
"cust_id": "512345678901"
}
curl -X POST "https://api-sandbox.alfakios.com/api/v1/merchant/ppob/pln/postpaid/transaction" \
-H "Content-Type: application/json" \
-H "X-API-Key: apk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-d '{
"req_id": "TXN-20240501-030",
"product_id": "PLNPOST",
"cust_id": "512345678901"
}'
Response Berhasil
{
"success": true,
"message": "PLN prepaid top-up created successfully",
"rc": "000",
"data": {
"req_id": "TXN-20240501-030",
"ref_id": "1777946295495372000",
"product_id": "PLNPOST",
"cust_id": "512345678901",
"status": "SUCCESS",
"rc": "000",
"description": "Transaksi Sukses",
"message": "BAYAR TAGIHAN PLN 512345678901 SUKSES",
"amount": "285000",
"unit_price": "291000",
"balance_used": "291000",
"balance": "209000",
"serial_no": "REF-PLN-20240501",
"data": {
"nama_pelanggan": "SITI RAHAYU",
"periode": "APR 2024",
"nomor_struk": "REF-PLN-20240501"
}
}
}
Perbedaan PLN Prabayar vs Pascabayar
| Aspek | Prabayar | Pascabayar |
|---|---|---|
| Jenis Produk | Beli token | Bayar tagihan |
cust_id | Nomor meter | ID pelanggan PLN |
| Output | Token 20 digit | Nomor struk |
unit_price | Harga beli + admin | Tagihan + biaya admin |
Catatan
- Satu ID pelanggan PLN pascabayar bisa memiliki tagihan untuk beberapa bulan sekaligus. Konfirmasi dengan pelanggan sebelum melakukan pembayaran.
- Nomor struk pembayaran tersedia di
serial_nosetelah transaksi sukses.
BPJS Kesehatan
Bayar iuran BPJS Kesehatan untuk nomor kartu/peserta BPJS. Menggunakan alur dua langkah: inquiry → pembayaran.
Endpoint
| Endpoint | Keterangan |
|---|---|
POST /api/v1/merchant/ppob/bpjs/inquiry | Inquiry tagihan BPJS, cek nama & jumlah |
POST /api/v1/merchant/ppob/bpjs/transaction | Bayar iuran BPJS |
Inquiry BPJS
Mengambil informasi tagihan BPJS Kesehatan. Tidak memotong saldo.
URL: POST /api/v1/merchant/ppob/bpjs/inquiry
Request
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
product_id | String | Ya | Kode produk BPJS (dari katalog) |
cust_id | String | Ya | Nomor kartu / peserta BPJS Kesehatan |
period | String | Ya | Jumlah bulan yang dibayar (2 digit, contoh: "01" = 1 bulan) |
mobile_no | String | Tidak | Nomor HP peserta (untuk notifikasi) |
Catatan
period: Nilai harus berupa 2 digit numerik, misalnya"01"untuk 1 bulan,"03"untuk 3 bulan. Maksimum 12 bulan.
Contoh Request
{
"product_id": "BPJSKS",
"cust_id": "0001234567890",
"period": "01",
"mobile_no": "08123456789"
}
curl -X POST "https://api-sandbox.alfakios.com/api/v1/merchant/ppob/bpjs/inquiry" \
-H "Content-Type: application/json" \
-H "X-API-Key: apk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-d '{
"product_id": "BPJSKS",
"cust_id": "0001234567890",
"period": "01",
"mobile_no": "08123456789"
}'
Response Inquiry Berhasil
{
"success": true,
"message": "BPJS inquiry completed successfully",
"rc": "000",
"data": {
"req_id": "",
"ref_id": "1777946295495371000",
"product_id": "BPJSKS",
"cust_id": "0001234567890",
"status": "SUCCESS",
"rc": "000",
"description": "Transaksi Sukses",
"message": "INQUIRY BPJSKS KE 0001234567890 SUKSES",
"amount": "42000",
"unit_price": "42500",
"balance_used": "0",
"balance": "500000",
"serial_no": "",
"data": {
"nama_peserta": "AHMAD FAUZAN",
"jumlah_peserta": "1",
"periode": "01",
"tagihan": "42000",
"admin": "500",
"total": "42500"
}
}
}
Pembayaran BPJS
Membayar iuran BPJS Kesehatan. Saldo merchant akan dipotong.
URL: POST /api/v1/merchant/ppob/bpjs/transaction
Request
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
req_id | String | Ya | ID unik transaksi (idempotency key) |
product_id | String | Ya | Kode produk BPJS |
cust_id | String | Ya | Nomor BPJS (sama dengan inquiry) |
period | String | Ya | Periode bulan (sama dengan inquiry, format 2 digit) |
inquiry_req_id | String | Ya | req_id dari step inquiry — digunakan oleh biller sebagai referensi |
mobile_no | String | Tidak | Nomor HP peserta |
email | String | Tidak | Email peserta (untuk notifikasi) |
Penting:
inquiry_req_idharus diisi dengan nilaireq_idyang dikembalikan dari response inquiry. Jika inquiry dilakukan tanpareq_id, gunakanref_iddari response inquiry.
Contoh Request
{
"req_id": "TXN-20240501-040",
"product_id": "BPJSKS",
"cust_id": "0001234567890",
"period": "01",
"inquiry_req_id": "INQ-20240501-040",
"mobile_no": "08123456789",
"email": "ahmad@email.com"
}
curl -X POST "https://api-sandbox.alfakios.com/api/v1/merchant/ppob/bpjs/transaction" \
-H "Content-Type: application/json" \
-H "X-API-Key: apk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-d '{
"req_id": "TXN-20240501-040",
"product_id": "BPJSKS",
"cust_id": "0001234567890",
"period": "01",
"inquiry_req_id": "INQ-20240501-040",
"mobile_no": "08123456789"
}'
Response Berhasil
{
"success": true,
"message": "BPJS payment completed successfully",
"rc": "000",
"data": {
"req_id": "TXN-20240501-040",
"ref_id": "1777946295495372000",
"product_id": "BPJSKS",
"cust_id": "0001234567890",
"status": "SUCCESS",
"rc": "000",
"description": "Transaksi Sukses",
"message": "BAYAR BPJSKS 0001234567890 SUKSES",
"amount": "42000",
"unit_price": "42500",
"balance_used": "42500",
"balance": "457500",
"serial_no": "BPJS-REF-2024050112345",
"data": {
"nama_peserta": "AHMAD FAUZAN",
"periode": "01",
"nomor_struk": "BPJS-REF-2024050112345"
}
}
}
Kode Produk BPJS
product_id | Keterangan |
|---|---|
BPJSKS | BPJS Kesehatan |
Gunakan endpoint Katalog Produk untuk daftar produk terbaru.
Catatan
- Field
periodwajib dan harus berupa string 2 digit ("01"s/d"12"). - Field
inquiry_req_idpada payment harus berisireq_idyang digunakan saat inquiry — ini adalah referensi transaksi yang dibutuhkan biller untuk melanjutkan proses. - Nomor struk pembayaran tersedia di
serial_nosetelah transaksi sukses.
Gambaran Umum Disbursement
Disbursement API memungkinkan merchant untuk melakukan transfer dana ke rekening bank tujuan secara terprogram. Menggunakan mekanisme dua langkah (inquiry → payment) untuk memastikan validitas rekening sebelum dana dikirim.
Endpoint
| Endpoint | Metode | Keterangan |
|---|---|---|
POST /api/v1/merchant/disbursement/inquiry | POST | Validasi rekening tujuan (tidak memotong saldo) |
POST /api/v1/merchant/disbursement/payment | POST | Eksekusi transfer dana |
POST /api/v1/merchant/disbursement/status | POST | Cek status transaksi disbursement |
Karakteristik
- Protokol: HTTP POST
- Format Data: JSON /
Content-Type: application/json - Autentikasi: API Key via header
X-API-Key - Keamanan Tambahan: Signature Validation (opsional)
- Timeout Request: 8 detik
Alur Transaksi
Merchant Sistem
│ │
│ POST /disbursement/inquiry │
│─────────────────────────────────────>│
│ │ validasi rekening ke biller
│ 200 OK { inquiry_reff, │
│ account_name, fee } │
│<─────────────────────────────────────│
│ │
│ POST /disbursement/payment │
│─────────────────────────────────────>│
│ │ potong saldo, kirim ke bank tujuan
│ 200 OK { status, ref_id } │
│<─────────────────────────────────────│
│ │
│ (opsional) POST /disbursement/status│
│─────────────────────────────────────>│
│ 200 OK { status final } │
│<─────────────────────────────────────│
Poin Penting
- Inquiry tidak memotong saldo — hanya memvalidasi rekening dan mendapatkan informasi fee.
- Payment memotong saldo — jika
rc: "000"ataurc: "00", saldo langsung berkurang. - Status PENDING — terjadi jika biller belum konfirmasi final. Gunakan
/statusuntuk polling. - Jangan kirim payment ulang sebelum cek status — risiko double transfer.
- Idempotency via
req_id— retry aman denganreq_idyang sama jika terjadi timeout.
Validasi Request
- Nominal (
amount) harus berupa string digit (contoh:"100000"), tidak boleh negatif, desimal, atau scientific notation. - Minimal transfer: Rp 10.000 (
"10000"). - Field yang tidak dikenal dalam JSON body akan ditolak dengan
HTTP 422.
Kode Bank Umum
| Kode | Nama Bank |
|---|---|
002 | Bank Rakyat Indonesia (BRI) |
008 | Mandiri |
009 | Bank Negara Indonesia (BNI) |
014 | Bank Central Asia (BCA) |
022 | CIMB Niaga |
028 | Wulandari Kencana (OCBC NISP) |
032 | Bank Tabungan Pensiun Nasional (BTPN) |
036 | Bank Tabungan Negara (BTN) |
046 | DKI Jakarta |
200 | Danamon |
213 | BTPN Syariah |
426 | Mega |
451 | Syariah Indonesia (BSI) |
484 | Sahabat Sampoerna |
553 | BRI Syariah / BSI |
898 | Nobu (National Nobu) |
Gunakan endpoint Katalog Produk untuk mendapatkan daftar produk transfer yang tersedia (kode bank dapat juga diambil dari sana).
Inquiry Rekening
Memvalidasi rekening bank tujuan sebelum transfer. Tidak memotong saldo deposit.
URL: POST /api/v1/merchant/disbursement/inquiry
Request
Headers
| Header | Wajib | Keterangan |
|---|---|---|
X-API-Key | Ya | API Key merchant |
Content-Type | Ya | application/json |
X-Signature | Kondisional | Jika Signature Validation aktif |
X-Timestamp | Kondisional | Unix timestamp (jika Signature Validation aktif) |
Body
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
product_id | String | Ya | Kode produk transfer (contoh: "DSTF") |
account_number | String | Ya | Nomor rekening tujuan |
amount | String | Ya | Nominal transfer dalam IDR (digits only, min "10000") |
bank_code | String | Tidak | Kode bank tujuan — disarankan untuk akurasi routing |
Contoh Request
{
"product_id": "DSTF",
"account_number": "1380610457",
"amount": "100000",
"bank_code": "014"
}
curl --location 'https://api-sandbox.alfakios.com/api/v1/merchant/disbursement/inquiry' \
--header 'Content-Type: application/json' \
--header 'X-API-Key: apk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
--data '{
"product_id": "DSTF",
"account_number": "1380610457",
"amount": "100000",
"bank_code": "014"
}'
Response
Spesifikasi
| Field | Tipe | Keterangan |
|---|---|---|
trx_id | String | ID transaksi internal sistem |
req_id | String | req_id yang dikirim merchant |
ref_id | String | ID referensi transaksi (sama dengan trx_id) |
inquiry_reff | String | Referensi inquiry dari biller — digunakan internal pada step payment |
account_name | String | Nama pemilik rekening tujuan |
account_number | String | Nomor rekening tujuan |
bank_code | String | Kode bank tujuan |
bank_name | String | Nama bank tujuan |
amount | String | Nominal transfer |
fee | String | Biaya admin transfer |
total_cost | String | Total biaya (amount + fee) |
balance | String | Saldo deposit merchant saat ini |
status | String | Status inquiry: SUCCESS atau FAILED |
rc | String | Kode respon dari biller |
description | String | Keterangan RC |
message | String | Keterangan detail |
data | Object | Informasi tambahan dari biller |
details | String | String OtomaX-style — lihat Integrasi OtomaX |
Contoh Response Berhasil
{
"success": true,
"message": "Disbursement inquiry completed",
"rc": "000",
"data": {
"trx_id": "1777946295495371000",
"req_id": "PAY-20240430-001",
"ref_id": "1777946295495371000",
"inquiry_reff": "1017797",
"account_name": "DUMMY NAME",
"account_number": "1380610457",
"bank_code": "014",
"bank_name": "Bank Central Asia",
"amount": "100000",
"fee": "3000",
"total_cost": "103000",
"balance": "281994",
"status": "SUCCESS",
"rc": "00",
"description": "Transaksi Sukses",
"message": "INQUIRY DISBURSEMENT DSTF KE 1380610457 SUKSES",
"data": {},
"details": "REQID:PAY-20240430-001.REFID:1777946295495371000.INQREF:1017797.STATUS:SUCCESS.RC:00.NAMA:DUMMY NAME.REK:1380610457.KODEBANK:014.NOMINAL:100000.FEE:3000.TOTAL:103000.SALDO:281994.KET:Transaksi Sukses"
}
}
Contoh Response Rekening Tidak Ditemukan
{
"success": true,
"message": "Disbursement inquiry completed",
"rc": "051",
"data": {
"req_id": "",
"ref_id": "REF-1714435200200002",
"inquiry_reff": "",
"account_name": "",
"account_number": "9999999999",
"bank_code": "014",
"bank_name": "Bank Central Asia",
"amount": "500000",
"fee": "0",
"total_cost": "0",
"balance": "5000000",
"status": "FAILED",
"rc": "051",
"description": "Account Not Found",
"message": "Rekening tidak ditemukan atau tidak aktif",
"data": {}
}
}
Contoh Response Error Validasi (422)
{
"success": false,
"message": "Validation failed",
"errors": [
{
"field": "amount",
"message": "amount must be a positive integer (digits only)"
}
]
}
Catatan
inquiry_reffdigunakan secara internal oleh sistem — Anda tidak perlu meneruskan nilai ini ke endpoint payment.- Catat
feedantotal_costdari response inquiry untuk ditampilkan kepada pengguna sebelum konfirmasi transfer. - Rekening yang tidak ditemukan (
rc: "051") tidak memotong saldo; aman untuk dicoba ulang dengan nomor yang berbeda.
Eksekusi Transfer Dana
Mengeksekusi transfer dana ke rekening bank tujuan. Saldo deposit merchant akan dipotong.
URL: POST /api/v1/merchant/disbursement/payment
Lakukan Inquiry Rekening terlebih dahulu untuk memvalidasi rekening dan mendapatkan informasi fee sebelum menjalankan payment.
Request
Headers
| Header | Wajib | Keterangan |
|---|---|---|
X-API-Key | Ya | API Key merchant |
Content-Type | Ya | application/json |
X-Signature | Kondisional | Jika Signature Validation aktif |
X-Timestamp | Kondisional | Unix timestamp (jika Signature Validation aktif) |
Body
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
req_id | String | Ya | ID unik transaksi dari merchant — idempotency key |
product_id | String | Ya | Kode produk transfer (contoh: "DSTF") |
account_number | String | Ya | Nomor rekening tujuan (sama dengan inquiry) |
amount | String | Ya | Nominal transfer dalam IDR (sama dengan inquiry) |
bank_code | String | Tidak | Kode bank tujuan (opsional) |
Idempotency via req_id
req_id berfungsi sebagai idempotency key:
- Retry dengan
req_idyang sama → sistem mengembalikan hasil transaksi pertama, tanpa debit ganda. - Gunakan
req_idyang berbeda hanya untuk transaksi yang memang baru.
Contoh Request
{
"req_id": "PAY-20240430-001",
"product_id": "DSTF",
"account_number": "1380610457",
"amount": "10000",
"bank_code": "014"
}
curl --location 'https://api-sandbox.alfakios.com/api/v1/merchant/disbursement/payment' \
--header 'Content-Type: application/json' \
--header 'X-API-Key: apk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
--data '{
"req_id": "PAY-20240430-001",
"product_id": "DSTF",
"account_number": "1380610457",
"amount": "10000",
"bank_code": "014"
}'
Response
Spesifikasi
| Field | Tipe | Keterangan |
|---|---|---|
trx_id | String | ID transaksi internal sistem |
req_id | String | req_id yang dikirim merchant |
ref_id | String | ID referensi dari biller |
account_number | String | Nomor rekening tujuan |
account_name | String | Nama pemilik rekening |
bank_code | String | Kode bank tujuan |
bank_name | String | Nama bank tujuan |
status | String | SUCCESS, FAILED, atau PENDING |
rc | String | Kode respon dari biller atau sistem |
description | String | Keterangan RC |
message | String | Keterangan detail |
amount | String | Nominal transfer |
fee | String | Biaya admin yang dipotong |
total_cost | String | Total yang dipotong (amount + fee) |
balance_used | String | Saldo yang benar-benar terpotong |
balance | String | Saldo deposit setelah transaksi |
serial_no | String | Nomor referensi transfer dari biller |
data | Object | Informasi tambahan |
details | String | String OtomaX-style — lihat Integrasi OtomaX |
Contoh Response Berhasil
{
"success": true,
"message": "Disbursement payment completed",
"rc": "000",
"data": {
"trx_id": "177794638960894000",
"req_id": "PAY-20240430-001",
"ref_id": "980173",
"account_number": "1380610457",
"account_name": "DUMMY NAME",
"bank_code": "014",
"bank_name": "",
"status": "SUCCESS",
"rc": "00",
"description": "Transaksi Sukses",
"message": "DISBURSEMENT DSTF KE 1380610457 SUKSES. SAL=268994,ID=177794638960894000",
"amount": "10000",
"fee": "3000",
"total_cost": "13000",
"balance_used": "13000",
"balance": "268994",
"serial_no": "980173",
"data": {},
"details": "REQID:PAY-20240430-001.REFID:980173.STATUS:SUCCESS.RC:00.NAMA:DUMMY NAME.REK:1380610457.KODEBANK:014.NOMINAL:10000.FEE:3000.TOTAL:13000.SALDO:268994.TERPAKAI:13000.SN:980173.KET:Transaksi Sukses"
}
}
Contoh Response Saldo Tidak Cukup
{
"success": true,
"message": "Disbursement payment completed",
"rc": "008",
"data": {
"req_id": "PAY-20240430-002",
"ref_id": "",
"account_number": "1380610457",
"account_name": "",
"status": "FAILED",
"rc": "008",
"description": "Insufficient Balance",
"message": "Saldo deposit tidak mencukupi",
"amount": "500000",
"fee": "6500",
"total_cost": "506500",
"balance_used": "0",
"balance": "100000",
"serial_no": "",
"data": {}
}
}
Contoh Response PENDING
{
"success": true,
"message": "Disbursement payment completed",
"rc": "021",
"data": {
"req_id": "PAY-20240430-003",
"ref_id": "980174",
"account_number": "1380610457",
"account_name": "BUDI SANTOSO",
"status": "PENDING",
"rc": "021",
"description": "Transaction Pending",
"message": "Transfer sedang diproses oleh bank tujuan",
"amount": "500000",
"fee": "6500",
"total_cost": "506500",
"balance_used": "506500",
"balance": "4493500",
"serial_no": "",
"data": {}
}
}
Jika status: "PENDING", gunakan endpoint Cek Status untuk polling hasil akhir.
Rekomendasi Retry Policy (PENDING)
Attempt 1 : tunggu 30 detik
Attempt 2 : tunggu 60 detik
Attempt 3 : tunggu 120 detik
Attempt 4 : tunggu 300 detik
Attempt 5+: eskalasi ke tim support dengan menyertakan req_id
JANGAN kirim payment baru sebelum mendapatkan status final. Transfer ganda dapat terjadi jika payment dikirim lebih dari sekali untuk transaksi yang sama.
Cek Status Disbursement
Mengecek status terbaru dari transaksi disbursement yang sebelumnya dikirim. Gunakan endpoint ini ketika transaksi mengembalikan status: "PENDING".
URL: POST /api/v1/merchant/disbursement/status
Request
Headers
| Header | Wajib | Keterangan |
|---|---|---|
X-API-Key | Ya | API Key merchant |
Content-Type | Ya | application/json |
X-Signature | Kondisional | Jika Signature Validation aktif |
X-Timestamp | Kondisional | Unix timestamp (jika Signature Validation aktif) |
Body
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
product_id | String | Ya | Kode produk yang digunakan saat transaksi |
account_number | String | Ya | Nomor rekening tujuan |
amount | String | Ya | Nominal yang ditransfer |
req_id | String | Ya | req_id dari response payment yang ingin dicek |
bank_code | String | Tidak | Kode bank tujuan (opsional) |
Contoh Request
{
"product_id": "DSTF",
"account_number": "1380610457",
"amount": "100000",
"bank_code": "014",
"req_id": "PAY-20240430-001"
}
curl --location 'https://api-sandbox.alfakios.com/api/v1/merchant/disbursement/status' \
--header 'Content-Type: application/json' \
--header 'X-API-Key: apk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
--data '{
"product_id": "DSTF",
"account_number": "1380610457",
"amount": "100000",
"bank_code": "014",
"req_id": "PAY-20240430-001"
}'
Response
Response menggunakan shape yang identik dengan response Inquiry Rekening, termasuk field details berformat OtomaX.
Spesifikasi
| Field | Tipe | Keterangan |
|---|---|---|
trx_id | String | ID transaksi internal sistem |
req_id | String | req_id yang dicek |
ref_id | String | ID referensi dari biller |
inquiry_reff | String | Referensi inquiry dari biller |
account_name | String | Nama pemilik rekening |
account_number | String | Nomor rekening tujuan |
bank_code | String | Kode bank |
bank_name | String | Nama bank |
amount | String | Nominal transfer |
fee | String | Biaya admin |
total_cost | String | Total biaya |
balance | String | Saldo merchant (bisa kosong — gunakan /balance/merchant untuk saldo terbaru) |
status | String | Status final: SUCCESS, FAILED, atau PENDING |
rc | String | Kode respon |
description | String | Keterangan RC |
message | String | Keterangan detail |
data | Object | Informasi tambahan |
details | String | String OtomaX-style |
Contoh Response — Konfirmasi Sukses
{
"success": true,
"message": "Disbursement direct transfer completed",
"rc": "000",
"data": {
"trx_id": "177794638960894000",
"req_id": "PAY-20240430-001",
"ref_id": "980173",
"inquiry_reff": "976373",
"account_name": "DUMMY NAME",
"account_number": "1380610457",
"bank_code": "014",
"bank_name": "",
"amount": "10000",
"fee": "3000",
"total_cost": "13000",
"balance": "",
"status": "SUCCESS",
"rc": "000",
"description": "Transaksi Sukses",
"message": "STATUS DISBURSEMENT DSTF KE 1380610457: SUCCESS",
"data": {},
"details": "REQID:PAY-20240430-001.REFID:980173.INQREF:976373.STATUS:SUCCESS.RC:000.NAMA:DUMMY NAME.REK:1380610457.KODEBANK:014.NOMINAL:10000.FEE:3000.TOTAL:13000.KET:Transaksi Sukses"
}
}
Contoh Response — Masih PENDING
{
"success": true,
"message": "Disbursement direct transfer completed",
"rc": "021",
"data": {
"req_id": "PAY-20240430-003",
"ref_id": "980174",
"account_number": "1380610457",
"account_name": "BUDI SANTOSO",
"status": "PENDING",
"rc": "021",
"description": "Transaction Pending",
"message": "STATUS DISBURSEMENT DSTF KE 1380610457: PENDING",
"data": {}
}
}
Catatan
- Field
balancepada response/statusbisa kosong. Gunakan endpoint Cek Saldo untuk mendapatkan saldo merchant terbaru. - Jika setelah 5 kali polling status masih
PENDING, eskalasi ke tim support dengan menyertakanreq_id.
Kode Respon Disbursement
Tabel Kode Respon
| RC | Keterangan | Status | Saldo Terpotong |
|---|---|---|---|
| 000 | Transfer sukses (kode sistem) | SUCCESS | Ya |
| 00 | Transfer sukses (kode biller) | SUCCESS | Ya |
| 002 | Transaksi tidak ditemukan | FAILED | Tidak |
| 005 | Kode produk tidak dikenal / pricing tidak tersedia | FAILED | Tidak |
| 006 | Produk tidak aktif | FAILED | Tidak |
| 007 | Produk dalam maintenance | FAILED | Tidak |
| 008 | Saldo deposit tidak cukup | FAILED | Tidak |
| 009 | Error pada biller saat inquiry | FAILED | Tidak |
| 021 | Transaksi pending (diproses bank tujuan) | PENDING | Ya (menunggu final) |
| 022 | Koneksi ke biller gagal (auto-refund) | FAILED | Auto-refunded |
| 023 | Response biller kosong (auto-refund) | FAILED | Auto-refunded |
| 051 | Rekening tujuan tidak ditemukan / tidak aktif | FAILED | Tidak |
Detail Kode Respon
RC: 000 / 00 — Transfer Sukses
Transfer berhasil. Saldo sudah terpotong dan dana telah dikirim ke rekening tujuan. serial_no berisi nomor referensi transfer dari bank.
RC: 021 — Transaksi Pending
Transfer sedang dalam proses di bank tujuan. Saldo sudah terpotong. Merchant harus mengecek status secara berkala menggunakan endpoint /status hingga mendapat status final.
RC: 022 — Biller Call Failed
Koneksi ke biller gagal (timeout atau error jaringan). Saldo yang terpotong akan otomatis di-refund oleh sistem dalam waktu singkat. Merchant dapat mengirim ulang request dengan req_id yang berbeda.
RC: 023 — Empty Biller Response
Biller mengembalikan response kosong atau tidak valid. Saldo yang terpotong akan otomatis di-refund oleh sistem.
RC: 051 — Rekening Tidak Ditemukan
Rekening tujuan tidak ditemukan, tidak aktif, atau tidak sesuai dengan bank yang dipilih. Tidak ada saldo yang terpotong. Verifikasi kembali nomor rekening dan kode bank.
RC: 008 — Saldo Tidak Cukup
Saldo deposit merchant tidak mencukupi untuk menutup amount + fee. Tidak ada saldo yang terpotong. Deposit saldo terlebih dahulu melalui CMS.
Policy Refund Otomatis
| Kondisi | Saldo | Policy |
|---|---|---|
| RC 005, 006, 007, 008, 009, 051 | Tidak pernah terpotong | Tidak ada refund |
| RC 021 → konfirmasi SUCCESS | Terpotong, final sukses | Tidak ada refund |
| RC 021 → konfirmasi FAILED | Terpotong | Sistem otomatis refund |
| RC 022, 023 | Terpotong | Sistem otomatis refund |
Alur Keputusan
Response Payment
│
├── rc = "000" / "00" → ✅ Transfer sukses — catat serial_no
│
├── rc = "021" → ⏳ Pending — polling via /status
│ │
│ ├── status = SUCCESS → ✅ Transfer sukses
│ └── status = FAILED → ❌ Gagal, saldo di-refund
│
├── rc = "022" / "023" → ❌ Gagal, saldo di-refund otomatis
│ → Boleh retry dengan req_id berbeda
│
├── rc = "008" → ❌ Saldo tidak cukup — isi deposit
│
└── rc = "051" → ❌ Rekening tidak valid — cek ulang nomor
Integrasi OtomaX Modul IP
Seluruh response endpoint disbursement menyertakan field details berformat flat string yang dirancang untuk dikonsumsi langsung oleh OtomaX Modul IP regex parser tanpa mem-parse JSON.
Format
Key dan value dipisahkan oleh titik dua (:), setiap pasangan key-value dipisahkan oleh titik (.). Field yang kosong dihilangkan otomatis.
KEY1:VALUE1.KEY2:VALUE2.KEY3:VALUE3
Daftar Key
| Key | Keterangan | Tersedia di |
|---|---|---|
REQID | ID transaksi dari merchant (req_id) | Inquiry, Payment, Status |
REFID | ID referensi server (ref_id) | Inquiry, Payment, Status |
INQREF | Referensi inquiry dari biller (inquiry_reff) | Inquiry, Status |
STATUS | Status: SUCCESS, FAILED, PENDING | Inquiry, Payment, Status |
RC | Kode respon | Inquiry, Payment, Status |
NAMA | Nama pemilik rekening tujuan | Inquiry, Payment, Status |
REK | Nomor rekening tujuan | Inquiry, Payment, Status |
BANK | Nama bank tujuan (hanya jika tidak kosong) | Inquiry, Payment, Status |
KODEBANK | Kode bank tujuan | Inquiry, Payment, Status |
NOMINAL | Nominal transfer | Inquiry, Payment, Status |
FEE | Biaya admin | Inquiry, Payment, Status |
TOTAL | Total biaya (nominal + fee) | Inquiry, Payment, Status |
SALDO | Saldo merchant setelah transaksi | Inquiry, Payment |
TERPAKAI | Saldo yang benar-benar terpotong (balance_used) | Payment |
SN | Serial number / referensi transfer dari bank | Payment |
KET | Keterangan (description atau message) | Inquiry, Payment, Status |
Contoh String details
Inquiry berhasil
REQID:PAY-20240430-001.REFID:1777946295495371000.INQREF:1017797.STATUS:SUCCESS.RC:00.NAMA:DUMMY NAME.REK:1380610457.KODEBANK:014.NOMINAL:100000.FEE:3000.TOTAL:103000.SALDO:281994.KET:Transaksi Sukses
Payment berhasil
REQID:PAY-20240430-001.REFID:980173.STATUS:SUCCESS.RC:00.NAMA:DUMMY NAME.REK:1380610457.KODEBANK:014.NOMINAL:10000.FEE:3000.TOTAL:13000.SALDO:268994.TERPAKAI:13000.SN:980173.KET:Transaksi Sukses
Status check berhasil
REQID:PAY-20240430-001.REFID:980173.INQREF:976373.STATUS:SUCCESS.RC:000.NAMA:DUMMY NAME.REK:1380610457.KODEBANK:014.NOMINAL:10000.FEE:3000.TOTAL:13000.KET:Transaksi Sukses
Payment pending
REQID:PAY-20240430-002.REFID:980174.STATUS:PENDING.RC:021.NAMA:DUMMY NAME.REK:1380610457.KODEBANK:014.NOMINAL:100000.FEE:3000.TOTAL:103000.SALDO:168994.TERPAKAI:103000.KET:Transaction Pending
Payment gagal (saldo tidak cukup)
REQID:PAY-20240430-003.REFID:980175.STATUS:FAILED.RC:008.REK:1380610457.KODEBANK:014.NOMINAL:100000.FEE:3000.TOTAL:103000.SALDO:50000.KET:Insufficient Balance
Regex Parser untuk OtomaX Modul IP
Cek sukses dengan SN
STATUS:SUCCESS.*SN:(?P<sn>[^.]+).*SALDO:(?P<saldo>[0-9]+)
Cek sukses atau pending (tanpa SN)
STATUS:(?P<status>SUCCESS|PENDING).*RC:(?P<rc>[0-9]+).*SALDO:(?P<saldo>[0-9]+)
Ekstrak semua field utama
REQID:(?P<reqid>[^.]+).*REFID:(?P<refid>[^.]+).*STATUS:(?P<status>[^.]+).*RC:(?P<rc>[^.]+).*SALDO:(?P<saldo>[0-9]+)
Konfigurasi OtomaX Modul IP
Konfigurasi parsing untuk payment sukses di OtomaX:
Regex SN : SN:(?P<sn>[^.]+)
Regex Saldo : SALDO:(?P<saldo>[0-9]+)
Regex Status : STATUS:(?P<status>SUCCESS|PENDING|FAILED)
Regex RC : RC:(?P<rc>[0-9]+)
Catatan: Nilai
STATUSdalam fielddetailsmenggunakan bahasa Inggris (SUCCESS,FAILED,PENDING). Sesuaikan regex Modul IP Anda jika sebelumnya menggunakan token berbeda sepertiSUKSESatauGAGAL.
Gambaran Umum PayIn
PayIn API memungkinkan merchant untuk menerima pembayaran dari pelanggan melalui QRIS (QR Code Indonesian Standard). Pelanggan membayar menggunakan aplikasi dompet digital atau m-banking yang mendukung QRIS.
Endpoint
| Endpoint | Metode | Keterangan |
|---|---|---|
POST /api/v1/merchant/payin/qris/create | POST | Buat QRIS untuk satu transaksi |
POST /api/v1/merchant/payin/qris/check | POST | Cek status pembayaran QRIS |
POST /api/v1/merchant/payin/qris/refund | POST | Refund pembayaran QRIS yang berhasil |
Biller
PayIn QRIS menggunakan biller GPay (GPAY) — payment gateway yang menyediakan QRIS merchant.
Alur Transaksi PayIn QRIS
Merchant Sistem Pelanggan
│ │ │
│ POST /payin/qris/create │ │
│────────────────────────────────>│ │
│ 200 OK { qr_code, trace_number}│ │
│<────────────────────────────────│ │
│ │ │
│ Tampilkan QR kepada pelanggan ─────────────────────────> │
│ │ Pelanggan scan & bayar │
│ │<─────────────────────────│
│ │ │
│ Webhook dari GPay (callback) │ │
│<────────────────────────────────│ │
│ │ │
│ ATAU polling /qris/check │ │
│────────────────────────────────>│ │
│ 200 OK { status } │ │
│<────────────────────────────────│ │
Konsep Penting
trace_number
Setiap QRIS yang dibuat memiliki trace_number unik yang diterbitkan oleh GPay. Gunakan nilai ini untuk:
- Cek status pembayaran via
/qris/check - Inisiasi refund via
/qris/refund
Webhook Callback
GPay mengirimkan notifikasi webhook ke sistem Relay ketika pembayaran QRIS dikonfirmasi. Sistem Relay kemudian memperbarui status transaksi secara otomatis. Anda dapat:
- Polling status via
/qris/check, atau - Menyediakan callback URL di konfigurasi merchant untuk menerima notifikasi push.
Status Transaksi
| Status | Keterangan |
|---|---|
SUCCESS | Pembayaran dikonfirmasi oleh bank/dompet pelanggan |
PENDING | Menunggu pembayaran dari pelanggan (QRIS belum dibayar) |
FAILED | QRIS kedaluwarsa atau pembayaran gagal |
Autentikasi
Semua endpoint PayIn menggunakan API Key via header X-API-Key dan opsional Signature Validation. Lihat Autentikasi.
QRIS — Buat Transaksi
Membuat QRIS pembayaran untuk satu transaksi. Pelanggan memindai QR code yang dihasilkan menggunakan aplikasi m-banking atau dompet digital.
URL: POST /api/v1/merchant/payin/qris/create
Request
Headers
| Header | Wajib | Keterangan |
|---|---|---|
X-API-Key | Ya | API Key merchant |
Content-Type | Ya | application/json |
X-Signature | Kondisional | Jika Signature Validation aktif |
X-Timestamp | Kondisional | Unix timestamp (jika Signature Validation aktif) |
Body
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
req_id | String | Ya | ID unik transaksi dari merchant (idempotency key) |
product_id | String | Ya | Kode produk QRIS (contoh: "GPAY") |
amount | String | Ya | Nominal pembayaran dalam IDR (digits only) |
Contoh Request
{
"req_id": "QRIS-20240501-001",
"product_id": "GPAY",
"amount": "150000"
}
curl -X POST "https://api-sandbox.alfakios.com/api/v1/merchant/payin/qris/create" \
-H "Content-Type: application/json" \
-H "X-API-Key: apk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-d '{
"req_id": "QRIS-20240501-001",
"product_id": "GPAY",
"amount": "150000"
}'
Response
Spesifikasi
| Field | Tipe | Keterangan |
|---|---|---|
req_id | String | req_id yang dikirim merchant |
ref_id | String | ID referensi internal sistem |
product_id | String | Kode produk QRIS |
trace_number | String | Nomor unik dari GPay — simpan untuk cek status dan refund |
status | String | SUCCESS (QRIS berhasil dibuat), PENDING, atau FAILED |
rc | String | Kode respon |
description | String | Keterangan RC |
message | String | Pesan detail |
amount | String | Nominal pembayaran |
data | Object | Data tambahan dari GPay, termasuk QR string/URL |
Contoh Response Berhasil
{
"success": true,
"message": "QRIS created successfully",
"rc": "000",
"data": {
"req_id": "QRIS-20240501-001",
"ref_id": "1777946295495371000",
"product_id": "GPAY",
"trace_number": "240501001234",
"status": "SUCCESS",
"rc": "000",
"description": "QRIS Created",
"message": "QRIS berhasil dibuat",
"amount": "150000",
"data": {
"qr_string": "00020101021226670016ID.CO.BCA.WWW01189360050300000068790215240501001234...",
"qr_url": "https://api.gpay.co.id/qris/240501001234.png",
"expired_at": "2024-05-01T10:15:00Z"
}
}
}
Contoh Response Gagal
{
"success": true,
"message": "QRIS creation failed",
"rc": "009",
"data": {
"req_id": "QRIS-20240501-002",
"status": "FAILED",
"rc": "009",
"description": "Biller Error",
"message": "GPay tidak tersedia saat ini",
"data": {}
}
}
Langkah Selanjutnya
Setelah mendapatkan QRIS:
- Tampilkan QR code kepada pelanggan menggunakan
data.qr_string(render menjadi QR image) ataudata.qr_url(langsung tampilkan gambar). - Simpan
trace_number— digunakan untuk cek status dan refund. - Polling status via Cek Status QRIS atau tunggu webhook callback.
Catatan
- QR code memiliki masa berlaku (lihat
data.expired_at). Jika kedaluwarsa tanpa pembayaran, buat QRIS baru denganreq_idbaru. - Jika koneksi terputus saat membuat QRIS, coba lagi dengan
req_idyang sama — sistem akan mengembalikan QRIS yang sudah dibuat tanpa membuat duplikat.
QRIS — Cek Status
Mengecek status pembayaran QRIS menggunakan trace_number yang didapat dari response Buat QRIS.
URL: POST /api/v1/merchant/payin/qris/check
Request
Headers
| Header | Wajib | Keterangan |
|---|---|---|
X-API-Key | Ya | API Key merchant |
Content-Type | Ya | application/json |
Body
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
trace_number | String | Ya | trace_number dari response QRIS create |
Contoh Request
{
"trace_number": "240501001234"
}
curl -X POST "https://api-sandbox.alfakios.com/api/v1/merchant/payin/qris/check" \
-H "Content-Type: application/json" \
-H "X-API-Key: apk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-d '{"trace_number": "240501001234"}'
Response
Spesifikasi
| Field | Tipe | Keterangan |
|---|---|---|
req_id | String | req_id dari transaksi asal |
ref_id | String | ID referensi internal |
product_id | String | Kode produk QRIS |
trace_number | String | Trace number yang dicek |
status | String | SUCCESS, PENDING, atau FAILED |
rc | String | Kode respon |
description | String | Keterangan RC |
message | String | Pesan detail |
amount | String | Nominal pembayaran |
data | Object | Data tambahan dari GPay (payer info, dll) |
Contoh Response — Dibayar (SUCCESS)
{
"success": true,
"message": "Pembayaran QRIS diterima",
"rc": "000",
"data": {
"req_id": "QRIS-20240501-001",
"ref_id": "1777946295495371000",
"product_id": "GPAY",
"trace_number": "240501001234",
"status": "SUCCESS",
"rc": "000",
"description": "Payment Received",
"message": "Pembayaran QRIS berhasil dikonfirmasi",
"amount": "150000",
"data": {
"payer_name": "ANDI WIJAYA",
"payer_number": "08123456789",
"issuer": "BCA Mobile",
"paid_at": "2024-05-01T10:08:32Z",
"rrn": "240501123456"
}
}
}
Contoh Response — Belum Dibayar (PENDING)
{
"success": true,
"message": "Menunggu pembayaran",
"rc": "021",
"data": {
"req_id": "QRIS-20240501-001",
"ref_id": "1777946295495371000",
"product_id": "GPAY",
"trace_number": "240501001234",
"status": "PENDING",
"rc": "021",
"description": "Waiting Payment",
"message": "QRIS belum dibayar",
"amount": "150000",
"data": {}
}
}
Contoh Response — Tidak Ditemukan
Jika trace_number tidak valid atau tidak terdaftar di merchant ini:
HTTP Status: 404 Not Found
{
"success": false,
"message": "Transaction not found"
}
Rekomendasi Polling
Gunakan interval polling yang meningkat agar tidak membebani server:
Detik 0–30 : polling setiap 3 detik
Detik 30–60 : polling setiap 5 detik
Detik 60+ : polling setiap 10 detik
> 5 menit : tampilkan "QR kedaluwarsa" ke pelanggan
Catatan
- Endpoint ini hanya bisa mengecek QRIS yang dibuat oleh merchant yang sama (API Key yang sama).
- Setelah pembayaran dikonfirmasi (
status: "SUCCESS"),trace_numberdapat digunakan untuk refund via QRIS Refund jika diperlukan.
QRIS — Refund
Mengajukan refund untuk pembayaran QRIS yang sudah berhasil. Dana dikembalikan ke akun pelanggan yang membayar.
URL: POST /api/v1/merchant/payin/qris/refund
Refund hanya dapat dilakukan untuk transaksi dengan
status: "SUCCESS". Pastikan Anda sudah mengonfirmasi status pembayaran via Cek Status QRIS sebelum mengajukan refund.
Request
Headers
| Header | Wajib | Keterangan |
|---|---|---|
X-API-Key | Ya | API Key merchant |
Content-Type | Ya | application/json |
X-Signature | Kondisional | Jika Signature Validation aktif |
X-Timestamp | Kondisional | Unix timestamp (jika Signature Validation aktif) |
Body
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
trace_number | String | Ya | trace_number dari transaksi QRIS yang akan di-refund |
Contoh Request
{
"trace_number": "240501001234"
}
curl -X POST "https://api-sandbox.alfakios.com/api/v1/merchant/payin/qris/refund" \
-H "Content-Type: application/json" \
-H "X-API-Key: apk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-d '{"trace_number": "240501001234"}'
Response
Spesifikasi
| Field | Tipe | Keterangan |
|---|---|---|
req_id | String | req_id dari transaksi asal |
ref_id | String | ID referensi refund |
product_id | String | Kode produk QRIS |
trace_number | String | Trace number yang di-refund |
status | String | SUCCESS, PENDING, atau FAILED |
rc | String | Kode respon |
description | String | Keterangan RC |
message | String | Pesan detail |
amount | String | Nominal yang di-refund |
data | Object | Data tambahan dari GPay |
Contoh Response Berhasil
{
"success": true,
"message": "Refund berhasil",
"rc": "000",
"data": {
"req_id": "QRIS-20240501-001",
"ref_id": "1777946295495380000",
"product_id": "GPAY",
"trace_number": "240501001234",
"status": "SUCCESS",
"rc": "000",
"description": "Refund Processed",
"message": "Refund QRIS 150000 berhasil diproses",
"amount": "150000",
"data": {
"refund_id": "RF-240501001234",
"refunded_at": "2024-05-01T10:30:00Z"
}
}
}
Contoh Response Gagal — Transaksi Tidak Ditemukan
HTTP Status: 404 Not Found
{
"success": false,
"message": "Transaction not found"
}
Contoh Response Gagal — Transaksi Belum Sukses
{
"success": true,
"message": "Refund failed",
"rc": "009",
"data": {
"trace_number": "240501001234",
"status": "FAILED",
"rc": "009",
"description": "Transaction not eligible for refund",
"message": "Hanya transaksi dengan status SUCCESS yang dapat di-refund",
"data": {}
}
}
Catatan
- Refund hanya dapat dilakukan untuk transaksi yang sudah SUCCESS.
- Kebijakan refund (batas waktu, ketersediaan) ditentukan oleh GPay — hubungi tim support jika refund ditolak.
- Setelah refund sukses, dana dikembalikan ke akun pelanggan dalam 1–3 hari kerja (tergantung bank/dompet pelanggan).
- Setiap
trace_numberhanya dapat di-refund satu kali.
Cek Saldo Merchant
Mengecek saldo deposit merchant saat ini.
URL: POST /api/v1/balance/merchant
Autentikasi
Endpoint ini menggunakan API Key via header X-API-Key. Signature Validation tidak diterapkan pada endpoint ini.
Request
Headers
| Header | Wajib | Keterangan |
|---|---|---|
X-API-Key | Ya | API Key merchant |
Content-Type | Ya | application/json |
Body
Request body bersifat opsional. Request kosong ({}) atau tanpa body juga diterima.
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
req_id | String | Tidak | ID request untuk tracing |
ref_id | String | Tidak | ID referensi untuk tracing |
product_id | String | Tidak | Kode produk untuk konteks |
cust_id | String | Tidak | ID customer untuk konteks |
Contoh Request (minimal)
curl -s -X POST "https://api-sandbox.alfakios.com/api/v1/balance/merchant" \
-H "Content-Type: application/json" \
-H "X-API-Key: apk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-d '{}'
Contoh Request (dengan tracing)
curl -s -X POST "https://api-sandbox.alfakios.com/api/v1/balance/merchant" \
-H "Content-Type: application/json" \
-H "X-API-Key: apk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-d '{
"req_id": "BAL-CHECK-001"
}'
Response
Spesifikasi
| Field | Tipe | Keterangan |
|---|---|---|
req_id | String | req_id yang dikirim (kosong jika tidak dikirim) |
ref_id | String | ref_id yang dikirim (kosong jika tidak dikirim) |
product_id | String | product_id yang dikirim |
cust_id | String | cust_id yang dikirim |
status | String | SUCCESS atau FAILED |
rc | String | Kode respon |
description | String | Keterangan RC |
message | String | Pesan detail |
unit_price | String | Kosong untuk balance check |
balance_used | String | Kosong untuk balance check |
balance | String | Saldo deposit merchant saat ini (dalam IDR) |
serial_no | String | Bernilai "balance" untuk endpoint ini |
data | Any | Data tambahan (biasanya null) |
Contoh Response
{
"success": true,
"message": "Balance retrieved successfully",
"rc": "000",
"data": {
"req_id": "",
"ref_id": "",
"product_id": "",
"cust_id": "",
"status": "SUCCESS",
"rc": "000",
"description": "",
"message": "balance retrieved",
"unit_price": "",
"balance_used": "",
"balance": "4493500",
"serial_no": "balance",
"data": null
}
}
Nilai balance adalah Rp 4.493.500 dalam contoh di atas.
Kapan Menggunakannya
- Sebelum melakukan transaksi besar, untuk memastikan saldo mencukupi.
- Setelah menerima response disbursement dengan
rc: "021"(PENDING) — fieldbalancepada response/disbursement/statusbisa kosong, gunakan endpoint ini untuk saldo terbaru. - Untuk menampilkan saldo di dashboard aplikasi merchant.
Katalog Produk
Mengembalikan daftar produk yang tersedia untuk merchant berdasarkan API Key yang digunakan.
URL: GET /api/v1/product/inquiry
Autentikasi
Endpoint ini menggunakan API Key via header X-API-Key. Tidak memerlukan Signature Validation.
Request
Tidak ada parameter atau body — cukup kirim GET request dengan API Key.
curl --location 'https://api-sandbox.alfakios.com/api/v1/product/inquiry' \
--header 'X-API-Key: apk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
Response
Field data berisi array flat produk yang tersedia.
Spesifikasi per Produk
| Field | Tipe | Keterangan |
|---|---|---|
operator | String | Nama operator/provider produk |
product_id | String | Kode produk — gunakan nilai ini di field product_id pada request transaksi |
denom | String | Denominasi/nilai produk ("0" = harga dinamis berdasarkan nominal) |
description | String | Deskripsi produk |
unit_price | String | Harga jual dalam IDR ("0" = harga dinamis) |
status | String | OPEN, CLOSED, atau MAINTENANCE |
Contoh Response
{
"success": true,
"message": "Products retrieved successfully",
"rc": "000",
"data": [
{
"operator": "Bank Transfer",
"product_id": "DSTF",
"denom": "0",
"description": "Disbursement Transfer",
"unit_price": "0",
"status": "OPEN"
},
{
"operator": "Token PLN",
"product_id": "PLNPREP",
"denom": "0",
"description": "PLN Token Prabayar",
"unit_price": "0",
"status": "OPEN"
},
{
"operator": "PLN Pascabayar",
"product_id": "PLNPOST",
"denom": "0",
"description": "Tagihan PLN Pascabayar",
"unit_price": "0",
"status": "OPEN"
},
{
"operator": "BPJS Kesehatan",
"product_id": "BPJSKS",
"denom": "0",
"description": "BPJS Kesehatan",
"unit_price": "0",
"status": "OPEN"
},
{
"operator": "GoPay",
"product_id": "GOPAY",
"denom": "0",
"description": "Top-up GoPay",
"unit_price": "0",
"status": "OPEN"
},
{
"operator": "XL Axiata",
"product_id": "XL5",
"denom": "5000",
"description": "Pulsa XL Rp 5.000",
"unit_price": "5500",
"status": "OPEN"
},
{
"operator": "Telkomsel",
"product_id": "TSEL10",
"denom": "10000",
"description": "Pulsa Telkomsel Rp 10.000",
"unit_price": "10800",
"status": "MAINTENANCE"
}
]
}
Catatan Penggunaan
- Gunakan
product_iddari response ini sebagai nilai fieldproduct_idpada request transaksi apa pun. - Produk dengan
status: "MAINTENANCE"ataustatus: "CLOSED"tidak dapat digunakan untuk transaksi dan akan mengembalikan errorrc: "007"ataurc: "006". unit_price: "0"artinya harga dihitung dinamis berdasarkanamountyang dikirim — biaya final tampil di fieldfeedantotal_costpada response inquiry/payment.- Daftar produk bisa berbeda antar merchant tergantung konfigurasi akun.
Integrasi dengan Endpoint Lain
| Kategori | Field | Sumber dari Katalog |
|---|---|---|
| PPOB | product_id | product_id dengan operator sesuai layanan |
| Disbursement | product_id | product_id: "DSTF" atau produk transfer lainnya |
| PayIn QRIS | product_id | product_id: "GPAY" |
Contoh Integrasi Lengkap
Contoh alur integrasi end-to-end untuk berbagai use case.
1. Beli Pulsa (PHP)
<?php
class RelayAPI {
private $baseUrl;
private $apiKey;
public function __construct(string $baseUrl, string $apiKey) {
$this->baseUrl = rtrim($baseUrl, '/');
$this->apiKey = $apiKey;
}
public function post(string $path, array $body): array {
$ch = curl_init("{$this->baseUrl}{$path}");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($body),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
"X-API-Key: {$this->apiKey}",
],
]);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
}
$api = new RelayAPI('https://api-sandbox.alfakios.com', 'apk_live_xxx');
$result = $api->post('/api/v1/merchant/ppob/phone-credit/transaction', [
'req_id' => 'TXN-' . date('YmdHis') . '-' . rand(1000, 9999),
'product_id' => 'XL5',
'cust_id' => '08123456789',
]);
if ($result['data']['status'] === 'SUCCESS') {
echo "Sukses! SN: " . $result['data']['serial_no'];
} elseif ($result['data']['status'] === 'PENDING') {
echo "Pending. Cek status dengan req_id: " . $result['data']['req_id'];
} else {
echo "Gagal: " . $result['data']['description'];
}
2. Disbursement Lengkap (Node.js)
const axios = require('axios');
const API = axios.create({
baseURL: 'https://api-sandbox.alfakios.com',
headers: {
'Content-Type': 'application/json',
'X-API-Key': 'apk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
},
timeout: 15000,
});
async function transferDana(reqId, accountNumber, amount, bankCode = '014') {
// Step 1: Inquiry
const inquiry = await API.post('/api/v1/merchant/disbursement/inquiry', {
product_id: 'DSTF', account_number: accountNumber,
amount, bank_code: bankCode,
});
if (inquiry.data.data.status !== 'SUCCESS') {
throw new Error(`Inquiry gagal: ${inquiry.data.data.description}`);
}
const { account_name, fee, total_cost } = inquiry.data.data;
console.log(`Nama: ${account_name} | Fee: Rp ${fee} | Total: Rp ${total_cost}`);
// Step 2: Payment
const payment = await API.post('/api/v1/merchant/disbursement/payment', {
req_id: reqId, product_id: 'DSTF',
account_number: accountNumber, amount, bank_code: bankCode,
});
const d = payment.data.data;
if (d.status === 'SUCCESS') {
console.log(`✅ Sukses! Ref: ${d.serial_no}, Saldo: Rp ${d.balance}`);
return d;
}
if (d.status === 'PENDING') {
return await pollDisbursementStatus(reqId, accountNumber, amount, bankCode);
}
throw new Error(`Gagal: ${d.description} (RC: ${d.rc})`);
}
async function pollDisbursementStatus(reqId, accountNumber, amount, bankCode) {
const delays = [30000, 60000, 120000, 300000];
for (const delay of delays) {
await new Promise(r => setTimeout(r, delay));
const res = await API.post('/api/v1/merchant/disbursement/status', {
product_id: 'DSTF', account_number: accountNumber,
amount, bank_code: bankCode, req_id: reqId,
});
const { status, description } = res.data.data;
if (status === 'SUCCESS') { console.log('✅ Sukses'); return res.data.data; }
if (status === 'FAILED') { throw new Error(`Gagal: ${description}`); }
console.log('Masih PENDING...');
}
throw new Error('Timeout — eskalasi ke support dengan req_id: ' + reqId);
}
transferDana('PAY-' + Date.now(), '1380610457', '100000').catch(console.error);
3. Token PLN Prabayar (Python)
import requests, time, uuid
BASE_URL = "https://api-sandbox.alfakios.com"
HEADERS = {"Content-Type": "application/json",
"X-API-Key": "apk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}
def beli_token_pln(nomor_meter: str) -> dict:
req_id = f"PLN-{int(time.time())}-{uuid.uuid4().hex[:6]}"
# Inquiry
r = requests.post(f"{BASE_URL}/api/v1/merchant/ppob/pln/prepaid/inquiry",
json={"product_id": "PLNPREP", "cust_id": nomor_meter},
headers=HEADERS, timeout=15)
r.raise_for_status()
inq = r.json()["data"]
if inq["status"] != "SUCCESS":
raise ValueError(f"Inquiry gagal: {inq['description']}")
print(f"Pelanggan: {inq['data'].get('nama_pelanggan', '-')}, Harga: Rp {inq['unit_price']}")
# Transaksi
r = requests.post(f"{BASE_URL}/api/v1/merchant/ppob/pln/prepaid/transaction",
json={"req_id": req_id, "product_id": "PLNPREP", "cust_id": nomor_meter},
headers=HEADERS, timeout=15)
r.raise_for_status()
result = r.json()["data"]
if result["status"] == "SUCCESS":
print(f"✅ Token: {result['serial_no']}")
elif result["status"] == "PENDING":
print(f"⏳ Pending — req_id: {req_id}")
else:
print(f"❌ Gagal: {result['description']}")
return result
beli_token_pln("12345678901")
4. QRIS PayIn (Go)
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
const (
baseURL = "https://api-sandbox.alfakios.com"
apiKey = "apk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
)
func callAPI(path string, body interface{}) map[string]interface{} {
b, _ := json.Marshal(body)
req, _ := http.NewRequest("POST", baseURL+path, bytes.NewReader(b))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-API-Key", apiKey)
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
raw, _ := io.ReadAll(resp.Body)
var result map[string]interface{}
json.Unmarshal(raw, &result)
return result
}
func main() {
reqID := fmt.Sprintf("QRIS-%d", time.Now().Unix())
// Buat QRIS
res := callAPI("/api/v1/merchant/payin/qris/create", map[string]string{
"req_id": reqID, "product_id": "GPAY", "amount": "75000",
})
data := res["data"].(map[string]interface{})
traceNumber := data["trace_number"].(string)
fmt.Printf("QRIS dibuat. Trace: %s\n", traceNumber)
// Polling sampai dibayar
for i := 0; i < 12; i++ {
time.Sleep(5 * time.Second)
status := callAPI("/api/v1/merchant/payin/qris/check",
map[string]string{"trace_number": traceNumber})
d := status["data"].(map[string]interface{})
s := d["status"].(string)
fmt.Printf("Status [%d]: %s\n", i+1, s)
if s == "SUCCESS" { fmt.Println("✅ Pembayaran diterima!"); return }
if s == "FAILED" { fmt.Println("❌ QRIS gagal/kedaluwarsa"); return }
}
fmt.Println("Timeout polling — buat QRIS baru")
}
5. Cek Saldo (cURL)
curl -s -X POST "https://api-sandbox.alfakios.com/api/v1/balance/merchant" \
-H "Content-Type: application/json" \
-H "X-API-Key: apk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-d '{}' | python3 -c "import sys,json; d=json.load(sys.stdin); print('Saldo: Rp', d['data']['balance'])"
6. BPJS Lengkap (PHP)
<?php
$api = new RelayAPI('https://api-sandbox.alfakios.com', 'apk_live_xxx');
$inqId = 'INQ-' . time();
// Step 1: Inquiry
$inquiry = $api->post('/api/v1/merchant/ppob/bpjs/inquiry', [
'product_id' => 'BPJSKS',
'cust_id' => '0001234567890',
'period' => '01',
'mobile_no' => '08123456789',
]);
if ($inquiry['data']['status'] !== 'SUCCESS') {
die("Inquiry gagal: " . $inquiry['data']['description']);
}
echo "Nama: " . $inquiry['data']['data']['nama_peserta'] . "\n";
echo "Tagihan: Rp " . $inquiry['data']['data']['tagihan'] . "\n";
// Step 2: Payment
$payment = $api->post('/api/v1/merchant/ppob/bpjs/transaction', [
'req_id' => 'PAY-' . time(),
'product_id' => 'BPJSKS',
'cust_id' => '0001234567890',
'period' => '01',
'inquiry_req_id' => $inqId,
'mobile_no' => '08123456789',
]);
echo "Status: " . $payment['data']['status'] . "\n";
echo "Struk: " . $payment['data']['serial_no'] . "\n";
Catatan Perubahan
Disbursement API
| Versi | Tanggal | Keterangan | PIC |
|---|---|---|---|
| 1.0 | 30 April 2026 | Dokumen perdana: inquiry, payment, status | Backend API Team |
| 1.1 | 30 April 2026 | Ganti autentikasi dari OAuth2 ke API Key (X-API-Key) | Backend API Team |
| 1.2 | 05 Mei 2026 | Tambah req_id wajib di payment (idempotency); field details OtomaX; dokumentasi cek saldo dan katalog produk | Backend API Team |
PPOB API
| Versi | Tanggal | Keterangan | PIC |
|---|---|---|---|
| 1.0 | 01 Mei 2026 | Rilis perdana: pulsa, e-wallet, PLN prabayar/pascabayar, BPJS | Backend API Team |
| 1.1 | 05 Mei 2026 | Tambah endpoint cek status (/ppob/check); timeout 8 detik | Backend API Team |
PayIn QRIS API
| Versi | Tanggal | Keterangan | PIC |
|---|---|---|---|
| 1.0 | 07 Mei 2026 | Rilis perdana: create, check, refund via GPay | Backend API Team |
Dokumentasi mdBook
| Tanggal | Keterangan |
|---|---|
| 08 Mei 2026 | Dokumentasi komprehensif merchant API dikonversi ke format mdBook |