Send funds

View as MarkdownOpen in Claude
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: | Original attempt | Repeat with the same id | | --- | --- | | Completed | The stored result is **replayed** — the same `txHash`, nothing new broadcast. | | Still in flight | `409` — the outcome isn't known yet. Reconcile via `/transactions`; never blind-retry. | | Failed before broadcast | The retry proceeds normally. | | Same id, **different** `assetId` / `recipient` / `amount` | `422` — the id is already committed to a different transfer. | 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.

Authentication

AuthorizationBearer

A 15-minute token from /auth. Required on every endpoint except /auth.

Headers

X-Request-IdstringRequiredformat: "^[A-Za-z0-9._-]{1,64}$"<=64 characters
**Required on `/send`, and client-supplied** — it is the idempotency key for the transfer. One id per logical transfer; **the same id on every retry of it**; a fresh id for a new transfer. 1–64 characters of `A-Za-z0-9._-`. Omitting it is a `400`.
X-USER-IDstringOptionalformat: "^[0-9a-fA-F]{24}$"

Optional. When present it overrides any userId in the body.

Request

This endpoint expects an object.
userIdstringRequiredformat: "^[0-9a-fA-F]{24}$"

24-character hex id, returned by /create.

assetIdenumRequired
Primary asset selector. An all-digit string (`"21"`) is accepted and normalised to an integer. - `1` — BITCOIN BTC (native, 8 decimals) - `2` — ETHEREUM ETH (native, 18 decimals) - `21` — ETHEREUM USDT (ERC20, 6 decimals) - `22` — ETHEREUM USDC (ERC20, 6 decimals) - `3` — BSC BNB (native, 18 decimals) - `31` — BSC USDT (BEP20, 18 decimals) - `32` — BSC USDC (BEP20, 18 decimals) - `4` — TRON TRX (native, 6 decimals) - `41` — TRON USDT (TRC20, 6 decimals) - `42` — TRON USDC (TRC20, 6 decimals) — not on every endpoint - `5` — POLYGON POL (native, 18 decimals) - `51` — POLYGON USDT (ERC20, 6 decimals) — not on every endpoint - `52` — POLYGON USDC (ERC20, 6 decimals) - `6` — SOLANA SOL (native, 9 decimals) - `61` — SOLANA USDT (SPL, 6 decimals) — not on every endpoint - `62` — SOLANA USDC (SPL, 6 decimals)
recipientstringRequired
Destination address on the asset's chain. Must differ from the sender.
amountstringRequiredformat: "^\d+(\.\d+)?$"

Human-decimal amount, e.g. "0.5". Never base units, never a float.

passwordstringRequired>=8 characters

Keystore password (AES-256-GCM, scrypt KDF). Unrecoverable — required by /send and /extend.

Response

OK
resultobject
requestIdstring

Echo of the inbound X-Request-Id, or a generated one.

Errors

400
Bad Request Error
401
Unauthorized Error
402
Payment Required Error
403
Forbidden Error
404
Not Found Error
409
Conflict Error
422
Unprocessable Entity Error
502
Bad Gateway Error
503
Service Unavailable Error