Skip to main content
Balances are the fiat side of your account — GHS, NGN, USD and the rest. Each currency has its own account with its own ID, and that ID is what trades and payouts settle into. This guide reads them four ways: everything at once, one account by ID, one currency by code, and the list of currencies you could hold.

What you’ll need

  • A dashboard JWT. These endpoints do not take a secret key.
Balance endpoints authenticate with a JWT, not a secret key — the opposite of the marketplace endpoints. A secret key returns 401:
The message says “format”, which reads like a malformed token. It is not — it is the wrong kind of credential. A perfectly valid secret key produces this.
JWTs are short-lived — roughly 30 minutes. An expired one returns 401 Expired Token. Refresh and retry rather than treating it as a failure.

The shape of the flow

1

List every balance

One call, every currency you hold.
2

Read one account by ID

When you already have the account ID.
3

Read one currency by code

When you know the currency but not the ID.
4

List the supported currencies

What you could hold, not what you do hold.

Step 1: List every balance

The response is a plain array, not a paged object:
There is no paging and no ordering you can rely on. The live response returned 15 currencies in no obvious order — not alphabetical, not by balance. Find a currency by filtering on currency, never by array position.
Accounts exist with a zero balance. EUR, EGP, GMD, GBP and CNY all came back at 0.00 — they are provisioned and ready, just empty. A zero balance is not a missing account.
Keep the accountId. This is the single most useful value on the page. Accepting a trade requires the destination currency’s accountId — see Let a Buyer Pay for a Trade.

Step 2: Read one account by ID

One object, same four fields as a row in Step 1. Use this to re-check a single account after a trade rather than pulling the whole list.

Step 3: Read one currency by code

If you know the currency but not the ID, look it up directly:
Identical to Step 2’s response, including the same accountId. These are two routes to one account.
The currency code is case-insensitive. /balances/currency/ghs and /balances/currency/GHS both work and both return "currency": "GHS" — the response always uppercases it.
This is the more useful of the two in practice: you can hard-code GHS in your integration, while an accountId is specific to your account and differs between test and live.

Step 4: List the supported currencies

This is the catalogue — what HyperRails supports, not what you hold.
mode is required, and it is easy to miss — it is a query parameter with no default. Leaving it off returns 400:
Pass mode=test or mode=live.
Test and live support different currencies. Test mode returned 20 currencies; live returned 5 — KES, NGN, GHS, USD, CNY. A pair that works in test may not exist in live. Check mode=live before you promise a currency to a customer.
The two lists disagree on wording, so do not key off description. GHS reads “Ghanaian Cedi” in both, but NGN is “Nigerian Naira” in test and “Nigerian Nairia” in live, and KES is “test currency” in live mode. Use currency.
Note also that the catalogue is wider than what you hold. Test mode lists LSL and RWF as ACTIVE, but no account for either appeared in Step 1 — a currency being supported does not mean an account is provisioned for it.

When things go wrong

What to do next