FERDIPAY API

Integrasi pembayaran untuk semua produk digital.

FerdiPay bisa dipakai oleh website, aplikasi mobile, toko digital, SaaS, POS, order form, aplikasi komunitas, sistem internal, dan workflow backend apa pun yang membutuhkan payment link, pencatatan saldo, transaksi, payout, dan rekonsiliasi.

Konsep utama

Satu account USER memiliki satu wallet. Di dalam account itu Anda bisa membuat banyak integrasi. Setiap integrasi mewakili aplikasi atau channel server-side: website checkout, aplikasi mobile melalui backend, POS, Discord, WhatsApp order, kasir internal, atau sistem order.

AccountIdentitas finansial, pemilik wallet, destination payout, VIP, dan session dashboard.
Integration keyAPI key server-side dengan prefix fs_test_ atau fs_live_. Full key hanya tampil sekali.
PaymentIntent pembayaran bernominal Rupiah yang menghasilkan reference dan payment URL.
LedgerSumber saldo immutable. Saldo dihitung dari entry ledger, bukan dari cache UI.

Autentikasi

Ada dua jenis akses: session dashboard untuk operasi browser dan Bearer API key untuk integrasi server-side.

JenisDipakai untukHeader wajib
Session cookieLogin, dashboard, buat key, destination, withdrawal, adminOrigin: PUBLIC_ORIGIN untuk POST
Bearer API keyCreate payment, cek payment, balance, transaksi integrasiAuthorization: Bearer fs_live_...
Webhook providerSettlement payment dari providerSignature provider, bukan API key integrasi

Simpan API key hanya di backend. Jangan taruh key di browser, aplikasi mobile client-side, repository publik, log, atau pesan customer.

Quickstart

  1. Daftar atau login ke dashboard.
  2. Buka menu Integrasi & API.
  3. Buat aplikasi/channel, misalnya Website Toko, Mobile App, POS, Backend Order, atau nama produk.
  4. Terbitkan API key live untuk production atau test untuk sandbox jika deployment mendukungnya.
  5. Dari backend Anda, buat payment dengan nominal dan Idempotency-Key unik per order.
  6. Simpan reference FerdiPay di database Anda.
  7. Arahkan customer ke payment_url, lalu cek status melalui API atau tunggu webhook provider diproses FerdiPay.
curl -X POST https://domain-anda.com/api/v1/payments \
  -H 'Authorization: Bearer fs_live_xxx' \
  -H 'Idempotency-Key: order-INV-2026-0001' \
  -H 'Content-Type: application/json' \
  -d '{"amount_rupiah":10000}'

Ringkasan endpoint

EndpointAksesFungsi
POST /api/v1/paymentsBearer keyMembuat payment baru.
GET /api/v1/payments/{reference}Bearer keyMengambil status payment milik key tersebut.
GET /api/v1/balanceBearer keySaldo wallet account integrasi.
GET /api/v1/transactionsBearer keyDaftar payment milik integrasi, pagination limit/offset.
GET /payment-methodsSessionMetode payment yang aktif/nonaktif untuk user.
GET /payout-capabilitiesSessionStatus provider payout dan daftar bank/e-wallet.
GET /walletSessionSaldo wallet dashboard.
GET /wallet/ledgerSessionRiwayat ledger account.
POST /payout-destinationsSessionMendaftarkan rekening bank atau e-wallet.
POST /withdrawalsSessionMengajukan penarikan saldo.
POST /api/v1/webhooks/{mock|doku}ProviderWebhook settlement dari provider aktif.

Payment API

Body create payment hanya menerima amount_rupiah integer positif. Field tambahan ditolak. Nominal maksimum mengikuti konfigurasi deployment.

POST /api/v1/payments
Authorization: Bearer <PAYMENT_API_KEY>
Idempotency-Key: order-123
Content-Type: application/json

{"amount_rupiah":10000}
{
  "reference": "fsp_abc123",
  "status": "PENDING",
  "provider_state": "READY",
  "gross_rupiah": 10000,
  "provider_fee_rupiah": 70,
  "platform_fee_rupiah": 500,
  "net_account_rupiah": 9430,
  "payment_url": "https://provider.example/pay/fsp_abc123",
  "created_at": "2026-09-14T12:00:00Z",
  "paid_at": null
}

Gunakan Idempotency-Key yang sama saat retry order yang sama. Jika key sama dikirim dengan nominal berbeda, API mengembalikan 409.

StatusArti
PENDINGPayment dibuat dan menunggu pembayaran.
PAIDProvider mengonfirmasi sukses dan saldo sudah dikreditkan.
FAILED / EXPIREDProvider menyatakan gagal atau kedaluwarsa.
REFUNDEDRefund internal dicatat melalui reversal ledger.

Metode payment

Pembayaran user hanya tersedia melalui QRIS. Owner dapat mengaktifkan atau menonaktifkan QRIS dari dashboard Owner > Payment. User dapat melihat status metode dari menu Metode Pembayaran atau endpoint session GET /payment-methods.

GET /payment-methods
[
  {"method_code":"qris","label":"QRIS DOKU","enabled":true}
]

Jika QRIS dimatikan, request POST /api/v1/payments untuk payment baru akan ditolak. Payment yang sudah dibuat sebelumnya tetap mengikuti status provider masing-masing.

Virtual account, transfer bank, e-wallet langsung, dan kartu tidak tersedia sebagai metode pembayaran user.

Balance dan transaksi

GET /api/v1/balance
Authorization: Bearer <PAYMENT_API_KEY>
{
  "wallet_id": "uuid",
  "account_id": "uuid",
  "kind": "ACCOUNT",
  "balance_rupiah": 1250000
}
GET /api/v1/transactions?limit=50&offset=0
Authorization: Bearer <PAYMENT_API_KEY>

limit bernilai 1 sampai 100. offset dimulai dari 0.

Payout, destination, dan VIP

Payout dikelola memakai session dashboard agar rekening/e-wallet tujuan dan withdrawal tetap berada di bawah account yang login. POST wajib membawa header Origin sesuai konfigurasi.

Sebelum menampilkan tombol validasi atau tarik saldo, dashboard membaca GET /payout-capabilities. Jika provider payout production belum aktif, UI mengunci validasi dan penarikan agar tidak terlihat seolah dana pasti terkirim.

GET /payout-capabilities
{
  "provider": "unavailable",
  "available": false,
  "institutions": [
    {"kind":"BANK","institution_code":"014","label":"Bank BCA"},
    {"kind":"BANK","institution_code":"008","label":"Bank Mandiri"},
    {"kind":"EWALLET","institution_code":"DANA","label":"DANA"}
  ]
}
EndpointBody
GET /payout-capabilitiesStatus provider payout dan daftar institusi.
POST /payout-destinationskind BANK/EWALLET, institution_code dari daftar resmi, destination_number
POST /payout-destinations/{id}/validateTidak perlu body; hanya berjalan jika provider tersedia.
POST /withdrawalsdestination_id, mode, amount_rupiah jika RECEIVE_EXACT
GET /withdrawals100 penarikan terbaru
GET /vipStatus VIP, harga, durasi
POST /vip/purchaseHeader Idempotency-Key; body {"payment_method":"WALLET"} untuk potong saldo dan aktivasi langsung, atau {"payment_method":"QR_OWNER_MANUAL"} untuk QR owner dan pemeriksaan manual
POST /payout-destinations
Origin: https://domain-anda.com
Content-Type: application/json

{"kind":"BANK","institution_code":"014","destination_number":"1234567890"}
{
  "destination_id": "uuid",
  "mode": "RECEIVE_EXACT",
  "amount_rupiah": 50000
}

Mode WITHDRAW_ALL tidak menerima amount_rupiah. Server menghitung saldo terbaru, fee, dan total debit. Batas penerimaan Rp50.000–Rp1.000.000 per transaksi berlaku untuk semua user termasuk VIP. WITHDRAW_ALL ditolak jika melebihi maksimum; gunakan RECEIVE_EXACT. Satu akun hanya boleh memiliki satu rekening/e-wallet. Nama pemilik harus terverifikasi oleh provider dan tidak digunakan akun lain sebelum penarikan diterima.

Webhook settlement

Webhook FerdiPay adalah endpoint untuk provider payment aktif, bukan webhook yang dipanggil langsung oleh aplikasi merchant. Provider mengirim event ke /api/v1/webhooks/{provider_name}, FerdiPay memverifikasi signature, lalu mengunci payment dan mencatat ledger secara atomik.

Duplicate event tidak mengkredit saldo dua kali. Event sukses terlambat dapat memperbaiki payment FAILED/EXPIRED jika provider menyatakan sukses. Failure terlambat tidak membatalkan payment yang sudah PAID.

ProviderEndpoint
MockPOST /api/v1/webhooks/mock
DOKUPOST /api/v1/webhooks/doku

Owner dan operasional

Endpoint admin hanya untuk account OWNER dan memakai session dashboard. Gunakan untuk audit internal, pengaturan metode payment, pencarian user, dan rekonsiliasi. Endpoint admin bukan untuk integrasi publik.

EndpointFungsi
GET /admin/summaryRingkasan realtime total transaksi, volume, fee, merchant, dan withdrawal.
GET /admin/payment-methodsDaftar metode payment dan status aktif/nonaktif.
POST /admin/payment-methods/{method_code}Aktif/nonaktifkan metode payment untuk user.
GET /admin/usersCari user, filter aktif/tidak aktif, saldo, rekening terdaftar.
GET /admin/accountsDaftar account dan saldo.
GET /admin/paymentsSeluruh payment platform.
GET /admin/transactionsLedger semua wallet, opsional filter account_id.
GET /admin/payoutsDaftar withdrawal account.
POST /admin/reconciliationMemeriksa kecocokan dana provider, saldo user, dan entitlement developer.
POST /admin/adjustmentsKoreksi transfer antar wallet dengan ledger debit/kredit.
GET /admin/auditAudit log operasional.

Blokir/hapus akun belum diaktifkan karena data finansial dan ledger harus dipertahankan untuk audit. Jika dibutuhkan, gunakan status akun/suspension melalui migration terpisah agar tidak menghapus riwayat transaksi.

Error, keamanan, dan praktik terbaik

KodeUmum terjadi saat
401Session tidak valid atau Bearer API key salah/revoked.
403Origin tidak sesuai atau akses OWNER diperlukan.
404Resource bukan milik account/key pemanggil atau tidak ditemukan.
409Konflik idempotency, duplicate destination, saldo tidak cukup, QRIS sedang nonaktif, destination belum valid, atau state konflik.
422Payload tidak valid, field tambahan, nominal salah, environment key tidak cocok, atau institution_code tidak tersedia.
429Cooldown/kuota validasi destination; baca header Retry-After.
503Provider payout belum tersedia atau provider eksternal belum siap.

Selalu buat Idempotency-Key stabil per order, simpan reference FerdiPay di database Anda, lakukan retry aman pada timeout, dan tampilkan status final hanya setelah PAID, FAILED, EXPIRED, atau REFUNDED.

API key hanya boleh berada di backend. Jangan simpan key di localStorage, aplikasi mobile client-side, repository publik, log, pesan customer, atau frontend JavaScript. Regenerate key jika ada indikasi bocor, lalu revoke key lama dari dashboard.