Referensi API
Terima pembayaran QRIS dan USDT lewat satu REST API. Transaksi dibuat dengan status pending dan baru menjadi paid setelah pembayaran dikonfirmasi server-to-server. Pembayaran sandbox bukan uang sungguhan: Anda sendiri yang memilih hasilnya.
Buat API key
Buat key sandbox (pw_test_…) di menu API Key dan kirim sebagai Bearer token.
Buat pembayaran
POST /api/v1/transactions dengan ID order dan nominal Anda, lalu tampilkan QR code atau buka checkout_url.
Konfirmasi lewat webhook
Proses order saat webhook payment.paid yang bertanda tangan sampai di server Anda.
Setiap request, kecuali endpoint webhook provider, memerlukan API key. Buat di dashboard Anda pada menu API Key.
Authorization: Bearer pw_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
429 RATE_LIMITED. Setiap respons, berhasil maupun error, menyertakan header X-Request-Id yang juga tampil di baris yang sesuai pada Log API Anda.403 IP_NOT_ALLOWED, dan Anda akan diberi tahu.Setiap API key dimiliki oleh tepat satu environment, yang terlihat langsung dari prefiksnya:
pw_test_…
Transaksi yang dibuat dengan key sandbox ditandai sandbox dan tidak pernah muncul di laporan live atau tampilan dashboard default Anda. Untuk menyelesaikan pembayaran sandbox, buka checkout_url-nya lalu pilih Berhasil dibayar, Gagal, atau Kedaluwarsa: webhook Anda menerima event yang sama seperti pembayaran live.
pw_live_…
Transaksi dengan key live adalah transaksi sungguhan dan masuk ke statistik dashboard, laporan, dan settlement Anda.
Setiap respons memakai salah satu dari dua format ini.
{
"success": true,
"data": {
"…": "…"
}
}
{
"success": false,
"error": {
"code": "INVALID_API_KEY",
"message": "Invalid API credentials."
}
}
| HTTP | Kode | Arti |
|---|---|---|
| 401 | INVALID_API_KEY | API key tidak ada, tidak valid, atau tidak dikenali |
| 401 | API_KEY_REVOKED | Kunci telah dicabut dari dashboard |
| 403 | IP_NOT_ALLOWED | API key memiliki daftar IP yang diizinkan dan request datang dari IP lain |
| 403 | MERCHANT_INACTIVE | Akun merchant sedang ditangguhkan |
| 404 | NOT_FOUND | Resource tidak ada, atau milik merchant lain |
| 405 | METHOD_NOT_ALLOWED | Endpoint tidak menerima metode HTTP ini |
| 409 | DUPLICATE_REFERENCE | merchant_reference yang sama digunakan ulang dengan jumlah/metode berbeda |
| 422 | VALIDATION_ERROR | Isi request gagal divalidasi |
| 422 | RETURN_URL_NOT_ALLOWED | return_url bukan https, atau tidak berada di salah satu website aktif Anda |
| 422 | WEBSITE_NOT_FOUND | website bukan salah satu website aktif Anda |
| 429 | RATE_LIMITED | Terlalu banyak request |
| 502 | PROVIDER_ERROR | QRIS atau USDT live: provider menolak atau mengirim respons tidak valid; transaksi ditandai gagal |
| 503 | PROVIDER_NOT_CONNECTED | QRIS atau USDT live: provider metode tersebut belum terhubung, jadi pembayaran tidak bisa dibuat |
| 504 | PROVIDER_TIMEOUT | QRIS atau USDT live: provider tidak merespons tepat waktu; transaksi ditandai gagal |
Pembayaran
| Field | Catatan |
|---|---|
| merchant_reference string · wajib | ID pesanan Anda sendiri. Sekaligus berfungsi sebagai idempotency key. |
| amount number · wajib | QRIS: rupiah bulat, 1.000–10.000.000 IDR. USDT: minimal 1, maksimal 2 desimal |
| payment_method string · wajib | Hanya QRIS (IDR) atau USDT (BEP20) |
| customer_id string · wajib | Wajib (maks. 100). ID pelanggan dari sistem Anda: user ID, username, atau email. Tampil di dashboard, ekspor, respons API, dan webhook, sehingga Anda tahu siapa yang membayar. Juga diteruskan ke provider pembayaran sebagai label pelanggan, kecuali mengandung "@" (email tidak pernah dikirim). |
| currency string · opsional | Opsional. Harus sesuai metode: IDR untuk QRIS, USDT untuk USDT. Disimpan apa adanya, tanpa konversi. |
| network string · opsional | Hanya USDT, wajib: BEP20. TRC20/ERC20 ditolak. Kosongkan untuk QRIS. |
| customer_name string · opsional | Opsional (maks. 50), semua metode. Nama pembayar, tampil di dashboard Anda. Diteruskan ke provider sebagai pengganti customer_id jika customer_id berupa email. |
| return_url string · opsional | Opsional. Menggantikan URL kembali milik website untuk pembayaran ini. https, di salah satu website aktif Anda (Dashboard → Website & Webhook). |
| website string · opsional | Opsional. Domain salah satu website Anda (mis. toko.contoh.com); URL kembalinya yang dipakai. Kosongkan keduanya untuk memakai website default. Domain mirror dihitung sebagai website-nya: URL kembali dan webhook URL di domain website ikut pindah ke mirror itu. |
| expires_in integer · opsional | Opsional, khusus QRIS. Berapa lama kode QR bisa dibayar, dalam detik: 60 sampai 1.200 (default). |
{
"merchant_reference": "ORDER-1042",
"amount": 250000,
"currency": "IDR",
"payment_method": "QRIS",
"customer_id": "user-1042",
"customer_name": "Budi Santoso"
}
{
"merchant_reference": "ORDER-1043",
"amount": 100,
"currency": "USDT",
"payment_method": "USDT",
"network": "BEP20",
"customer_id": "user-1043"
}
{
"success": true,
"data": {
"reference": "PW20260921143022AB3F",
"merchant_reference": "ORDER-1042",
"payment_method": "QRIS",
"environment": "sandbox",
"customer_id": "user-1042",
"customer_name": "Budi Santoso",
"amount": 250000,
"fee_bearer": "merchant",
"currency": "IDR",
"network": null,
"status": "pending",
"created_at": "2026-09-21T14:30:22+00:00",
"paid_at": null,
"qr_string": "SANDBOX-QRIS-PW20260921143022AB3F-NOT-PAYABLE",
"pay_address": null,
"pay_amount": 250000,
"expires_at": "2026-09-21T14:50:22+00:00",
"checkout_url": "https://checkout.paywise.asia/Xk7p2QaZ9mRt"
}
}
USDT: tampilkan ke pelanggan pay_address (alamat BEP20) dan pay_amount, yaitu jumlah USDT persis yang harus dikirim. pay_amount adalah amount ditambah biaya jaringan dan pemrosesan yang dibayar pelanggan, sehingga Anda menerima amount penuh. Alamat berlaku 60 menit (expires_at); setoran yang datang terlambat tetap dikonfirmasi. Pembayaran yang kurang dari pay_amount tidak ditandai lunas.
Siapa yang menanggung fee transaksi diatur per website di Dashboard → Website & Webhook. Dengan fee_bearer customer, customer membayar pay_amount (jumlah + fee: tampilkan QR string atau angka ini) dan Anda menerima tepat amount; webhook dan dashboard Anda menampilkan amount. Beri tahu customer Anda bahwa harga sudah termasuk biaya layanan. Selain itu, untuk QRIS pay_amount sama dengan amount. Perubahan hanya berlaku untuk transaksi baru.
merchant_reference serta jumlah/metode yang sama akan mengembalikan transaksi asli dengan 200 OK alih-alih membuat duplikat. Menggunakan ulang referensi dengan jumlah atau metode berbeda akan mengembalikan 409 DUPLICATE_REFERENCE. Key sandbox dan live terpisah: merchant_reference yang sama dapat dipakai sekali di masing-masing, dan sebuah key tidak pernah melihat transaksi environment lainnya.Aktifkan halaman pembayaran untuk sebuah website di Dashboard → Website & Webhook. Transaksi untuk website itu (disebut di website, cocok dengan return_url, atau website default Anda) disertai checkout_url (selain itu null): halaman yang di-host PAYWISE yang menampilkan kode QR (QRIS) atau alamat deposit dan jumlah pastinya (USDT), hitung mundur, dan status pembayaran yang diperbarui otomatis. Arahkan pelanggan ke sana, atau buka di tab baru. Anda tetap bisa menampilkan qr_string atau pay_address sendiri.
Setelah pembayaran berhasil, kedaluwarsa, atau gagal, halaman mengembalikan pelanggan ke URL kembali yang Anda atur untuk website di Dashboard → Website & Webhook (website default, atau yang disebut di website). Kirim return_url untuk menggantinya pada satu pembayaran: harus https dan di salah satu domain tersebut (atau subdomainnya), selain itu 422 RETURN_URL_NOT_ALLOWED. PAYWISE menambahkan hasilnya ke URL tersebut:
https://shop.example.com/thanks?reference=PW20260921143022AB3F&merchant_reference=ORDER-1042&status=paid
status di URL itu hanya untuk pesan di halaman Anda. Siapa pun bisa mengetiknya, jadi jangan pernah memproses pesanan berdasarkan nilai itu: tunggu webhook payment.paid atau periksa dengan GET /api/v1/transactions/{reference}.{reference} adalah referensi PAYWISE yang dikembalikan saat transaksi dibuat, bukan merchant_reference milik Anda.
404 NOT_FOUND, bukan 403, agar keberadaan referensi itu tidak terungkap.Transaksi Anda di environment key tersebut, terbaru lebih dulu: 20 per halaman, hingga 100 dengan per_page. Semua filter opsional dan dapat digabungkan. Setiap item adalah objek yang sama dengan yang dikembalikan GET /api/v1/transactions/{reference}.
| Field | Catatan |
|---|---|
| status | pending, paid, failed, atau expired. |
| payment_method | QRIS atau USDT. |
| date_from | YYYY-MM-DD. Hari pertama (UTC+7) transaksi dibuat. |
| date_to | YYYY-MM-DD. Hari terakhir (UTC+7), termasuk hari itu. |
| merchant_reference | Referensi pesanan Anda, harus sama persis. |
| customer_id | ID pelanggan Anda, harus sama persis. |
| per_page | 1–100, default 20. |
| page | Nomor halaman, default 1. |
{
"success": true,
"data": [
{
"reference": "PW20260921143022AB3F",
"merchant_reference": "ORDER-1042",
"payment_method": "QRIS",
"status": "paid",
"amount": 250000,
"currency": "IDR",
"…": "…"
}
],
"meta": {
"page": 1,
"per_page": 20,
"total": 1,
"last_page": 1
}
}
meta berisi halaman saat ini, ukuran halaman, jumlah total transaksi yang cocok, dan halaman terakhir.
Nilai yang sama digunakan secara konsisten di database, API ini, dashboard merchant, dan dashboard admin.
Penarikan
Ajukan penarikan dana yang sudah settle langsung dari server Anda: sama dengan Dashboard → Penarikan, dengan minimum, maksimum, biaya, dana tersedia, dan payout otomatis yang sama. Hanya key live yang bisa mengajukan (key sandbox mendapat 403 LIVE_KEY_REQUIRED). Tidak ada kode email, jadi key live saja sudah cukup untuk mengizinkan payout. Simpan key di server dan pertimbangkan daftar IP yang diizinkan di halaman API Key.
amount adalah nominal yang diterima di tujuan. Biaya penarikan (Rp3.000 untuk QRIS, 1.00 USDT untuk USDT) ditambahkan di atasnya dan diambil dari dana tersedia; respons menampilkan amount (yang diambil), fee, dan payout_amount (yang dikirim). Batas per penarikan: Rp25.000 – Rp20.000.000 untuk QRIS, 10.00 USDT – 10,000.00 USDT untuk USDT.
| Field | Catatan |
|---|---|
| payment_method | Wajib. Dana mana yang ditarik: QRIS (dibayarkan ke rekening bank dalam IDR) atau USDT (dikirim ke wallet BEP20). |
| amount | Wajib. Nominal yang diterima di tujuan, dalam mata uang metode pembayaran (maksimal 2 desimal). |
| bank_code | Khusus QRIS, wajib. Kode dari daftar di bawah: 3 digit untuk bank, atau DANA, OVO, GOPAY, SHOPEEPAY untuk e-wallet (account_number berupa nomor HP 08…). E-wallet maksimal Rp10.000.000 per penarikan (tanpa partial withdraw) dan tidak dicek nama pemiliknya: nomor yang salah tetap dibayar. |
| account_number | Khusus QRIS, wajib. 5 sampai 30 digit. |
| wallet_address | Khusus USDT, wajib. Alamat BEP20: 0x diikuti 40 karakter hex. |
| network | Khusus USDT, wajib: BEP20. |
200, jadi request yang timeout aman diulang. Key yang sama dengan nominal, metode, atau tujuan berbeda menghasilkan 409 DUPLICATE_REQUEST.curl -X POST https://paywise.asia/api/v1/withdrawals \
-H "Authorization: Bearer pw_live_…" \
-H "Idempotency-Key: payout-2026-09-27-001" \
-H "Content-Type: application/json" \
-d '{"payment_method":"QRIS","amount":1500000,"bank_code":"014","account_number":"1234567890"}'
{
"success": true,
"data": {
"reference": "PWD20260927090112C4DQ",
"payment_method": "QRIS",
"environment": "live",
"payout_method": "bank_transfer",
"currency": "IDR",
"network": null,
"amount": 1503000,
"fee": 3000,
"payout_amount": 1500000,
"status": "requested",
"destination": {
"bank_code": "014",
"bank_name": "BCA",
"account_number": "1234567890"
},
"reason": null,
"requested_at": "2026-09-27T02:01:12+00:00",
"completed_at": null,
"closed_at": null
}
}
422 INSUFFICIENT_FUNDS berarti nominal ditambah biaya melebihi dana metode tersebut yang sudah settle dan belum ditarik; error.available adalah nominal terbesar yang bisa diajukan sekarang. Dana QRIS settle dalam beberapa batch per hari; dana USDT settle saat dibayar.
Penarikan dimulai sebagai requested lalu melewati approved dan processing hingga completed, atau berakhir failed atau rejected (dengan reason). Pantau lewat webhook withdrawal.* atau endpoint di bawah.
Penarikan Anda di environment key, terbaru dulu, dengan paging dan meta yang sama seperti daftar transaksi. Filter (semua opsional): status (requested, approved, processing, completed, failed, rejected), payment_method, date_from dan date_to (YYYY-MM-DD, UTC+7).
{reference} adalah referensi PWD… yang dikembalikan saat penarikan diajukan. Penarikan merchant lain, atau dari environment lain, menghasilkan 404 NOT_FOUND.
Dana Anda per metode pembayaran di environment key, seperti di halaman Penarikan: yang bisa ditarik sekarang, yang menunggu batch settlement berikutnya, nominal terbesar untuk satu penarikan saat ini (max_withdrawal), serta batas dan biaya tiap penarikan.
{
"success": true,
"data": {
"environment": "live",
"methods": {
"QRIS": {
"currency": "IDR",
"available": 1250000,
"awaiting_settlement": 480000,
"next_settlement_at": "2026-09-28T08:00:00+00:00",
"next_settlement_amount": 480000,
"max_withdrawal": 1245000,
"withdrawal": {
"min": 25000,
"max": 20000000,
"fee": 5000
}
},
"USDT": {
"…": "…"
}
}
}
}
Webhook
Konfigurasikan URL webhook dan event dari Dashboard → Website & Webhook. Saat status transaksi berubah menjadi event yang Anda langgani, PAYWISE mengirim:
POST <your webhook_url> Content-Type: application/json X-PAYWISE-Signature: <hex-encoded HMAC-SHA256>
HMAC-SHA256(raw_json_body, your_webhook_secret) (secret ditampilkan di halaman Website & Webhook; satu secret untuk semua webhook) lalu bandingkan dengan header X-PAYWISE-Signature. Event: payment.paid · payment.failed · payment.expired.
Webhook dikirim dari 217.217.253.90 · 2407:3640:2358:7339::1. Jika firewall Anda hanya menerima alamat tertentu, izinkan alamat ini; tetap verifikasi tanda tangan di setiap kiriman. Perubahan daftar ini diumumkan terlebih dahulu.
Punya beberapa website di server berbeda? Beri sebuah website webhook URL sendiri di Dashboard → Website & Webhook. Pembayaran untuk website itu (yang disebut di website, cocok dengan return_url, atau website default) lalu dikirim ke sana; selebihnya tetap ke webhook URL utama Anda. Semuanya ditandatangani dengan secret yang sama. Website yang sebelumnya sudah punya secret sendiri tetap memakainya sampai Anda memindahkannya ke secret utama di halaman itu.
Setiap percobaan pengiriman dicatat di halaman Website & Webhook: event, nomor percobaan, status HTTP asli dari endpoint Anda (kosong jika timeout) dan hingga 2 KB isi responsnya. Pengiriman yang gagal dicoba ulang otomatis, dan Anda juga bisa mengirim ulang dari halaman transaksi.
Event penarikan (withdrawal.completed · withdrawal.failed · withdrawal.rejected) dikirim ke URL webhook utama Anda saat penarikan selesai, gagal, atau ditolak. Nominal yang gagal atau ditolak bisa ditarik lagi. Aktifkan di halaman Website & Webhook. reason berisi alasan gagal atau ditolak, dan null jika selesai.
{
"event": "withdrawal.completed",
"data": {
"reference": "PWD20260925090112C4DQ",
"payment_method": "QRIS",
"environment": "live",
"payout_method": "bank_transfer",
"currency": "IDR",
"network": null,
"amount": 1500000,
"fee": 5000,
"payout_amount": 1495000,
"status": "completed",
"reason": null,
"requested_at": "2026-09-25T02:01:12+00:00",
"completed_at": "2026-09-25T02:03:40+00:00",
"closed_at": null
}
}
Dipakai oleh jaringan pembayaran PAYWISE, bukan oleh merchant. Setiap notifikasi diautentikasi, dicocokkan ke satu transaksi live, lalu dikonfirmasi server-to-server sebelum pembayaran ditandai lunas. Metode yang belum tersedia mengembalikan 503 PROVIDER_NOT_CONNECTED.
Biasanya membalas dalam 1 menit