Wallet API
Read your BLOX wallet and move money out in three ways:
- Send MYRC to an external EVM or Solana address.
- Withdraw MYR to a verified bank account linked to your BLOX account.
- Have MYR withdrawn to that bank account automatically, whenever tokens arrive at an address you set aside for it.
This guide follows the integration sequence from access setup to final-status reconciliation. See the API Reference for the complete request and response contracts.
Prerequisites
Before you integrate, prepare:
| Requirement | How to get it |
|---|---|
| Wallet API access | Ask BLOX to enable Wallet on your sandbox account |
| API key and signer key id | Ask BLOX for API access |
| Ed25519 key pair | Generate it yourself; register only the public key with BLOX |
| Funded wallet | Deposit MYRC on-chain or buy it through the BLOX app or Onramp API |
| Linked bank account | Required for fiat withdrawal; the account must be active and verified |
| Public HTTPS webhook URL | Required only for automatic withdrawal on deposit; register a WALLET webhook under Devtools → Webhooks |
Use the sandbox base URL while integrating:
https://api.sandbox.blox.myProduction uses https://api.blox.my. Read requests require blox-api-key. Write requests also require an HTTP message signature, and—where shown—an Idempotency-Key UUID v4 persisted before the first request.
How it works
The two flows share these rules:
- Amounts are in sen: integers in requests and strings in responses.
10000means RM100.00. - The create response returns an
id. Store it and read that withdrawal for status updates. GET /v1/wallet/transactionsis account history for reconciliation, not the best way to monitor one withdrawal.- Reuse the same
Idempotency-Keyafter a timeout or5xx. A new key represents a new transfer and may move money twice.
Token transfer lifecycle
CREATED ──► PENDING ──► PROCESSING ──► COMPLETED
│ │ │
└────────────┴────────────┴──────► FAILEDEVM transfers start at CREATED; Solana transfers start at PENDING. A transfer is final at COMPLETED or FAILED.
Fiat withdrawal lifecycle
PENDING ──► PROCESSING ──► COMPLETED
│ │
├──────────────┴──────► FAILED
└─────────────────────► REJECTEDA fiat withdrawal is final at COMPLETED, FAILED, or REJECTED. Bank credit is normally T+1 working day; requests after 5 PM MYT or on weekends start processing on the next working day.
Step-by-step guide
Step 1: Configure your application
Generate an Ed25519 key pair and send only the public key to BLOX:
openssl genpkey -algorithm Ed25519 -out blox_private_key.pem
openssl pkey -in blox_private_key.pem -pubout -out blox_public_key.pemSet your sandbox credentials. The examples below assume you copied the Node.js signBlox or Python sign_blox helper from Request Signing.
Keep the private key on your server. Never send it to BLOX or expose it in frontend code.
Step 2: Check the wallet balance
Read walletBalance and verify it covers the amount you intend to send.
See GET /v1/wallet/balance for the response fields.
Step 3: Choose a withdrawal flow
Choose one path based on the destination:
| Destination | Resolve first | Create request |
|---|---|---|
| External EVM or Solana address | GET /v1/wallet/networks | POST /v1/wallet/token/withdrawals |
| Linked Malaysian bank account | GET /v1/wallet/bank-accounts | POST /v1/wallet/fiat/withdrawals |
| Linked bank account, on every deposit | GET /v1/wallet/bank-accounts | None — see Step 6 |
Do not send a bank payout through the token route or use the Payout API for withdrawing your own Wallet balance. The Payout API is for merchant payouts from a separate prefund balance.
Step 4A: Transfer MYRC on-chain
Resolve tokenId at runtime because sandbox and production use different IDs. Choose a network matching the destination address format: EVM addresses start with 0x; Solana addresses use Base58.
The requested amount is the total wallet debit. Network fees, when applicable, are deducted before delivery; use the response amount and fee for reconciliation.
See POST /v1/wallet/token/withdrawals for limits, fields, statuses, and errors.
Step 4B: Withdraw MYR to a bank
List linked accounts and choose an active, verified account. Then create the withdrawal with its id.
See Bank Accounts and POST /v1/wallet/fiat/withdrawals for the complete contracts.
Step 5: Monitor the withdrawal
Poll the resource-specific read endpoint with the id from the create response:
- Token transfer:
GET /v1/wallet/token/withdrawals/{id} - Fiat withdrawal:
GET /v1/wallet/fiat/withdrawals/{id}
Use GET /v1/wallet/transactions later to reconcile all wallet movements. A new EVM transfer is absent from that list while it remains CREATED, so the resource-specific endpoint is authoritative from creation.
Step 6 (optional): Withdraw automatically on deposit
Ask BLOX to enable automatic withdrawal on deposit, then give a linked bank account its own on-chain address. Tokens sent to that address are converted and paid into that bank account without a create request — the deposit is the instruction.
Set it up once:
POST /v1/wallet/bank-accounts/{bankAccountId}/addressreturns the address. A bank account has one address for its lifetime, so calling again returns the same one.POST /v1/wallet/bank-accounts/{bankAccountId}/address/whitelistfor each address you will send from.
The second step is not optional. A trigger address accepts nothing until you allow a sender. Deposits from any other address are refused with sender_not_allowed, and the tokens simply stay in your wallet.
From then on, each deposit produces one bank transfer. You learn about it from wallet.deposit.updated, which arrives once the deposit is credited and carries the withdrawal it triggered — including a refusal, so a deposit you sent from an address you had not allowed says so in the same event.
One deposit produces at most one bank transfer, so sending to the same address twice pays twice, and nothing pays twice for a single deposit.
If a deposit is refused for a reason you can fix, fix it and call POST /v1/wallet/deposits/{id}/redrive. If you sent tokens and heard nothing at all, POST /v1/wallet/deposits/check-missed with the transaction hash is the way back.
Before switching to production, change the base URL and credentials, resolve the production tokenId, verify the production bank account, persist every idempotency key before sending, and respect the 30-per-minute create limit.