AKD Pay Docs
Bahasa IndonesiaID Dashboard
LIVE This documentation applies to both sandbox and live.

API reference

Payments

Create a QRIS or Virtual Account payment, read its status, and retry requests safely.

In short: POST /v1/payments with an Idempotency-Key header creates a payment and answers 200 with payment_id, status (PENDING), expires_at, and checkout (qr_string for QRIS, account_number for Virtual Account). Unknown body fields are rejected. GET /v1/payments/{payment_id} returns the same shape and is the source of truth when a webhook is late. Repeating a request with the same key and body returns the same payment; the same key with a different body is answered 409.

§4 Membuat pembayaran#

POST /v1/payments
Authorization: Bearer <api_key>
Idempotency-Key: order-10023-attempt-1
Content-Type: application/json
{
  "project_id": "8f1c2d3e-4a5b-6c7d-8e9f-0a1b2c3d4e5f",
  "external_order_id": "ORDER-10023",
  "amount": 150000,
  "currency": "IDR",
  "payment_method": "QRIS",
  "metadata": { "customer_id": "C-77" },
  "return_url": "https://shop.example.com/orders/ORDER-10023"
}
Field Wajib Keterangan
project_id ya project milik merchant Anda
external_order_id ya ID pesanan Anda; unik per project. Jangan dipakai ulang untuk pesanan lain
amount ya IDR, bilangan bulat > 0, minimal sesuai metode
currency ya hanya IDR
payment_method ya QRIS atau VIRTUAL_ACCOUNT
metadata tidak objek JSON bebas untuk Anda; ikut dihitung dalam idempotensi
return_url tidak URL https:// untuk kanal yang mengarahkan pembeli kembali
location tidak request_country, customer_country, country_source, timezone untuk analitik

Body dibaca ketat: field yang tidak dikenal ditolak 400 invalid request body.

Respons 200:

{
  "payment_id": "2b8f6c1e-0d5a-4c1b-9f3e-7a6d5c4b3a21",
  "external_order_id": "ORDER-10023",
  "status": "PENDING",
  "amount": 150000,
  "currency": "IDR",
  "payment_method": "QRIS",
  "expires_at": "2026-11-01T03:30:00Z",
  "checkout": {
    "type": "QRIS",
    "qr_string": "00020101021226…"
  },
  "refunded_amount": 0,
  "refund_status": "NONE"
}
  • Untuk VIRTUAL_ACCOUNT, checkout berisi {"type":"VIRTUAL_ACCOUNT","account_number":"…"}.
  • payment_url hanya ada di sandbox (halaman bayar AKD). Di live, tampilkan checkout di aplikasi Anda.
  • expires_at mengikuti masa berlaku pembayaran (saat ini 30 menit). Setelah lewat, pembayaran menjadi EXPIRED dan Anda menerima payment.expired.
  • Simpan payment_id; semua webhook dan pembacaan status memakainya.
  • refunded_amount (total refund yang berhasil) dan refund_status (NONE, PARTIAL, FULL) ada sejak v1.0.3. Refund tidak mengubah status; lihat payment.refunded di bagian 7.

Varian halaman bayar (hanya sandbox): POST /v1/hosted/payments dengan body dan header yang sama mengembalikan payment_url.

Simulasi di sandbox: POST /v1/payments/{payment_id}/simulate (tanpa body) meminta Xendit Test membayar pembayaran PENDING. Jawaban 202 {"status":"simulation_requested"}, atau 200 {"status":"already_paid"}. Webhook payment.paid menyusul beberapa detik kemudian.

§5 Membaca status pembayaran#

GET /v1/payments/{payment_id}
Authorization: Bearer <api_key>

Respons sama dengan pembuatan pembayaran. Pembayaran merchant lain dijawab 404. Gunakan ini bila webhook terlambat atau bila Anda ragu: webhook adalah sinyal, GET /v1/payments/{id} adalah kebenaran.

§10 Idempotensi#

  • Idempotency-Key wajib pada POST /v1/payments dan POST /v1/hosted/payments; tanpa header dijawab 400 missing Idempotency-Key.
  • Key berlaku per merchant. Request ulang dengan key dan body yang sama (project_id, external_order_id, amount, currency, payment_method, metadata, return_url) mengembalikan pembayaran yang sama, termasuk expires_at aslinya. Aman untuk retry setelah timeout.
  • Key yang sama dengan body berbeda dijawab 409 idempotency key conflicts with an existing payment.
  • Gunakan satu key per percobaan pembuatan pembayaran untuk satu pesanan, misalnya <order_id>-<nomor percobaan>. Untuk membuat pembayaran baru bagi pesanan yang sama (misalnya setelah EXPIRED), pakai external_order_id dan key baru.
  • Di sisi webhook, idempotensi Anda adalah deduplikasi X-AKD-Event-ID.