Errors

One envelope, one meaning per status code.
View as MarkdownOpen in Claude

Every failure returns the same shape, with the HTTP status repeated in error as a string:

1{
2 "message": "Unknown assetId",
3 "error": "400",
4 "requestId": "b7a1f0c2-3d4e-4a5b-9c6d-7e8f90a1b2c3"
5}

message is always safe to show a user and safe to log. Internal detail never appears in it — when something breaks on our side, the specifics go to our audit log against the requestId, and you get a generic message. Quote the requestId when you report a problem and we can pull up the exact request.

Status codes

StatusMeansWhat to do
400Bad input — a missing field, a malformed address, an unknown assetId, an unparseable amount, an amount below the minimum.Fix the request. Retrying it unchanged will fail identically.
401Not authenticated, or a wrong password on /send and /extend.Re-authenticate, or fix the password. Nothing was signed or broadcast.
402The wallet cannot cover the transfer — not enough of the asset, or no native coin to pay gas.Top the wallet up. Nothing was signed or broadcast.
403Refused on purpose. /seed always returns this; /extend returns it when the seed does not derive the user’s address.Do not retry.
404The transaction hash is not known to the chain.For a fresh broadcast, wait and poll again — it may not have propagated yet.
409A conflict — a wallet that already exists, or a seed that cannot be verified against that user.Read the message; usually the user already has what you were creating.
422The amount is smaller than the network fee that would be deducted from it (native sends only).Send more, or send a token instead. Nothing was broadcast.
500Something failed on our side — including a chain node or RPC provider being down or timing out.Safe to retry a read. Do not blindly retry a /send — see below.
502The chain rejected the broadcast (Tron). The transfer did not go out.Read the message. Do not retry unchanged.
503This deployment is not configured for that chain (Chain is not configured: SOLANA).Permanent — do not retry. It is a deployment issue, not an outage. Contact your operator.

The two that matter

401 on /send means the password was wrong — nothing was broadcast, so fixing it and retrying is completely safe. But a 500 or a timeout on /send is ambiguous: the transaction may have been signed and broadcast before the failure reached you. Never auto-retry it, and do not assume it failed just because it isn’t in /transactions yet. Follow the procedure in Reliability — retrying blind is how you send twice.

A 200 from /send is not a confirmation. It returns a txHash as soon as the network accepts the transaction. It can still fail on-chain — out of gas, reverted, dropped. Poll /txid until status is success or failed, and treat pending as unfinished.

Common messages

MessageStatusCause
assetId is required400You omitted assetId. There is no default.
Unknown assetId: 51400Not a supported asset — or a mainnet-only asset on a testnet deployment. The offending id is included in the message. See Asset IDs.
Wallet not found for user on this chain.400That user has no wallet on the asset’s chain — usually because the chain was not configured when the user was created. Backfill with /extend.
Missing/Invalid userId400userId must be a 24-character hex id.
Invalid amount400amount must be a decimal string like "0.5" — not a float, not base units, not negative.
Amount below minimum of 0.0001ETH400Native EVM sends have a floor of 0.0001 (ETH, BNB, POL).
Minimum send amount is 0.00001 BTC400Bitcoin’s floor.
Amount must be greater than zero.400Token sends cannot be zero.
Amount has more than 6 decimal places400More precision than the asset’s decimals allow.
Missing/Invalid address400A malformed recipient (or sender on /fee).
Sender and recipient must differ400Self-transfers are rejected.
Invalid password400 / 401The wrong keystore password. 400 on Bitcoin, 401 on Solana.
Invalid credentials401Bad api key on /auth, or the wrong keystore password on /send / /extend (EVM and Tron).
Insufficient native funds.402Not enough of the native coin for the transfer.
Insufficient native for gas.402The token balance is fine, but there is no native coin to pay the gas.
Insufficient token balance402Not enough of the token.
Seed does not match this user.403The mnemonic sent to /extend does not derive that user’s stored address.
Seed export is disabled.403/seed is permanently disabled. Key export is not available at any tier.
Transaction not found404Unknown hash, or a broadcast that has not propagated yet.
Wallet already exists.409A derived address is already registered.
Amount does not cover the network fee.422On a native send the fee is taken out of the amount — and this amount is smaller than the fee.
Transaction was rejected by the network.502Tron refused the broadcast. Nothing went out.
Chain is not configured: SOLANA503This deployment does not run that chain. Permanent.

Idempotency

There is none. /send has no idempotency key: the same request sent twice sends funds twice.

Most failures are safe — a 400, 401, 402, 422 or 502 means nothing was ever broadcast, so retrying once you have fixed the cause carries no risk. The dangerous case is a 500, a timeout or a dropped connection: the transaction may have been signed and broadcast before the failure reached you.

Do not resolve that case by checking /transactions and retrying if you don’t find the transfer. EVM history comes from an indexer that lags the mempool, so a fresh broadcast is routinely absent — and transaction rows carry no counterparty address, so you cannot positively identify one transfer anyway. “Not found” does not mean “not sent.”

Reliability sets out the procedure that is actually safe, and lists exactly which failures may be retried automatically.