Guides
Create a transaction
Create an outgoing transaction from an existing BroSettlement wallet. A successful `POST` accepts the transaction for processing; it does not mean that the transaction is already final on-chain.
Before you begin
You need:
- An
ACTIVEwallet and itswalletId - An asset currently returned by
GET /api/v1/assets - A valid destination address for the selected chain
- Enough
availableBalancefor the amount and any applicable network fee - An initialized MPC setup and a healthy Co-Signer
- An API key with the
withdrawals:createscope - A unique
X-Idempotency-Key - An optional but recommended unique
clientReferencefrom your system
1. Check the wallet and available balance
Read the wallet and its balances before creating the transaction:
GET /api/v1/wallets/{walletId}
GET /api/v1/wallets/{walletId}/balancesUse availableBalance for the spendability check. Do not assume that the posted balance is fully available when part of it is reserved.
2. Convert the amount to atomic units
Send amountAtomic as a base-10 string in the asset’s smallest unit. Never use a floating-point number for an amount.
For example, if USDT uses 6 decimals:
1.00 USDT = "1000000"Read the current decimals and chain availability from the Assets API instead of hard-coding them.
3. Build the request body
{
"clientReference": "withdrawal-4821",
"walletId": "wallet-id",
"asset": "USDT",
"toAddress": "destination-address",
"amountAtomic": "1000000"
}clientReference can connect the BroSettlement transaction to your order, payout, or withdrawal record. It must be unique when supplied.
Use chainParams only when the current API schema requires chain-specific settings. Do not copy parameters between chains.
4. Sign and send the exact request
curl https://brosettlement-staging-api.brolabel.io/api/v1/transactions \
-X POST \
-H "X-Api-Key-Id: 11111111-2222-4333-8444-555555555555" \
-H "X-Api-Timestamp: 1785402000" \
-H "X-Api-Nonce: 37c19dc0-8247-4a56-8193-beca10dce927" \
-H "X-Api-Signature: base64_ed25519_signature" \
-H "X-Api-Body-Hash: sha256_of_exact_body" \
-H "X-Idempotency-Key: 018f4df0-5a7f-7352-bd4a-5fd069c2a0c2" \
-H "Content-Type: application/json" \
-d '{"clientReference":"withdrawal-4821","walletId":"wallet-id","asset":"USDT","toAddress":"destination-address","amountAtomic":"1000000"}'Calculate the body hash from the exact body bytes sent by the HTTP client. Sign the canonical six-line string using the exact POST method, request target /api/v1/transactions, body hash, timestamp, nonce, and API key ID.
5. Store the accepted transaction
A successful request returns 201 Created with a transaction detail object. Store at least:
idwalletIdtypestatuschainassetamountAtomicclientReferencecreatedAtandupdatedAt
The initial status is normally PENDING. Persist the BroSettlement transaction id before returning success from your own workflow.
6. Track the transaction to a terminal state
Listen for transaction.created, transaction.updated, transaction.confirmed, transaction.failed, and transaction.failed_on_chain. Reconcile each event against:
GET /api/v1/transactions/{transactionId}Treat REST as the source of truth. Do not mark a payout complete from the 201 response alone. Terminal statuses are CONFIRMED, FAILED, and FAILED_ON_CHAIN.
Retry safely
If the result of the original request is unknown, retry with the same X-Idempotency-Key and the identical request body. Changing the body while reusing the key produces an IDEMPOTENCY_CONFLICT.
Do not create a new idempotency key until you have checked the original transaction by id, clientReference, or the transaction list.
Common errors
| Error code | What to check |
|---|---|
INSUFFICIENT_AVAILABLE_BALANCE | Check the spendable amount and applicable network fee. |
INVALID_ADDRESS | Validate the destination against the selected chain. |
UNSUPPORTED_ASSET or UNSUPPORTED_CHAIN | Refresh the current asset and chain catalog. |
WITHDRAWALS_BLOCKED | Stop retries and resolve the organization or wallet restriction. |
CLIENT_REFERENCE_CONFLICT | Reuse the existing transaction or generate a genuinely new business reference. |
IDEMPOTENCY_CONFLICT | Retry only with the exact original request. |
UPSTREAM_UNAVAILABLE | Keep the original idempotency key and retry with backoff. |
Review the complete request and response schema, filters, statuses, and balance effects.
Implement resumable, idempotent lifecycle event processing.
Review canonical signing, idempotency, retries, errors, and request tracing.