← Docs

Quickstart

Integrasi BITS Pay dalam 3 langkah: buat charge, tampilkan QRIS, konfirmasi pembayaran.

0. Dapatkan API key

Daftar di dashboard (panduan lengkap: Panduan Dashboard), buat aplikasi di workspace kamu. API key (sk_...) hanya ditampilkan sekali saat create/rotate — simpan di tempat aman. Semua request /v1/* pakai header:

Authorization: Bearer sk_xxxxxxxxxxxxxxxx

Base URL: https://api.pay.bits.co.id. Response sukses selalu { "success": true, "data": ... }, error { "success": false, "error": { "code", "message" } }.

1. Buat charge (QRIS dinamis)

1POST /v1/charges

Kirim order_id (unik per aplikasi, idempoten) dan amount (minimal Rp 100). API mengembalikan QRIS dinamis dengan kode unik: amount_due = amount + fee + unique_code (fee = biaya admin opsional, dikirim di request — default 0).

const res = await fetch('https://api.pay.bits.co.id/v1/charges', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer sk_xxxxxxxxxxxxxxxx',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    order_id: 'ORD-001',
    amount: 150000,
    description: 'Pembayaran invoice #001',
  }),
});
const { success, data, error } = await res.json();
if (!success) throw new Error(`${error.code}: ${error.message}`);

console.log(data.amount_due);  // 150001
console.log(data.qr_image);    // data:image/png;base64,...
console.log(data.expired_at);  // batas bayar, ISO-8601 UTC: "2026-09-02T12:45:00Z"

Tampilkan data.qr_image sebagai <img src> ke pelanggan. Pelanggan bayar nominal persis amount_due.

2. Cek status pembayaran

2GET /v1/payments/:id

Poll status transaksi, atau terima update real-time via webhook. Untuk rekonsiliasi massal pakai GET /v1/payments (filter order_id/status, paginated).

const res = await fetch(`https://api.pay.bits.co.id/v1/payments/${id}`, {
  headers: { Authorization: 'Bearer sk_xxxxxxxxxxxxxxxx' },
});
const { data } = await res.json();
// data.status: 'pending' | 'success' | 'failed' | 'expired' | 'pending_review'

3. Konfirmasi pembayaran

3POST /v1/payments/:id/confirm

Kirim multipart/form-data berisi amount (harus sama persis dengan amount_due) dan opsional proof_image (JPG/PNG, maks 5MB) untuk auto-confirm via OCR.

const form = new FormData();
form.append('amount', '150001');        // = amount_due
form.append('proof_image', fileInput.files[0]); // opsional

const res = await fetch(`https://api.pay.bits.co.id/v1/payments/${id}/confirm`, {
  method: 'POST',
  headers: { Authorization: 'Bearer sk_xxxxxxxxxxxxxxxx' },
  body: form,
});
const { data } = await res.json();
// Request valid SELALU HTTP 200 — cek data.status:
// 'success'        → auto_confirm (lunas)
// 'pending_review' → OCR confidence rendah, direview admin
// 'failed'         → nominal tidak cocok / bukti tidak disertakan

Error handling

Code HTTP Arti
validation_error 400 Body tidak valid (cek error.details)
unauthorized 401 API key salah / aplikasi nonaktif
not_found 404 Transaksi tidak ditemukan
duplicate_order 409 order_id sudah dipakai transaksi aktif
duplicate_hash 409 Bukti bayar sudah dipakai
expired 400 Transaksi kedaluwarsa
rate_limited 429 Rate limit / kuota tercapai
Rate limit per tier: Free 10 req/s, Premium 100 req/s. Cek header X-RateLimit-Limit, X-RateLimit-Remaining, dan X-RateLimit-Reset.