Derive a blockchain address
Derives a blockchain address for the specified network at the given BIP-44 index.
Set enable_monitoring: true to have the payment monitor watch this address
for incoming deposits and push webhooks.
Requires an active subscription. Returns 402 if the plan has expired.
Deriving additional addresses for an existing customer wallet does not count
against the wallet cap — only creating a new customer wallet does.
Deposit lifecycle (when enable_monitoring: true):
| Event | When | Notes |
|---|---|---|
wallet.deposit.detected | deposit first seen on-chain | may carry hash_pending: true |
wallet.deposit.hash_resolved | real on-chain tx hash resolved | same deposit_id, tx_hash now real |
wallet.deposit.confirmed | block depth / settlement delay met | safe to credit |
Idempotency — dedup on deposit_id, NOT tx_hash. Every deposit webhook carries a stable
deposit_id; record it and ignore repeats. tx_hash may initially be a placeholder (pending_…)
when the real on-chain hash isn’t indexable yet — then hash_pending is true, and a follow-up
wallet.deposit.hash_resolved (same deposit_id) arrives later with the real tx_hash. Update
the hash on your existing record; never credit a second time.
Addresses are always EIP-55 checksummed for EVM chains (ETH/BSC/POL), matching the casing
returned by GET /balances and list addresses. The native BSC coin is BNB (never BSC).
The confirmations field behaviour differs by network:
| Network | Confirmation method | confirmations value |
|---|---|---|
| ETH, BSC, POL | Block depth via eth_getTransactionReceipt | Real block count (e.g. 12) |
| BTC | Block depth via Esplora API | Real block count (e.g. 6) |
| TRX, SOL, LTC, BCH, XRP | Time-based settlement delay | Always 0 even when confirmed |
TRX/SOL/LTC/BCH/XRP always emit "confirmations": 0 in the webhook payload — even when
status is "confirmed". This is expected: these networks use a settlement delay instead of
block depth. Do not treat confirmations: 0 as an error on these networks.
Use status === "confirmed" as the authoritative signal, not the confirmations count.
Do not credit customer funds until you receive wallet.deposit.confirmed.
Webhook payload shape:
{
"event": "wallet.deposit.detected",
"data": {
"deposit_id": 4821, // STABLE idempotency key — dedup on THIS, not tx_hash
"customer_id": "cus_abc123",
"network": "TRX",
"address": "TV8f...", // EVM addresses are EIP-55 checksummed
"amount": "8.152212",
"currency": "USDT", // native BSC coin is "BNB"
"tx_hash": "pending_a1b2c3...", // may be a placeholder until resolved
"hash_pending": true, // true ⇒ the real hash arrives via hash_resolved
"confirmations": 0,
"status": "detected",
"detected_at": "2026-07-21T04:41:30Z",
"detected_by": "custom",
"safe_to_credit": false
}
}
Follow-up once the real on-chain hash is known (same deposit_id — update, don’t re-credit):
{
"event": "wallet.deposit.hash_resolved",
"data": { "deposit_id": 4821, "tx_hash": "9644c5c5...", "hash_pending": false, "status": "detected" }
}
Note: on TRX/SOL/LTC/BCH/XRP confirmations stays 0 even when status is "confirmed"
(settlement-delay networks) — use status, not the count.
Reconciling / normalizing your recorded balances: the authoritative source is the chain.
To (re)sync one customer, call GET /api/v1/wallet/{customerID}/balances (live, per-currency,
with confirmed/spendable) and set your stored balance to it; for a full sweep of every
customer use GET /api/v1/wallet/addresses. This corrects both any past double-count and any
previously-missed deposit in a single pass. Dedup historical deposits by deposit_id.
Verify webhook authenticity using HMAC-SHA256(rawRequestBody, whsec_secret), hex-encoded —
the signature is in the X-Webhook-Signature header (we also send X-Webhook-Event and X-Webhook-ID).
Authorizations
Business API key for server-to-server integrations.
Key prefix determines the environment — no separate flag needed:
test_sk_* = sandbox/testnet, live_sk_* = production/mainnet.

