Wallet API
Use the Wallet API to read your BLOX wallet balance. You can also move money out of your wallet in three ways:
- Send a token transfer of MYRC to an external EVM or Solana address.
- Make a fiat withdrawal of MYR to a verified linked bank account.
- Use automatic withdrawal on deposit. When tokens arrive at the trigger address of a linked bank account, BLOX withdraws MYR to that account automatically.
This guide gives the integration steps in sequence, from API access to the reconciliation of the final status. For the full request and response contracts, refer to the API Reference.
Prerequisites
Before you start the integration, get these items:
| Requirement | How to get it |
|---|---|
| Wallet API access | Ask BLOX to enable the Wallet API on your sandbox account. |
| API key and signer key id | Ask BLOX for API access. |
| Ed25519 key pair | Create the key pair yourself. Register only the public key with BLOX. |
| Funded wallet | Deposit MYRC on chain, or buy MYRC through the BLOX app or the Onramp API. |
| Linked bank account | Necessary for a fiat withdrawal. The account must be active and verified. |
| Public HTTPS webhook URL | Necessary only for automatic withdrawal on deposit. Register a WALLET webhook in Devtools → Webhooks. |
During the integration, use the sandbox base URL:
https://api.sandbox.blox.myThe production base URL is https://api.blox.my. Each request must include the blox-api-key header. Each write request must also include an HTTP message signature. If an endpoint shows an Idempotency-Key header, the request must also include it. Use a UUID v4 as the key, and store it before you send the first request.
How it works
These rules apply to a token transfer and to a fiat withdrawal:
- Amounts are in sen. Requests use integers, and responses use strings.
10000is RM100.00. - The create response gives an
id. Store it. To get status updates, read the token transfer or the fiat withdrawal with thatid. GET /v1/wallet/transactionsgives the account history for reconciliation. To monitor one token transfer or fiat withdrawal, use the read endpoint of that resource.- After a timeout or a
5xxresponse, send the request again with the sameIdempotency-Key. A new key creates a new token transfer or fiat withdrawal, and BLOX can move the money two times.
Token transfer lifecycle
CREATED ──► PENDING ──► PROCESSING ──► COMPLETED
│ │ │
└────────────┴────────────┴──────► FAILEDAn EVM token transfer starts at CREATED. A Solana token transfer starts at PENDING. A token transfer is final at COMPLETED or FAILED.
Fiat withdrawal lifecycle
PENDING ──► PROCESSING ──► COMPLETED
│ │
├──────────────┴──────► FAILED
└─────────────────────► REJECTEDA fiat withdrawal is final at COMPLETED, FAILED, or REJECTED. The bank usually credits the money one working day later (T+1). If you send the request after 5 PM MYT or on a weekend, BLOX starts to process it on the next working day.
Step-by-step guide
Step 1: Configure your application
Create an Ed25519 key pair. 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.pemConfigure your sandbox credentials. The examples below use the Node.js signBlox helper or the Python sign_blox helper from Request Signing. Copy the helper into your code before you use the examples.
Keep the private key on your server. Do not send it to BLOX. Do not put it in frontend code.
Step 2: Check the wallet balance
Read walletBalance. Make sure that it is equal to or more than the amount that you will send.
For the response fields, refer to GET /v1/wallet/balance.
Step 3: Choose a withdrawal flow
Choose one flow for the destination:
| Destination | Read 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, for each deposit | GET /v1/wallet/bank-accounts | None. Refer to Step 6. |
Do not use the token transfer endpoint to send money to a bank account. Do not use the Payout API to withdraw your own wallet balance. The Payout API sends merchant payouts from a different prefund balance.
Step 4A: Transfer MYRC on-chain
Get the tokenId at runtime. The sandbox and production use different IDs. Choose a network that agrees with the format of the destination address. EVM addresses start with 0x. Solana addresses use Base58.
The amount in the request is the total debit from your wallet balance. If a network fee applies, BLOX deducts it before delivery. For reconciliation, use the amount and the fee in the response.
For limits, fields, statuses, and errors, refer to POST /v1/wallet/token/withdrawals.
Step 4B: Withdraw MYR to a bank
Get the list of linked bank accounts. Choose an account that is active and verified. Create the fiat withdrawal with the id of that account.
For the full contracts, refer to Bank Accounts and POST /v1/wallet/fiat/withdrawals.
Step 5: Monitor the withdrawal
Send a GET request to the read endpoint of the resource. Use the id from the create response. Send the request again until the status is final:
- Token transfer:
GET /v1/wallet/token/withdrawals/{id} - Fiat withdrawal:
GET /v1/wallet/fiat/withdrawals/{id}
Later, use GET /v1/wallet/transactions to reconcile all wallet movements. While an EVM token transfer has the status CREATED, it is not in that list. Thus, use the read endpoint of the resource to get the correct status from the time that you create the token transfer.
Step 6 (optional): Withdraw automatically on deposit
Ask BLOX to enable automatic withdrawal on deposit. Then create a trigger address for a linked bank account. When tokens arrive at the trigger address, BLOX converts them and pays the money into that bank account. You do not send a create request. The deposit is the instruction.
Do these steps one time:
- Send
POST /v1/wallet/bank-accounts/{bankAccountId}/address. The response gives the trigger address. A bank account has one trigger address. If you send the request again, the response gives the same trigger address. - Send
POST /v1/wallet/bank-accounts/{bankAccountId}/address/whitelistfor each address that you will send tokens from. Each of these addresses becomes an allowed sender.
Do step 2. A trigger address accepts no deposit until it has an allowed sender. BLOX refuses a deposit from any other address with the reason sender_not_allowed. The tokens stay in your wallet balance.
After this configuration, each deposit starts one fiat withdrawal. BLOX tells you about it with the wallet.deposit.updated webhook event. BLOX sends this event when the deposit is confirmed on chain (PROCESSING). BLOX sends it again when BLOX credits the deposit (COMPLETED). The fiat withdrawal starts only after BLOX credits the deposit. Thus, the COMPLETED event contains the fiat withdrawal that the deposit started.
If BLOX refused the deposit, the COMPLETED event also shows the refusal. For example, the event shows the refusal of a deposit from an address that is not an allowed sender.
One deposit starts a maximum of one fiat withdrawal. If you send tokens to the same trigger address two times, BLOX makes two fiat withdrawals. BLOX does not make two fiat withdrawals for one deposit.
If BLOX refuses a deposit for a reason that you can correct, correct the cause. Then send POST /v1/wallet/deposits/{id}/redrive. If you sent tokens and you got no webhook event for the deposit, send POST /v1/wallet/deposits/check-missed with the transaction hash.
Before you change to production, do these steps:
- Change the base URL and the credentials.
- Get the production
tokenId. - Verify the production bank account.
- Store each idempotency key before you send the request.
- Send a maximum of 30 create requests each minute.