Ekosistem API Bank ABC
Platform H2H (Host-to-Host) berbasis standar SNAP BI: sistem backend Anda berkomunikasi langsung ke server Bank ABC tanpa browser, tanpa redirect, dan tanpa interaksi manual. Setiap request ditandatangani secara kriptografis menggunakan RSA dan diverifikasi di kedua sisi.
Arsitektur koneksi
Navigasi dokumentasi
Open Banking: Mengapa Bank Jadi Pusat Ekosistem?
Selama puluhan tahun, data keuangan hidup secara tertutup di dalam sistem bank; tidak ada cara bagi pihak luar untuk mengaksesnya secara terprogram. Open Banking mengubah paradigma ini: bank membuka akses ke infrastruktur keuangan mereka melalui API terstandar, sehingga developer dapat membangun layanan di atas data dan kapabilitas bank dengan izin yang jelas.
Di Indonesia, kerangka ini diatur oleh Bank Indonesia melalui regulasi SNAP BI (Standar Nasional Open API Pembayaran). SNAP BI mendefinisikan format request/response, mekanisme autentikasi, dan standar keamanan yang wajib diikuti oleh seluruh bank dan fintech yang beroperasi dalam ekosistem pembayaran nasional. Bank ABC mengikuti standar ini sepenuhnya.
Mengapa bank berada di pusat ekosistem?
Ekosistem Open Banking: siapa berbicara ke siapa
Konsep H2H (Host-to-Host)
Layanan transaksi berbasis Host-to-Host (H2H) memberikan Anda akses komunikasi langsung ke sistem Bank ABC melalui aturan bahasa dan respons yang disepakati, tanpa perantara browser atau interaksi manual. Setiap request ditandatangani secara kriptografis menggunakan RSA key pair dan diverifikasi di kedua sisi; itulah yang membedakannya dari REST API pada umumnya.
H2H vs integrasi berbasis browser
Membutuhkan intervensi manusia. Tidak bisa diotomasi penuh.
Server-to-server langsung. Tidak ada browser, tidak ada redirect, tidak ada intervensi manual.
Prasyarat teknis
Alur koneksi
Authorization dan tanda tangan RSA di header X-SIGNATURE.Langkah berikutnya: Daftarkan RSA public key Anda (Signing Key) untuk mulai menandatangani request.
Signing Key
Setiap request API ke Bank ABC harus disertai tanda tangan digital. Ini membuktikan bahwa request benar-benar datang dari server Anda, bukan dari pihak lain yang berpura-pura menjadi Anda.
Signing Key adalah mekanisme untuk membuat tanda tangan tersebut. Teknologi di baliknya adalah RSA, standar kriptografi yang sama dipakai oleh HTTPS, SSH, dan JWT di seluruh internet. Anda tidak perlu memahami matematikanya. Yang perlu dipahami adalah cara kerjanya: ada dua kunci dengan fungsi yang berbeda.
Dua kunci, dua fungsi yang berbeda
Private Key
private_key.pem
- Dibuat di terminal server Anda
- Disimpan hanya di server Anda
- Digunakan untuk menandatangani setiap request
Public Key
public_key.pem
- Diekstrak otomatis dari private key
- Diunggah ke Bank ABC sekali saat setup
- Bank ABC menggunakannya untuk verifikasi tanda tangan
Setup: 2 langkah, sekali seumur proyek
Generate RSA key pair di terminal
Jalankan dua perintah ini satu kali di server Anda. Hasilnya dua file .pem.
openssl genrsa -out private_key.pem 2048 openssl rsa -in private_key.pem -pubout -out public_key.pem
Daftarkan public key di portal
Buka halaman Credentials, masuk ke tab Signing Key, paste seluruh isi file public_key.pem termasuk baris BEGIN dan END, lalu simpan. Tidak perlu diulang kecuali Anda merotasi key.
Tidak punya tanggal kedaluwarsa. Dibuat dan didaftarkan sekali, berlaku selamanya kecuali Anda memilih untuk merotasi. Ini yang baru saja Anda generate di langkah 1.
Kedaluwarsa setiap 15 menit. Dibuat otomatis oleh kode Anda dari client_id dan client_secret. Ini bukan RSA, ini OAuth 2.0 token biasa.
Yang terjadi di setiap request API
Contoh implementasi signing
import jwt, time, hashlib, base64
from cryptography.hazmat.primitives import serialization
with open("private_key.pem", "rb") as f:
private_key = serialization.load_pem_private_key(f.read(), password=None)
def get_access_token(client_id, client_secret):
payload = {"iss": client_id, "sub": client_id,
"iat": int(time.time()), "exp": int(time.time()) + 900}
return jwt.encode(payload, private_key, algorithm="RS256")
def sign_request(method, path, body, timestamp):
body_hash = base64.b64encode(hashlib.sha256(body.encode()).digest()).decode()
string_to_sign = f"{method}:{path}:{body_hash}:{timestamp}"
return jwt.encode({"data": string_to_sign}, private_key, algorithm="RS256")const jose = require('jose');
const fs = require('fs'), crypto = require('crypto');
const privateKey = crypto.createPrivateKey(fs.readFileSync('private_key.pem'));
async function getAccessToken(clientId) {
return new jose.SignJWT({ iss: clientId, sub: clientId })
.setProtectedHeader({ alg: 'RS256' }).setIssuedAt().setExpirationTime('15m')
.sign(privateKey);
}
function signRequest(method, path, body, timestamp) {
const bodyHash = crypto.createHash('sha256').update(body).digest('base64');
const stringToSign = `${method}:${path}:${bodyHash}:${timestamp}`;
return crypto.sign('sha256', Buffer.from(stringToSign), privateKey).toString('base64');
}PrivateKey privateKey = loadPrivateKeyFromPem("private_key.pem");
String getAccessToken(String clientId) {
long now = Instant.now().getEpochSecond();
return Jwts.builder().setIssuer(clientId).setSubject(clientId)
.setIssuedAt(new Date(now*1000)).setExpiration(new Date((now+900)*1000))
.signWith(privateKey, SignatureAlgorithm.RS256).compact();
}
String signRequest(String method, String path, String body, String timestamp) {
String bodyHash = Base64.getEncoder().encodeToString(
MessageDigest.getInstance("SHA-256").digest(body.getBytes()));
String toSign = method + ":" + path + ":" + bodyHash + ":" + timestamp;
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initSign(privateKey); sig.update(toSign.getBytes());
return Base64.getEncoder().encodeToString(sig.sign());
}Spesifikasi teknis
Error signing yang umum
| Response Code | HTTP | Penyebab | Solusi |
|---|---|---|---|
| 4012900 | 401 | Access token kedaluwarsa | Generate token baru secara otomatis dan ulangi request |
| 4012901 | 401 | Signature tidak valid | Periksa format string_to_sign dan private key yang digunakan |
| 4012902 | 401 | RSA public key belum terdaftar | Daftarkan public key di Credentials > Signing Key |
| 4002900 | 400 | Header X-TIMESTAMP tidak sesuai format | Gunakan ISO 8601: 2026-05-23T09:00:00+07:00 |
Glosarium SNAP BI
Terminologi standar yang digunakan di seluruh dokumentasi API Bank ABC, mengacu pada regulasi SNAP BI dari Bank Indonesia.
| Istilah | Penjelasan |
|---|---|
| SNAP BI | Standar Nasional Open API Perbankan dari Bank Indonesia. Mendefinisikan format request, header wajib, dan struktur response untuk semua transaksi antar bank dan mitra. |
| H2H | Host-to-Host. Koneksi langsung server-to-server tanpa browser atau manusia. Mitra mengintegrasikan backend mereka langsung ke server Bank ABC. |
| Signing Key | RSA key pair untuk menandatangani setiap request API. Private key disimpan di sisi mitra, public key didaftarkan ke Bank ABC melalui Credentials. |
| VA (Virtual Account) | Nomor rekening virtual untuk tracking dan routing pembayaran. Bisa berupa VA unik per transaksi atau VA statis permanen per merchant. |
| partnerReferenceNo | ID unik yang dibuat oleh sistem mitra untuk setiap transaksi. Digunakan untuk idempotency: request dengan ID sama tidak diproses dua kali. |
| T+0 Settlement | Dana diselesaikan pada hari yang sama. Berlaku untuk transaksi yang masuk sebelum pukul 15.00 WIB di hari kerja. |
| CBS | Core Banking System. Sistem inti Bank ABC yang memproses semua transaksi keuangan dan ledger rekening. |
| X-SIGNATURE | HTTP header berisi tanda tangan RSA per-request. Dibuat dari hash method + path + body + timestamp, ditandatangani dengan RSA private key mitra. |
| Access Token | JWT OAuth 2.0 untuk otentikasi sesi. Berlaku 15 menit, dibuat otomatis oleh kode Anda dari client_id dan client_secret. |
| Callback URL | Endpoint HTTPS milik mitra yang menerima notifikasi asinkron dari Bank ABC setelah transaksi diproses. |
| Idempotency | Properti yang memastikan request dengan partnerReferenceNo yang sama tidak diproses lebih dari sekali meskipun dikirim ulang. |
Panduan Troubleshooting
Isu paling umum yang ditemui selama integrasi dan setelah live. Setiap item mencakup penyebab akar dan langkah konkret untuk mengatasinya.
Token berlaku 15 menit sejak di-generate (diperbarui di v1.2, sebelumnya 60 menit). Ini seringkali mengejutkan developer yang masih menggunakan asumsi lama.
Solusi: Implementasikan proactive refresh di kode Anda: generate token baru secara otomatis sebelum expired, bukan setelah mendapat error 401. Cek header X-Expires-In pada response auth untuk durasi tepat. Simpan token di in-memory cache dengan TTL 12 menit untuk safety margin.
Referensi: Signing Key > Spesifikasi Teknis
Verifikasi 4 hal secara berurutan:
1. URL terdaftar persis sama di halaman Credentials, termasuk trailing slash dan protokol HTTPS. Perbedaan satu karakter akan menyebabkan callback tidak dikirim.
2. Endpoint Anda harus mengembalikan HTTP 200 dalam 5 detik. Jika response lebih lambat dari itu, Bank ABC menganggap delivery gagal dan akan retry. Pastikan endpoint tidak melakukan proses berat sebelum mengembalikan 200.
3. Firewall tidak memblokir IP notifikasi Bank ABC. Minta tim infrastruktur untuk whitelist range IP callback Bank ABC (tersedia di halaman Integrasi Langsung).
4. Cek log delivery di portal: Integrasi Langsung > Log Callback untuk melihat status setiap upaya pengiriman.
partnerReferenceNo berfungsi sebagai idempotency key: request dengan ID yang sama dalam 24 jam terakhir akan ditolak dengan 4092900.
Pola yang benar: Gunakan format UUID-v4 + epoch timestamp untuk memastikan keunikan di setiap transaksi baru. Contoh: TRF-1716598800-a3f2c1d9.
Untuk idempotent retry (mengirim ulang transaksi yang sama karena timeout): gunakan partnerReferenceNo yang SAMA, bukan nilai baru. Bank ABC akan mengembalikan response transaksi yang sudah diproses tanpa memroses ulang.
Format wajib: ISO 8601 dengan timezone offset WIB eksplisit: 2026-05-21T14:30:00+07:00. Format UTC (Z suffix) tidak diterima.
Clock skew: Nilai timestamp harus berada dalam rentang +/- 5 menit dari server time Bank ABC. Jika server Anda tidak tersinkronisasi, request akan ditolak dengan error 4002900 meskipun format sudah benar.
Solusi clock skew: Pastikan NTP daemon berjalan di server Anda (timedatectl status di Linux) dan waktu server sinkron ke time.google.com atau pool.ntp.org.
Sesuai regulasi SNAP BI: transfer di atas Rp 5.000.000 per transaksi atau akumulasi harian di atas Rp 25.000.000 memerlukan validasi tambahan.
Bank ABC mengembalikan response code 4013 dengan additionalInfo.otpRequired: true ketika threshold tercapai. Ini bukan error, ini adalah sinyal bahwa flow autentikasi tambahan perlu dijalankan.
Yang harus diimplementasikan: Tangkap response 4013 di error handler Anda dan arahkan flow ke OTP verification step sebelum mengirim ulang transaksi.
Sejak v1.4 (12 April 2026), dua kode error dipisah:
4001 = parameter request tidak valid atau format salah. 4002 = rekening tujuan tidak ditemukan atau tidak aktif.
Sebelum v1.4, keduanya menggunakan 4001 untuk semua kasus validasi. Jika error handler Anda hanya menangani 4001, Anda tidak akan menangkap 4002 dengan benar.
Tindakan: Update error handler untuk menangani 4001 dan 4002 secara terpisah. Lihat Changelog v1.4 untuk detail lengkap.
Ini hampir selalu masalah IP whitelist. Sandbox tidak mewajibkan whitelist IP (untuk kemudahan development), tapi production mewajibkan IP publik statis server Anda terdaftar.
Cara mendaftar: Buka Credentials, pilih credential production, klik ikon detail, lalu buka tab IP Whitelist. Masukkan IP publik statis server production Anda. Perubahan berlaku dalam 2 hingga 5 menit.
Sandbox mengizinkan maksimal 5 IP per credential. Jika Anda menggunakan load balancer atau NAT gateway, daftarkan IP keluar (egress IP) dari infrastruktur tersebut, bukan IP server individual.
Changelog
Riwayat perubahan signifikan pada API Bank ABC. Breaking changes ditandai secara eksplisit dan mencakup panduan migrasi.
4001. Mulai v1.4: 4001 = parameter tidak valid, 4002 = rekening tujuan tidak ditemukan. Update error handler untuk menangani keduanya secara terpisah.
X-Expires-In ditambahkan pada response auth token. Berisi durasi validitas token dalam detik. Gunakan ini untuk proactive refresh daripada hardcode durasi.
X-Expires-In (tersedia di v1.4).
callbackUrl di request body memungkinkan override URL callback per-transaksi. Berguna untuk skenario multi-tenant dimana setiap merchant memiliki callback endpoint berbeda.
Virtual Account (VA): Use Case & Konteks Bisnis
Rumah sakit atau klinik menggunakan VA Bank ABC untuk otomasi routing pembayaran tagihan medis. Setiap tagihan rawat inap, poliklinik, atau biaya lab dapat dibuat VA unik dengan nominal dan waktu berlaku tertentu, sehingga rekonsiliasi berjalan otomatis tanpa input manual bendahara.
Pembayar (pasien atau penjamin seperti BPJS/asuransi) melunasi tagihan dari channel mana saja: mobile banking, ATM, atau internet banking. Sistem RS menerima konfirmasi melalui callback real-time.
Aktor Utama
Alur Integrasi
Merchant retail, toko online, atau sistem kasir POS menggunakan VA statis Bank ABC sebagai "nomor rekening toko" yang permanen. Pembeli mentransfer ke VA merchant dari channel mana saja; dana langsung tercatat dan terekonsiliasi tanpa konfirmasi manual kasir.
VA statis sangat cocok untuk toko dengan volume transaksi tinggi karena satu nomor VA dapat menerima ribuan pembayaran, dengan setiap transaksi dilaporkan via callback real-time ke sistem POS.
Aktor Utama
Alur Integrasi
Platform fintech menggunakan VA Bank ABC sebagai jalur distribusi dana untuk pencairan pinjaman P2P lending, top-up saldo e-wallet, pembayaran gaji (payroll), dan distribusi reward merchant.
Alur dana berjalan dari rekening giro fintech → VA Bank ABC → rekening tujuan akhir, dengan settlement T+0 pada hari kerja sebelum pukul 15.00 WIB.
Aktor Utama
Alur Uang (Settlement T+0)
Sekolah atau universitas menggunakan VA Bank ABC per siswa untuk pembayaran SPP, biaya ujian, daftar ulang, atau biaya kegiatan. VA dapat dikonfigurasi untuk menerima pembayaran berulang setiap periode tagihan tanpa perlu membuat VA baru setiap semester.
Bendahara sekolah mendapat rekonsiliasi otomatis: setiap pembayaran yang masuk langsung terhubung ke data siswa melalui nomor VA yang sudah terpetakan di sistem.
Aktor Utama
Alur Integrasi
Perusahaan listrik, air, atau gas menggunakan VA Bank ABC per nomor pelanggan untuk penagihan bulanan. Pelanggan membayar tagihan dari channel mana saja; rekonsiliasi berjalan otomatis di sisi back-office tanpa proses matching manual.
Satu VA pelanggan berlaku seumur hidup berlangganan: sistem utilitas hanya perlu membuatnya sekali dan menggunakan nomor yang sama untuk semua tagihan berikutnya.
Aktor Utama
Alur Integrasi
Topologi Koneksi & Sequence Diagram
Integrasi VA Disbursement menggunakan pola H2H (Host-to-Host) berbasis standar SNAP BI. Koneksi berjalan server-to-server: sistem Anda memanggil endpoint Bank ABC langsung dari backend.
Sequence Diagram: Disbursement Flow
Persyaratan Koneksi
Authorization dan tanda tangan RSA di header X-SIGNATURE. Keduanya dibuat otomatis oleh kode Anda setelah RSA public key terdaftar.POST /va/disburse
/snap/v1.0/va/disburseRequest Parameters
| Parameter | Tipe | Wajib | Deskripsi |
|---|---|---|---|
| partnerReferenceNo | string | Wajib | Nomor referensi unik dari sistem fintech. Maks 64 karakter. Digunakan untuk idempotency check. |
| beneficiaryAccountNo | string | Wajib | Nomor rekening tujuan penerima dana. Harus rekening aktif di Bank ABC. |
| beneficiaryBankCode | string | Wajib | Kode bank tujuan format SNAP BI. Gunakan "008" untuk Bank ABC. |
| amount.value | string | Wajib | Jumlah transfer dalam string desimal. Format: "100000.00". Minimal IDR 10.000. |
| amount.currency | string | Wajib | Kode mata uang. Saat ini hanya mendukung "IDR". |
| remark | string | Opsional | Keterangan transfer yang tercetak di rekening koran penerima. Maks 40 karakter. |
| callbackUrl | string | Opsional | Override URL callback untuk transaksi ini. Jika kosong, menggunakan URL callback terdaftar di credential. |
Contoh Request
curl -X POST https://api-sandbox.bankabc.co.id/snap/v1.0/va/disburse \
-H "Authorization: Bearer {access_token}" \
-H "Content-Type: application/json" \
-H "X-TIMESTAMP: 2026-05-20T12:00:00+07:00" \
-H "X-SIGNATURE: {rsa_signature}" \
-H "X-PARTNER-ID: your_partner_id" \
-d '{
"partnerReferenceNo": "TRF-2026-001",
"beneficiaryAccountNo": "1234567890",
"beneficiaryBankCode": "008",
"amount": { "value": "500000.00", "currency": "IDR" },
"remark": "Pencairan pinjaman TRF-001"
}'HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api-sandbox.bankabc.co.id/snap/v1.0/va/disburse"))
.header("Authorization", "Bearer " + accessToken)
.header("Content-Type", "application/json")
.header("X-TIMESTAMP", timestamp).header("X-SIGNATURE", signature)
.POST(HttpRequest.BodyPublishers.ofString("""
{"partnerReferenceNo":"TRF-2026-001","beneficiaryAccountNo":"1234567890",
"beneficiaryBankCode":"008","amount":{"value":"500000.00","currency":"IDR"},
"remark":"Pencairan pinjaman TRF-001"}"""))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());import requests
response = requests.post(
"https://api-sandbox.bankabc.co.id/snap/v1.0/va/disburse",
headers={
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json",
"X-TIMESTAMP": timestamp, "X-SIGNATURE": signature
},
json={
"partnerReferenceNo": "TRF-2026-001",
"beneficiaryAccountNo": "1234567890",
"beneficiaryBankCode": "008",
"amount": {"value": "500000.00", "currency": "IDR"},
"remark": "Pencairan pinjaman TRF-001"
}
)
print(response.json())const data = await fetch(
'https://api-sandbox.bankabc.co.id/snap/v1.0/va/disburse',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
'X-TIMESTAMP': timestamp, 'X-SIGNATURE': signature
},
body: JSON.stringify({
partnerReferenceNo: 'TRF-2026-001',
beneficiaryAccountNo: '1234567890',
beneficiaryBankCode: '008',
amount: { value: '500000.00', currency: 'IDR' },
remark: 'Pencairan pinjaman TRF-001'
})
}
).then(r => r.json());Response & Error Codes
| Response Code | HTTP | Deskripsi | Tindakan |
|---|---|---|---|
| 2002900 | 200 | Transaksi berhasil diproses | Simpan responseId untuk rekonsiliasi |
| 4002901 | 400 | Saldo tidak mencukupi | Periksa saldo rekening giro fintech |
| 4002902 | 400 | Rekening tujuan tidak ditemukan | Validasi nomor rekening dan kode bank |
| 4012900 | 401 | Access token tidak valid atau kedaluwarsa | Refresh access token dan ulangi request |
| 4092900 | 409 | partnerReferenceNo sudah diproses | Gunakan ID unik baru; request idempoten |
| 5002900 | 500 | Kesalahan internal Bank ABC | Retry setelah 30 detik; hubungi support jika berlanjut |
| 5042900 | 504 | Timeout: tidak ada respons dari CBS | Jangan retry langsung; cek status via GET /va/status |