Signs and broadcasts a transfer, and returns as soon as the network accepts it.
⚠️ A txHash is not a confirmation. Poll /txid until status flips from pending to success or failed.
The fee comes out of the amount — for native assets
Native transfers (BTC, ETH, BNB, POL, TRX, SOL) are sent net of the network fee: the recipient receives amount − fee, not amount. The transfer is sized so that the total leaving the wallet equals exactly the amount you asked for. If you need the recipient to receive an exact figure, add the fee (quote it with /fee) to the amount you send.
Token transfers (USDT, USDC) deliver the full amount. Their fee is paid separately, in the chain’s native coin — so a token wallet also needs a native balance for gas.
Amounts
amount is a human-decimal string ("0.5"), matched against /^\d+(\.\d+)?$/ and parsed to base units with the asset’s decimals. Never send base units, and never send a float you produced by arithmetic.
Minimums are enforced: 0.00001 BTC, and 0.0001 for a native EVM send (ETH, BNB, POL). Token sends must be greater than zero. An amount with more decimal places than the asset supports is rejected.
Sender
The sender is resolved server-side from userId + assetId. A client can never supply a private key or a from-address. recipient must differ from the sender.
Idempotency — X-Request-Id is required here
/send is the one endpoint where you must supply X-Request-Id (omitting it is a 400). It is the idempotency key, and it is what makes a retry safe.
The contract: one id per logical transfer, the same id on every retry of it, a fresh id for a new transfer. Generate it before the first attempt and store it alongside your intent record — if you mint a new id on retry, you have authorised a second transfer, and the service will send it.
Repeating a request with the same id resolves against the original:
A failure is only re-armed for retry when it is definitely pre-broadcast (bad input, wrong password, a broadcast the chain positively rejected). Ambiguous failures — a timeout, a dropped connection, an unknown 500 — deliberately leave the transfer claimed, because the transaction may be on-chain. Retrying those with the same id returns 409 until the claim expires (48 hours), which is the service refusing to double-send on your behalf.