Skip to content
LogoLogo

Payout API

Use the Payout API to send payouts to Malaysian bank accounts from your BLOX prefund balance. This guide gives the integration steps in sequence, from account configuration to reconciliation.

Prerequisites

Before you start the integration, get these items:

ItemHow to get it
Payout API accessAsk BLOX to enable Payout on your sandbox account.
API key and signer key idAsk BLOX for API access.
Ed25519 key pairGenerate the key pair yourself. Register only the public key with BLOX.
Public HTTPS webhook URLRegister a PAYOUT webhook in Devtools → Webhooks.
Prefund balanceCreate a top-up in Payouts → Top up.

Use the sandbox base URL during the integration:

https://api.sandbox.blox.my

The production base URL is https://api.blox.my. All read requests must contain blox-api-key. All write requests must also contain an HTTP message signature. The created= timestamp of a payout signature must be in the range of ±300 seconds of the BLOX time.

How it works

Loading diagram...

A payout follows one of these status sequences:

INITIATED ─────► SETTLED ─────► RETURNED
    │
    └──────────► REVERSED
StatusMeaning
INITIATEDBLOX accepted the payout and debited your prefund balance. The bank did not confirm the payout yet.
SETTLEDThe bank confirmed that the beneficiary received the money.
REVERSEDThe bank rejected the payout before settlement. netAmount and the fee return to your prefund balance.
RETURNEDThe bank returned the payout after settlement. netAmount returns to your prefund balance. BLOX keeps the fee.

All amounts are in sen. Requests use integers, and responses use strings. Read fee and netAmount from the response. Do not calculate them yourself.

Each payout must have a feeMode:

  • DEDUCT_FROM_AMOUNT: The beneficiary receives amount - fee.
  • CHARGE_TO_PREFUND: The beneficiary receives the full amount. BLOX debits the fee separately.

In the two modes, BLOX debits netAmount + fee from your prefund balance.

BLOX sets the fee for each account with three values: a percentage, a fixed amount, and a formula. MAX uses the larger of the two charges (max(amount × rate, fixed)). SUM adds the two charges. The standard fee is MAX at 1.00% with a minimum of RM1.50. Ask BLOX for the fee of your account.

BLOX rounds the percentage charge half-up to the nearest sen before it applies the formula. The fee in the response is the correct value.

Step-by-step guide

Step 1: Configure your application

Generate 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.pem

Configure your sandbox credentials. The examples that follow use the Node.js signBlox or Python sign_blox helper. Copy the helper from Request Signing.

Keep the private key on your server. Do not send it to BLOX. Do not put it in frontend code.

Step 2: Register your webhook and fund the prefund

In the dashboard, do these steps:

  1. Register a public HTTPS endpoint of type PAYOUT in Devtools → Webhooks.
  2. Create a sandbox top-up in Payouts → Top up.
  3. Wait for payout.prefund_completed. A sandbox top-up usually completes in about 10 seconds.

Verify the signature of each webhook event. Process each eventId one time only. For the payloads, refer to Webhook Events.

Step 3: Check the available balance

Read available before you create a payout. Do not subtract inFlight from available. BLOX already subtracted it.

For all response fields, refer to GET /v1/payout/prefund/balance.

Step 4: Choose the beneficiary

Get the list of active banks, and use the bankCode from the response. Then use one of these two methods:

  • For a new beneficiary that you pay one time, send beneficiary inline.
  • For a beneficiary that you pay again, register the beneficiary first. Then send its beneficiaryId.

For all fields, refer to Active Banks and Beneficiary endpoints.

Step 5: Create the payout

Generate one UUID v4 Idempotency-Key, and store it before you send the request. After a timeout or a 5xx response, send the request again with the same key.

Do not use a new key for a retry. A new key can create a second payout.

If BLOX creates the payout, the status is INITIATED. A 202 response tells you that BLOX did not complete the first request yet. Send the request again with the same idempotency key. For validation, response fields, and retry rules, refer to POST /v1/payouts.

Step 6: Handle the final outcome

Use the payout.updated webhook event as the primary source of the payout status. Do these steps:

  1. Store the payoutId.
  2. Process each webhook eventId one time only.
  3. Process all three final statuses: SETTLED, REVERSED, and RETURNED.

Use the read endpoint only to find the status after you did not receive a webhook event:

Step 7 (optional): Pay a beneficiary from a deposit

Ask BLOX to enable payouts from deposits. Then give a beneficiary its own on-chain address. When you send tokens to that address, BLOX converts the tokens and pays that beneficiary. You do not send POST /v1/payouts, and BLOX does not use your prefund balance.

For the endpoints, deposit records, and webhook events, refer to Onchain Trigger.

Do these steps one time for each beneficiary:

  1. Send POST /v1/payouts/beneficiaries/{beneficiaryId}/address. The response contains the address. A beneficiary has only one address. If you send the request again, you get the same address.
  2. For each address that you will send tokens from, send POST /v1/payouts/beneficiaries/{beneficiaryId}/address/whitelist.

You must do step 2. A trigger address does not accept deposits until you allow a sender. BLOX refuses deposits from all other addresses with sender_not_allowed. The tokens of a refused deposit stay in your wallet.

BLOX reports these transfers with payout.deposit.updated and payout.withdrawal.updated. BLOX does not send payout.created or payout.updated for them, and GET /v1/payouts does not show them. One deposit causes a maximum of one transfer.

If BLOX refuses a deposit for a reason that you can correct, correct the problem. Then send POST /v1/payouts/deposits/{id}/redrive. If you sent tokens and did not get a webhook event, send POST /v1/payouts/deposits/check-missed with the transaction hash.

Before you change to production, do these steps:

  1. Test the settled, reversed, returned, and pending results. Refer to Sandbox Testing.
  2. Change the base URL and the credentials to the production values.
  3. Add funds to your production prefund balance.
  4. Ask BLOX to confirm your fee and your account limits.
  5. Set alerts for RETURNED and payout.prefund_reversed.