REST API native
API native adalah antarmuka REST milik blockwallets sendiri: invoice berharga sen AS, ref idempoten untuk setiap pesanan, akun deposit statis yang mencakup semua jaringan, dan webhook bertanda tangan HMAC-SHA256. API ini membuat tagihan yang sama di halaman pembayaran yang sama dengan API kompatibel Cryptomus, dengan biaya dan saldo yang sama.
Buat kunci Anda sendiri di dasbor pada “Developer › Integrasi & kunci”: satu kunci Live dan satu kunci Test beserta webhook signing secret-nya. Masing-masing hanya ditampilkan sekali; daftar hanya menampilkan awalannya. Jika akun Anda mengaktifkan verifikasi dua langkah, membuat atau merotasi kunci Live akan meminta kode. Belum punya akun merchant? Minta akses. Sudah memakai Cryptomus? Lihat API kompatibel Cryptomus (cara memilih).
Kunci dan permintaan
Base URL https://blockwallets.io. Permintaan dan respons berupa JSON. Setiap permintaan membawa:
Authorization: Bearer bw_live_…atauBearer bw_test_…: awalan menentukan mode, jadi kunci Test hanya melihat invoice Test dan berjalan di testnetContent-Type: application/jsonpada permintaanPOST- Simpan kunci hanya di server Anda, jangan pernah di halaman web atau aplikasi; kami hanya menyimpan hash-nya
Error mengembalikan status HTTP dan {"error": {"code": "…", "message": "…"}}: 400 invalid_request (field hilang atau formatnya salah), 401 unauthorized (kunci tidak ada, tidak dikenal, atau dinonaktifkan), 404 not_found, 409 conflict (permintaan bertentangan dengan status invoice saat ini), 422 currency_unsupported.
Endpoint
| Endpoint | Fungsinya |
|---|---|
GET /v1/networks | Jaringan yang bisa Anda terima saat ini pada mode kunci ini: minimum, konfirmasi, perkiraan waktu tiba, dan perkiraan biaya; koin berharga menyertakan kurs saat ini |
POST /v1/invoices | Membuat invoice (201), atau mengembalikan yang sudah ada untuk ref yang sama (200) |
GET /v1/invoices?ref=… | Mencari invoice berdasarkan ref Anda |
GET /v1/invoices/:id | Mencari invoice berdasarkan id |
POST /v1/invoices/:id/network | Memilih sendiri jaringan untuk invoice (halaman pembayaran white-label): mengembalikan address dan pay_amount untuk ditampilkan |
POST /v1/invoices/:id/close | Menutup invoice tertunda yang belum menerima transfer apa pun |
POST /v1/deposit-accounts | Membuka (201) atau mengambil (200) akun deposit satu pelanggan: alamat permanen di setiap jaringan |
GET /v1/deposit-accounts?customer_ref=… | Mencari akun deposit berdasarkan customer_ref |
GET /v1/deposit-accounts/:id | Mencari akun deposit berdasarkan id |
GET /v1/deposits | Menampilkan daftar deposit satu akun (account_id atau customer_ref, limit 1–200, default 50) |
GET /v1/deposits/:id | Mencari satu deposit |
GET /v1/events | Pengiriman webhook untuk satu invoice atau deposit (invoice_id atau deposit_id) |
POST /v1/events/:id/redeliver | Mengirim ulang webhook (202) |
Tambahkan ?probe=1 pada pencarian invoice atau akun deposit untuk memeriksa chain saat itu juga (paling banyak sekali per 10 detik); jika tidak, Anda mendapat status terbaru dari pemindai kami, yang memeriksa setiap menit.
Membuat invoice POST /v1/invoices
Panggil POST /v1/invoices saat pelanggan checkout dan arahkan mereka ke pay_url dalam respons.
curl -X POST https://blockwallets.io/v1/invoices \
-H "Authorization: Bearer $BW_KEY" -H "Content-Type: application/json" \
-d '{"ref":"order_1042","amount":4200,"title":"Order #1042",
"return_url":"https://shop.example/cart","success_url":"https://shop.example/thanks?order=1042",
"meta":{"user_id":42}}'| Field | Wajib | Deskripsi |
|---|---|---|
ref | Ya | Nomor pesanan Anda: 1–64 karakter berupa huruf, angka, dan _ . : -. Unik per mode; mengirim ref yang sama dengan field yang sama lagi mengembalikan invoice yang sama, dengan field berbeda mengembalikan 409 |
amount | Ya | Jumlah dalam sen AS sebagai bilangan bulat: 4200 = $42.00. Tidak di bawah minimum jaringan setelah jaringan dipilih |
title | Ya | Yang dilihat pelanggan di halaman pembayaran, maksimal 64 karakter |
return_url | Ya | Tujuan tombol “Kembali” di halaman pembayaran; harus berada di salah satu domain situs Anda |
success_url | Tidak | Tujuan pelanggan setelah membayar; defaultnya return_url |
network | Tidak | Pilih lebih dulu id jaringan dari tabel jaringan; kosongkan agar pelanggan memilih di halaman pembayaran |
customer_ref | Tidak | Id pelanggan Anda, maksimal 64 karakter, dikembalikan apa adanya |
lifetime | Tidak | Masa berlaku dalam detik, 600 – 43200, default 3600 |
amount_rule | Tidak | "any" = kreditkan berapa pun yang masuk (top-up): paid segera setelah terkonfirmasi. Kosongkan untuk memakai “Aturan jumlah pembayaran” di “Pengaturan › Aturan pembayaran & tarif” pada dasbor |
accuracy_percent | Tidak | Seberapa besar kekurangan bayar yang masih dianggap lunas, 0 – 5 (persen), default 0 |
subtract_percent | Tidak | Bagian biaya platform yang dibayar pelanggan, 0 – 100 (persen), ditambahkan ke pay_amount; kosongkan untuk memakai default dasbor |
payment_multiple | Tidak | Apakah pembayaran yang kurang boleh dilengkapi ke alamat yang sama, default dari dasbor (aktif kecuali Anda ubah); false: transfer pertama yang kurang berakhir sebagai wrong_amount |
meta | Tidak | Objek JSON apa pun hingga 2 KB, dikembalikan apa adanya dalam pencarian dan webhook |
currency | Tidak | Hanya USD (default); selain itu mengembalikan 422 |
Setiap URL harus berada di salah satu domain situs Anda (dasbor → “Developer › Integrasi & kunci”). Responsnya adalah objek invoice di bawah; network, address, dan pay_amount terisi setelah jaringan dipilih.
Objek invoice
Id diawali inv_. amount dalam sen AS; pay_amount dan paid_amount adalah jumlah koin sebagai string desimal pada jaringan yang dipilih.
{
"id": "inv_01J8…",
"ref": "order_1042",
"mode": "live",
"status": "pending",
"amount": 4200,
"currency": "USD",
"title": "Order #1042",
"meta": { "user_id": 42 },
"network": null,
"address": null,
"pay_amount": null,
"paid_amount": null,
"payments": [],
"pay_url": "https://blockwallets.io/pay/inv_01J8…",
"return_url": "https://shop.example/cart",
"success_url": "https://shop.example/thanks?order=1042",
"created_at": "2026-11-03T08:00:00.000Z",
"expires_at": "2026-11-03T09:00:00.000Z",
"paid_at": null,
"closed_at": null
}| status | Artinya | Yang perlu Anda lakukan |
|---|---|---|
pending | Menunggu pembayaran | — |
confirming | Transfer terlihat dan sedang dikonfirmasi, atau datang kurang dan masih bisa dilengkapi | — |
paid | Lunas | Kirim barang / kreditkan pesanan |
paid_over | Lunas, dan kelebihan bayar | Sama; kelebihannya ada di saldo Anda |
wrong_amount | Berakhir dengan jumlah kurang dari penuh (saat kedaluwarsa, atau pada transfer pertama yang kurang jika payment_multiple false) | Bisnis top-up bisa mengkreditkan yang masuk (paid_amount; koin berkurs juga punya paid_cents); toko meminta pelanggan membayar sisanya |
closed | Kedaluwarsa tanpa dana masuk, atau Anda menutupnya | — (dana yang masuk belakangan tetap dikreditkan dan diberitahukan) |
Field lain: pay_url (halaman pembayaran), payments (setiap transfer dengan txid, amount, confirmations, dan confirmed), expires_at, paid_at, closed_at; BTC, LTC, DOGE, BCH, dan koin native juga membawa rate (dolar AS per koin, dikunci 30 menit), rate_locked_until, dan paid_cents (yang sudah masuk, dalam sen AS).
Jaringan
Berikan id sebagai network. GET /v1/networks mengembalikan jaringan yang terbuka saat ini pada mode Anda; jaringan bisa dijeda, jadi lebih baik membacanya daripada menulis nilai secara permanen di kode.
| network | Koin | Chain | Minimum |
|---|---|---|---|
USDT_TRC20 | USDT | TRON | $1 |
USDT_BEP20 | USDT | BNB Chain | $1 |
USDC_BEP20 | USDC | BNB Chain | $1 |
USDT_ERC20 | USDT | Ethereum | $5 |
USDC_ERC20 | USDC | Ethereum | $5 |
USDC_BASE | USDC | Base | $1 |
USDT_POLYGON | USDT | Polygon | $1 |
USDC_POLYGON | USDC | Polygon | $1 |
USDT_ARBITRUM | USDT | Arbitrum | $1 |
USDC_ARBITRUM | USDC | Arbitrum | $1 |
USDT_OPTIMISM | USDT | Optimism | $1 |
USDC_OPTIMISM | USDC | Optimism | $1 |
USDT_AVALANCHE | USDT | Avalanche | $1 |
USDC_AVALANCHE | USDC | Avalanche | $1 |
USDT_XLAYER | USDT | X Layer | $1 |
USDC_XLAYER | USDC | X Layer | $1 |
USD1_BEP20 | USD1 | BNB Chain | $1 |
FDUSD_BEP20 | FDUSD | BNB Chain | $1 |
DAI_ERC20 | DAI | Ethereum | $5 |
DAI_ARBITRUM | DAI | Arbitrum | $1 |
DAI_BASE | DAI | Base | $1 |
BTC | BTC | Bitcoin | $5 |
LTC | LTC | Litecoin | $1 |
DOGE | DOGE | Dogecoin | $1 |
BCH | BCH | Bitcoin Cash | $1 |
TRX | TRX | TRON | $1 |
BNB | BNB | BNB Chain | $1 |
ETH | ETH | Ethereum | $5 |
ETH_BASE | ETH | Base | $1 |
ETH_ARBITRUM | ETH | Arbitrum | $1 |
ETH_OPTIMISM | ETH | Optimism | $1 |
POL | POL | Polygon | $1 |
AVAX | AVAX | Avalanche | $1 |
OKB | OKB | X Layer | $1 |
USDT_SOL | USDT | Solana | $1 |
USDC_SOL | USDC | Solana | $1 |
SOL | SOL | Solana | $1 |
USDT_TON | USDT | TON | $1 |
TON | TON | TON | $1 |
Akun deposit (alamat statis) POST /v1/deposit-accounts
POST /v1/deposit-accounts dengan {"customer_ref": "user_42"} memberi pelanggan itu alamat permanen di setiap jaringan (semua chain EVM memakai satu alamat). Apa pun yang mereka kirim dikreditkan dalam dolar AS, dengan satu webhook deposit.credited per transfer.
curl -X POST https://blockwallets.io/v1/deposit-accounts \
-H "Authorization: Bearer $BW_KEY" -H "Content-Type: application/json" \
-d '{"customer_ref":"user_42"}'{
"id": "dac_01J8…",
"mode": "live",
"customer_ref": "user_42",
"deposit_url": "https://blockwallets.io/deposit/dac_01J8…",
"min_amount": 100,
"currency": "USD",
"networks": [
{ "id": "USDT_TRC20", "chain": "tron", "token": "USDT", "address": "TXy4…8kQ2", "min_amount": 100, "confirmations": 1, … },
{ "id": "USDC_BASE", "chain": "base", "token": "USDC", "address": "0x5aE1…", "min_amount": 100, "confirmations": 20, … }
]
}customer_ref: 1–128 karakter berupa huruf, angka, dan_ . : @ -; nilai yang sama selalu mengembalikan akun yang sama.return_urlopsional di domain Anda- Responsnya berisi
deposit_url(halaman hosting dengan alamat, kode QR, dan deposit terbaru) dannetworks(id,address,min_amount,confirmationsuntuk tiap jaringan) - Id deposit diawali
dep_;amountdalam sen AS,amount_tokenjumlah koin, dan koin berharga membawarateyang dipakai
Transfer di bawah minimum (biasanya $1, BTC $5) dicatat sebagai below_min dan tidak dikreditkan otomatis; hubungi kami agar dikreditkan.
Webhook
Kami mengirim POST JSON ke URL webhook di dasbor (“Developer › Integrasi & kunci”; Live dan Test masing-masing punya URL dan secret sendiri). Body-nya adalah event:
POST /your/webhook
X-BW-Event: ev_01J8…
X-BW-Delivery: 1
X-BW-Signature: t=1793693052,v1=5f0c9b…
{"id":"ev_01J8…","type":"invoice.paid","created_at":"2026-11-03T08:04:12.000Z","invoice":{"id":"inv_01J8…","ref":"order_1042","status":"paid","amount":4200,…}}X-BW-Signature:t=<unix seconds>,v1=<hex>, denganv1= HMAC-SHA256(webhook secret mode tersebut,t+.+ body mentah)X-BW-Event: id event (ev_…); hapus duplikat berdasarkan id iniX-BW-Delivery: nomor percobaan, mulai dari 1
| Event | Kapan |
|---|---|
invoice.paid | Invoice menjadi paid atau paid_over (termasuk dana yang masuk setelah kedaluwarsa) |
invoice.wrong_amount | Invoice berakhir sebagai wrong_amount |
invoice.closed | Invoice kedaluwarsa tanpa dana masuk, atau Anda menutupnya |
deposit.credited | Transfer ke akun deposit telah dikreditkan |
Verifikasi terhadap body mentah sebelum mem-parse-nya, tolak t yang selisihnya lebih dari 300 detik dari jam Anda, dan bandingkan dalam waktu konstan. invoice / deposit di body adalah objek yang sama dengan hasil pencarian.
import crypto from "node:crypto";
// rawBody: the request body exactly as received (a string), header: X-BW-Signature
function verify(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(",").map((p) => p.trim().split("=")));
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false;
const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
return typeof parts.v1 === "string" && parts.v1.length === expected.length
&& crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
}Respons 2xx dianggap terkirim; jika tidak, kami coba lagi setelah 1 menit, 5 menit, 30 menit, 2 jam, 12 jam, 24 jam, dan 24 jam (total 8 percobaan).
Events dan pengiriman ulang
GET /v1/events?invoice_id=inv_… (atau deposit_id=dep_…) menampilkan webhook satu invoice atau deposit beserta state, attempts, last_status, dan last_error. POST /v1/events/ev_…/redeliver langsung mengantrekannya lagi, misalnya setelah Anda memperbaiki endpoint. “Developer › Log webhook” di dasbor menampilkan setiap percobaan beserta permintaan dan responsnya.
Mode uji
Invoice yang dibuat dengan kunci bw_test_ berjalan di testnet dan tidak pernah menyentuh uang sungguhan. Halaman pembayaran menampilkan tombol “Simulasikan pembayaran” (penuh / setengah / lebih), sehingga Anda bisa melihat status dan webhook tanpa koin testnet.