REST API gốc

Mở trong ChatGPTMở trong Claude

API gốc là giao diện REST riêng của blockwallets: hóa đơn tính bằng cent Mỹ, một ref idempotent cho mỗi đơn hàng, tài khoản nạp tiền tĩnh bao phủ mọi mạng, và webhook ký bằng HMAC-SHA256. Nó tạo cùng loại hóa đơn trên cùng trang thanh toán như API tương thích Cryptomus, với cùng phí và số dư.

Bạn tự tạo khóa trong trang quản trị tại “Nhà phát triển › Tích hợp & khóa”: một khóa Live và một khóa Test cùng webhook signing secret của chúng. Mỗi khóa chỉ hiển thị một lần; danh sách chỉ hiện tiền tố. Nếu tài khoản bật xác minh hai bước, việc tạo hoặc xoay khóa Live sẽ yêu cầu nhập mã. Chưa có tài khoản người bán? Đăng ký dùng. Đã dùng Cryptomus? Xem API tương thích Cryptomus (cách chọn).

Khóa và yêu cầu

URL gốc https://blockwallets.io. Yêu cầu và phản hồi đều là JSON. Mọi yêu cầu đều mang:

Lỗi trả về mã HTTP và {"error": {"code": "…", "message": "…"}}: 400 invalid_request (thiếu hoặc sai định dạng một trường), 401 unauthorized (khóa thiếu, không tồn tại hoặc đã bị tắt), 404 not_found, 409 conflict (yêu cầu xung đột với trạng thái hiện tại của hóa đơn), 422 currency_unsupported.

Endpoint

EndpointChức năng
GET /v1/networksCác mạng bạn có thể nhận ngay lúc này trong chế độ của khóa này: mức tối thiểu, số xác nhận, thời gian đến thông thường và ước tính phí; coin có giá kèm tỷ giá hiện tại
POST /v1/invoicesTạo hóa đơn (201), hoặc trả về hóa đơn đã có với cùng ref (200)
GET /v1/invoices?ref=…Tra cứu hóa đơn theo ref của bạn
GET /v1/invoices/:idTra cứu hóa đơn theo id
POST /v1/invoices/:id/networkTự chọn mạng cho hóa đơn (trang thanh toán white-label): trả về address và pay_amount để hiển thị
POST /v1/invoices/:id/closeĐóng hóa đơn đang chờ chưa có giao dịch chuyển nào
POST /v1/deposit-accountsMở (201) hoặc lấy (200) tài khoản nạp tiền của một khách: địa chỉ cố định trên mọi mạng
GET /v1/deposit-accounts?customer_ref=…Tra cứu tài khoản nạp tiền theo customer_ref
GET /v1/deposit-accounts/:idTra cứu tài khoản nạp tiền theo id
GET /v1/depositsLiệt kê các khoản nạp của một tài khoản (account_id hoặc customer_ref, limit 1–200, mặc định 50)
GET /v1/deposits/:idTra cứu một khoản nạp
GET /v1/eventsCác lần gửi webhook của một hóa đơn hoặc khoản nạp (invoice_id hoặc deposit_id)
POST /v1/events/:id/redeliverGửi lại một webhook (202)

Thêm ?probe=1 vào lệnh tra cứu hóa đơn hoặc tài khoản nạp tiền để kiểm tra chuỗi ngay lúc đó (tối đa 10 giây một lần); nếu không, bạn nhận trạng thái mới nhất từ trình quét của chúng tôi, quét mỗi phút một lần.

Tạo hóa đơn POST /v1/invoices

Gọi POST /v1/invoices khi khách thanh toán và chuyển hướng họ đến pay_url trong phản hồi.

curl
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}}'
TrườngBắt buộcMô tả
refCóMã đơn hàng của bạn: 1–64 ký tự gồm chữ cái, chữ số và _ . : -. Duy nhất trong mỗi chế độ; gửi lại cùng ref với cùng các trường sẽ trả về cùng hóa đơn, còn khác các trường thì trả về 409
amountCóSố tiền tính bằng cent Mỹ, là số nguyên: 4200 = $42.00. Không thấp hơn mức tối thiểu của mạng khi đã chọn mạng
titleCóNội dung khách thấy trên trang thanh toán, tối đa 64 ký tự
return_urlCóNơi nút “Quay lại” trên trang thanh toán dẫn đến; phải thuộc một trong các tên miền website của bạn
success_urlKhôngNơi khách đến sau khi thanh toán; mặc định là return_url
networkKhôngChọn trước id mạng trong bảng mạng; bỏ trống để khách tự chọn trên trang thanh toán
customer_refKhôngId khách hàng của bạn, tối đa 64 ký tự, được trả về nguyên văn
lifetimeKhôngThời hạn tính bằng giây, 600 – 43200, mặc định 3600
amount_ruleKhông"any" = ghi có bất cứ số tiền nào đến (nạp tiền): chuyển paid ngay khi được xác nhận. Bỏ trống để dùng “Quy tắc số tiền” trong “Cài đặt › Quy tắc thanh toán & phí” của trang quản trị
accuracy_percentKhôngMức thiếu tiền vẫn được tính là đã trả, 0 – 5 (phần trăm), mặc định 0
subtract_percentKhôngPhần phí nền tảng do khách trả, 0 – 100 (phần trăm), cộng vào pay_amount; bỏ trống để dùng mặc định trong trang quản trị
payment_multipleKhôngCó cho phép nạp thêm phần còn thiếu vào cùng địa chỉ hay không, mặc định theo trang quản trị (bật nếu bạn chưa đổi); false: khoản chuyển thiếu đầu tiên kết thúc ở wrong_amount
metaKhôngBất kỳ đối tượng JSON nào tối đa 2 KB, được trả về nguyên văn trong tra cứu và webhook
currencyKhôngChỉ USD (mặc định); giá trị khác trả về 422

Mọi URL phải thuộc một trong các tên miền website của bạn (trang quản trị → “Nhà phát triển › Tích hợp & khóa”). Phản hồi là đối tượng hóa đơn bên dưới; network, address và pay_amount được điền khi đã chọn mạng.

Đối tượng hóa đơn

Id bắt đầu bằng inv_. amount tính bằng cent Mỹ; pay_amount và paid_amount là số lượng coin dạng chuỗi thập phân trên mạng đã chọn.

json
{
  "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Ý nghĩaBạn cần làm gì
pendingChờ thanh toán—
confirmingĐã thấy giao dịch chuyển và đang chờ xác nhận, hoặc đã chuyển thiếu và vẫn có thể nạp thêm—
paidĐã thanh toánGiao hàng / ghi có cho đơn
paid_overĐã thanh toán, và trả dưNhư trên; phần dư nằm trong số dư của bạn
wrong_amountKết thúc với số tiền ít hơn đầy đủ (khi hết hạn, hoặc ở khoản chuyển thiếu đầu tiên khi payment_multiple là false)Dịch vụ nạp tiền có thể ghi có phần đã đến (paid_amount; coin tính theo tỷ giá còn có paid_cents); cửa hàng thì yêu cầu khách trả nốt phần còn lại
closedHết hạn mà chưa nhận được gì, hoặc bạn đã đóng— (tiền đến muộn vẫn được ghi có và thông báo)

Các trường khác: pay_url (trang thanh toán), payments (mọi khoản chuyển cùng txid, amount, confirmations và confirmed), expires_at, paid_at, closed_at; BTC, LTC, DOGE, BCH và các coin gốc còn có rate (đô la Mỹ trên mỗi coin, chốt trong 30 phút), rate_locked_until và paid_cents (phần đã đến, tính bằng cent Mỹ).

Mạng

Truyền id vào network. GET /v1/networks trả về các mạng đang mở ngay lúc này trong chế độ của bạn; một mạng có thể bị tạm dừng, nên hãy đọc từ đó thay vì mã hóa cứng.

networkCoinChuỗiTối thiểu
USDT_TRC20USDTTRON$1
USDT_BEP20USDTBNB Chain$1
USDC_BEP20USDCBNB Chain$1
USDT_ERC20USDTEthereum$5
USDC_ERC20USDCEthereum$5
USDC_BASEUSDCBase$1
USDT_POLYGONUSDTPolygon$1
USDC_POLYGONUSDCPolygon$1
USDT_ARBITRUMUSDTArbitrum$1
USDC_ARBITRUMUSDCArbitrum$1
USDT_OPTIMISMUSDTOptimism$1
USDC_OPTIMISMUSDCOptimism$1
USDT_AVALANCHEUSDTAvalanche$1
USDC_AVALANCHEUSDCAvalanche$1
USDT_XLAYERUSDTX Layer$1
USDC_XLAYERUSDCX Layer$1
USD1_BEP20USD1BNB Chain$1
FDUSD_BEP20FDUSDBNB Chain$1
DAI_ERC20DAIEthereum$5
DAI_ARBITRUMDAIArbitrum$1
DAI_BASEDAIBase$1
BTCBTCBitcoin$5
LTCLTCLitecoin$1
DOGEDOGEDogecoin$1
BCHBCHBitcoin Cash$1
TRXTRXTRON$1
BNBBNBBNB Chain$1
ETHETHEthereum$5
ETH_BASEETHBase$1
ETH_ARBITRUMETHArbitrum$1
ETH_OPTIMISMETHOptimism$1
POLPOLPolygon$1
AVAXAVAXAvalanche$1
OKBOKBX Layer$1
USDT_SOLUSDTSolana$1
USDC_SOLUSDCSolana$1
SOLSOLSolana$1
USDT_TONUSDTTON$1
TONTONTON$1

Tài khoản nạp tiền (địa chỉ tĩnh) POST /v1/deposit-accounts

POST /v1/deposit-accounts với {"customer_ref": "user_42"} cấp cho khách đó một địa chỉ cố định trên mọi mạng (tất cả chuỗi EVM dùng chung một địa chỉ). Mọi khoản họ gửi đều được ghi có theo đô la Mỹ, mỗi lần chuyển có một webhook deposit.credited.

curl
curl -X POST https://blockwallets.io/v1/deposit-accounts \
  -H "Authorization: Bearer $BW_KEY" -H "Content-Type: application/json" \
  -d '{"customer_ref":"user_42"}'
json
{
  "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, … }
  ]
}

Các khoản chuyển dưới mức tối thiểu (thường là $1, BTC $5) được ghi nhận là below_min và không được ghi có tự động; hãy liên hệ để chúng tôi ghi có.

Webhook

Chúng tôi POST JSON đến URL webhook trong trang quản trị (“Nhà phát triển › Tích hợp & khóa”; Live và Test mỗi bên có URL và secret riêng). Nội dung là sự kiện:

http
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,…}}
Sự kiệnKhi nào
invoice.paidHóa đơn chuyển sang paid hoặc paid_over (kể cả tiền đến sau khi hết hạn)
invoice.wrong_amountHóa đơn kết thúc ở wrong_amount
invoice.closedHóa đơn hết hạn mà chưa nhận được gì, hoặc bạn đã đóng
deposit.creditedMột khoản chuyển vào tài khoản nạp tiền đã được ghi có

Hãy xác minh trên nội dung thô trước khi phân tích, từ chối t lệch quá 300 giây so với đồng hồ của bạn, và so sánh trong thời gian không đổi. invoice / deposit trong nội dung là cùng đối tượng mà một lệnh tra cứu trả về.

Node.js
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));
}

Phản hồi 2xx được tính là đã gửi; nếu không, chúng tôi thử lại sau 1 phút, 5 phút, 30 phút, 2 giờ, 12 giờ, 24 giờ và 24 giờ (tổng cộng 8 lần).

Events và gửi lại

GET /v1/events?invoice_id=inv_… (hoặc deposit_id=dep_…) liệt kê các webhook của một hóa đơn hoặc khoản nạp cùng state, attempts, last_status và last_error. POST /v1/events/ev_…/redeliver xếp hàng gửi lại ngay, ví dụ sau khi bạn đã sửa endpoint. “Nhà phát triển › Nhật ký webhook” trong trang quản trị hiển thị mọi lần thử kèm yêu cầu và phản hồi.

Chế độ thử nghiệm

Hóa đơn tạo bằng khóa bw_test_ chạy trên testnet và không bao giờ động đến tiền thật. Trang thanh toán hiển thị nút “Mô phỏng thanh toán” (đủ / một nửa / trả dư), để bạn xem trạng thái và webhook mà không cần có coin testnet.