Skip to main content
Before you start: you need a Brale account (sign up, KYB started/completed), an API client created in the Dashboard for the right environment (testnet or mainnet), and curl or any HTTP client.
1

Authenticate

Create an API client in the Dashboard (keys shown once — store securely). Clients are environment-scoped; use testnet while integrating, mainnet when ready to move value.Tokens expire in ~60 minutes; refresh using expires_in before expiry.
CLIENT_CREDENTIALS=$(echo -n "${CLIENT_ID}:${CLIENT_SECRET}" | base64)

curl --request POST \
  --url https://auth.brale.xyz/oauth2/token \
  --header "Authorization: Basic ${CLIENT_CREDENTIALS}" \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data grant_type=client_credentials
Expected: access_token, token_type (Bearer), expires_in.
2

Get your account_id

Use the bearer token from the previous step. The response contains your account_id — a 27-character KSUID.
curl --request GET \
  --url https://api.brale.xyz/accounts \
  --header "Authorization: Bearer ${AUTH_TOKEN}"
3

Get your custodial address_id

Brale auto-creates internal wallets (EVM, Solana, Stellar) when your account is provisioned. List them:
ACCOUNT_ID="2awTHmuEhx4Rjhqf9bWhSJNeNq2"  # replace with your account_id

curl --request GET \
  --url "https://api.brale.xyz/accounts/${ACCOUNT_ID}/addresses" \
  --header "Authorization: Bearer ${AUTH_TOKEN}"
Pick the address_id whose transfer_types array includes the chain you want to land on (e.g., base).
Mainnet (onchain): ethereum, base, solana, canton, stellar, polygon, avalanche, optimism, arbitrum, hedera, celo, kusama, spark, xrp_ledgerOffchain: wire, ach_debit, ach_credit, same_day_ach_credit, rtp_creditTestnet: base_sepolia, canton_testnet, amoy, sepolia, solana_devnet, xion_testnet, tempo_testnet
4

Create your first transfer

Example: offchain wire → onchain stablecoin on Base. Always send a unique Idempotency-Key per logical transfer and reuse it on retries.
Examples use SBC as the placeholder stablecoin. Replace it with your own stablecoin ticker (e.g., USDGLO, USDB). See Value Types for the full list.
ADDRESS_ID="2bFGkrQ7mPp8dCvBNx1TqWYz5kj"  # replace with your address_id

curl --request POST \
  --url "https://api.brale.xyz/accounts/${ACCOUNT_ID}/transfers" \
  --header "Content-Type: application/json" \
  --header "Authorization: Bearer ${AUTH_TOKEN}" \
  --header "Idempotency-Key: $(uuidgen)" \
  --data '{
    "amount": { "value": "10", "currency": "USD" },
    "source": { "value_type": "USD", "transfer_type": "wire" },
    "destination": {
      "address_id": "'"${ADDRESS_ID}"'",
      "value_type": "SBC",
      "transfer_type": "base"
    }
  }'
Testnet? Use testnet transfer_types instead: base_sepolia, solana_devnet, sepolia, etc. 
5

Poll for status

Poll GET /accounts/{account_id}/transfers with pagination. Store id, idempotency key, timestamps, status, and references for reconciliation. On 401, refresh the token and retry with the same Idempotency-Key.

Common errors

  • 403 network_not_supported: Using a testnet client/token on mainnet (or vice versa). Create a client for the target environment.
  • 404 compatible_address_not_found: Address doesn’t support the transfer_type, typo in address_id, or wrong account_id in the path.
  • 400 missing Idempotency-Key: All POST creates must include Idempotency-Key.

Next steps

  • See Guides for on/off-ramps, swaps, payouts.
  • For production hardening, review Troubleshooting and Coverage (transfer_types, value_types).