Blackwell Global
Client API — Reference Guide
This document describes the Client API routes available to your application. All request and response examples below use fabricated names, emails and account numbers for illustration — field names, data shapes and status codes reflect real, verified API behavior.
Authentication
All requests are POST with a JSON body and Content-Type: application/json,
including read-only lookups. Obtain an access token from /login (completing
/2fa-check first if the account has 2FA enabled), then send it on every subsequent
request as Authorization: Bearer <accessToken>. Access tokens expire (see
expDate in the login response) — use /tokens/refresh with the
paired refresh token to get a new pair without logging in again.
Pagination (tableConfig.limit / tableConfig.offset)
Table-shaped routes accept an optional tableConfig: {"limit": N, "offset": N}.
/ib/tree and /ib/referrals page their results according to this value.
The other table routes listed here currently return the complete result set in a single response
regardless of the limit requested — design your client to handle a potentially large response
and paginate/filter client-side on those routes.
Error responses
| Status | Meaning |
|---|---|
200 / 202 | Success. 202 is returned by /login specifically, when the account has 2FA enabled and a verification code is required before an access token is issued. |
400 | Validation error — malformed or semantically invalid input (e.g. referencing an account you don't have permission to view). Body shape: {"code":400,"message":"Validation Failed","errors":{...}}. |
401 | Missing, invalid or expired access token — call /tokens/refresh or /login again. |
403 | Permission denied for reasons other than a bad token — e.g. calling /2fa-check with no two-factor process in progress. |
404 | The requested route or resource does not exist. |
500 | Unexpected server error. |
1. Authentication
Exchanges an email/password for an access token (or starts the 2FA flow if the account has it enabled).
| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | Account email. |
password | string | Yes | Account password. |
rememberMe | boolean | No | true issues a longer-lived session; omit/false for a short one. |
{
"email": "[email protected]",
"password": "MySecurePass!1",
"rememberMe": true
}
200 — 2FA not enabled, access token returned immediately
{
"accessToken": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMDAwMSJ9...<truncated>",
"refreshToken": "eyJhbGciOiJIUzI1NiJ9.eyJ0eXAiOiJyZWZyZXNoIn0...<truncated>",
"trustedDeviceToken": null,
"exp": 1795877516,
"refreshTokenExpDate": "2026-11-29T16:51:56+02:00",
"expDate": "2026-11-28T16:51:56+02:00",
"client": {
"id": 10001, "cid": 0, "isIb": true, "canRequestIb": true,
"clientType": "Individual", "firstName": "John", "lastName": "Doe",
"country": "AE", "phone": "+971500000000", "language": "en",
"email": "[email protected]", "isVerified": true
}
}
202 — 2FA IS enabled on this account, no access token yet
{
"login": true, "complete": false, "error": "",
"message": "Two-factor code required",
"twoFactorToken": "b7e1f2...<short-lived token>"
}
Pass twoFactorToken straight into /2fa-check below.
Completes login when 2FA is enabled. Must follow a /login call that returned 202.
| Field | Type | Required | Description |
|---|---|---|---|
_auth_code | string | Yes | The 6-digit code from the authenticator app. |
twoFactorToken | string | Yes | The token from /login's 202 response. |
rememberMe | boolean | No | true gives a 30-day token instead of 1 hour. |
{
"_auth_code": "482913",
"twoFactorToken": "b7e1f2...<short-lived token>",
"rememberMe": true
}
200 — correct code, same response shape as /login's 200 above.
403 — no 2FA session actually in progress (e.g. called standalone, or the account has 2FA off):
{
"result": false,
"message": "User is not in a two-factor authentication process.",
"data": []
}
Issues a new access/refresh token pair without re-entering credentials.
| Field | Type | Required | Description |
|---|---|---|---|
refreshToken | string | Yes | A refresh token previously issued by /login or /2fa-check. |
{ "refreshToken": "eyJhbGciOiJIUzI1NiJ9.eyJ0eXAiOiJyZWZyZXNoIn0...<truncated>" }
200
{
"accessToken": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMDAwMSJ9...<new, truncated>",
"refreshToken": "eyJhbGciOiJIUzI1NiJ9.eyJ0eXAiOiJyZWZyZXNoIn0...<new, truncated>",
"expDate": "2026-11-28T16:52:00+02:00",
"refreshExpDate": "2026-11-29T16:52:00+02:00"
}
Invalidates the current session. No request body needed — just the Authorization header.
200 — the entire response body is a bare boolean:
true
2. IB / Partner — Referral Hierarchy
Returns the caller's referral tree (or a sub-IB's tree, via ibId) as nested nodes.
Supports pagination via tableConfig.limit / tableConfig.offset.
| Field | Type | Required | Description |
|---|---|---|---|
calculatedGroupFields | boolean | Yes | Whether per-node totals are grouped/aggregated. |
tableConfig.limit | integer | No | Page size. |
tableConfig.offset | integer | No | Page offset. |
ibId | integer | No | A sub-IB's id, to drill into their downline instead of your own top-level tree. |
{ "calculatedGroupFields": false, "tableConfig": { "limit": 2, "offset": 0 } }
200 (truncated/compacted for brevity)
{
"headers": { "directReferralsTitle": "Direct Referrals", "total": "214", "subIBsCount": "11", "directCount": "5" },
"totals": { "balance": "48213.90", "lots": "302.44000000", "commission": "1180.22", "directCount": 5, "totalCount": 214 },
"referrals": [
{
"ibId": 10001, "referralId": 20001, "level": 0, "levelName": "direct",
"fullName": "JANE SMITH", "isIb": false, "directCount": 0, "totalCount": 0,
"values": { "balance": 530.10, "commission": 12.40, "country": "United States",
"createdAt": "2026-06-01T10:00:00+03:00", "lots": 1.2, "isVerified": true },
"children": [], "self": false, "childrenAvailable": false
},
{
"ibId": 10001, "referralId": 20002, "level": 0, "levelName": "direct",
"fullName": "MARIA GARCIA", "isIb": true, "directCount": 18, "totalCount": 41,
"values": { "balance": 8870.55, "commission": 266.10, "country": "Spain" },
"children": [], "self": false, "childrenAvailable": true
}
],
"pageInfo": { "limit": 2, "offset": 0, "total": 5 }
}
Returns the full referral downline as a flat, paginated table instead of a tree.
| Field | Type | Required | Description |
|---|---|---|---|
tableConfig.limit | integer | No | Page size. |
tableConfig.offset | integer | No | Page offset. |
from / to | string (date) | No | Optional date range filter. |
currency | string | No | Optional currency filter. |
{ "tableConfig": { "limit": 3, "offset": 0 } }
200
{
"columns": [
{ "key": "level", "title": "Level" }, { "key": "balance", "title": "Balance, USD" },
{ "key": "firstName", "title": "First Name" }, { "key": "lastName", "title": "Last Name" },
{ "key": "lots", "title": "Lots" }, { "key": "commission", "title": "Commission, USD" },
{ "key": "country", "title": "Country" }, { "key": "createdAt", "title": "Created At" },
{ "key": "isVerified", "title": "Is Verified" }
],
"rows": [
{ "level": "direct", "balance": "530.10", "firstName": "JANE", "lastName": "SMITH", "lots": "1.20000000",
"commission": "12.40", "country": "US", "createdAt": "2026-06-01T10:00:00+03:00", "isVerified": "1" },
{ "level": "direct", "balance": "8870.55", "firstName": "MARIA", "lastName": "GARCIA", "lots": "20.00000000" },
{ "level": "level 2", "balance": "140.00", "firstName": "ROBERT", "lastName": "LEE", "lots": "3.50000000" }
],
"totals": [], "canExportToCsv": true, "canFilter": true, "totalCount": 214
}
Lists the trading accounts belonging to one referral.
| Field | Type | Required | Description |
|---|---|---|---|
referralId | integer | Yes | The referral's id, from /ib/tree or /ib/referrals. |
tableConfig | object | Yes | Required by the schema. This endpoint currently returns all of a referral's accounts in a single response. |
{ "referralId": 20002, "tableConfig": {} }
200
{
"columns": [
{ "key": "login", "title": "Login" }, { "key": "type", "title": "Type" },
{ "key": "leverage", "title": "Leverage" }, { "key": "currency", "title": "Currency" },
{ "key": "balance", "title": "Balance" }, { "key": "equity", "title": "Equity" }
],
"rows": [
{ "login": "500101", "type": "MT5 Account", "leverage": "200", "currency": "USD", "balance": "1063.15", "equity": "1063.15" },
{ "login": "500102", "type": "MT5 Account", "leverage": "100", "currency": "USD", "balance": "5565.84", "equity": "5565.84" }
],
"totals": [], "canExportToCsv": false, "canFilter": false, "totalCount": null
}
The login value here, combined with a sid prefix, becomes the loginSid the next route needs.
Returns closed-trade history for one of a referral's trading accounts.
| Field | Type | Required | Description |
|---|---|---|---|
loginSid | string | Yes | Format "{sid}-{login}" — e.g. "2-500101". sid is a small integer identifying the account/platform type (2 = MT5 live trading); login comes from /ib/referrals/accounts. |
tableConfig.limit / .offset | integer | No | Optional paging hints. This endpoint currently returns the complete trade list in one response. |
{ "loginSid": "2-500101", "tableConfig": { "limit": 20 } }
200 — example rows:
{
"columns": [
{ "key": "col_..._opentime_...", "title": "Open Time" },
{ "key": "col_..._ticket_...", "title": "Ticket" },
{ "key": "col_..._type_...", "title": "Type" },
{ "key": "col_..._lots_...", "title": "Lots" },
{ "key": "col_..._symbol_...", "title": "Symbol" },
{ "key": "col_..._openprice_...", "title": "Open Price" },
{ "key": "col_..._stoploss_...", "title": "S/L" },
{ "key": "col_..._takeprofit_...", "title": "T/P" },
{ "key": "col_..._closetime_...", "title": "Close Time" },
{ "key": "col_..._closeprice_...", "title": "Close Price" },
{ "key": "col_..._commission_...", "title": "Commission" },
{ "key": "col_..._swaps_...", "title": "Swaps" },
{ "key": "col_..._profit_...", "title": "Profit" },
{ "key": "col_..._comment_...", "title": "Comment" }
],
"rows": [
{
"Open Time": "2026-10-12T08:14:02+03:00", "Ticket": "4821093", "Type": "buy",
"Lots": "0.10", "Symbol": "EURUSD", "Open Price": "1.08452",
"S/L": "1.08200", "T/P": "0", "Close Time": "2026-10-12T09:02:47+03:00",
"Close Price": "1.08595", "Commission": "0", "Swaps": "0",
"Profit": "14.30", "Comment": null
},
{
"Open Time": "2026-10-14T13:40:11+03:00", "Ticket": "4823510", "Type": "sell",
"Lots": "0.05", "Symbol": "GBPUSD", "Open Price": "1.26810",
"S/L": "1.27000", "T/P": "1.26500", "Close Time": "2026-10-14T15:11:28+03:00",
"Close Price": "1.26655", "Commission": "0", "Swaps": "0",
"Profit": "7.75", "Comment": "[tp 1.26500]"
}
],
"totals": [], "canExportToCsv": true, "canFilter": true, "totalCount": null
}
3. IB / Partner — Commissions
Per-trade commission ledger across the whole downline.
| Field | Type | Required | Description |
|---|---|---|---|
tableConfig | object | Yes | Required. This endpoint currently returns the complete commission ledger in a single response (large accounts may return several thousand rows). |
{ "tableConfig": { "limit": 20 } }
200
{
"columns": [
{ "key": "col_..._account_...", "title": "Account" },
{ "key": "col_..._closetime_...", "title": "Close Time" },
{ "key": "col_..._commission_...", "title": "Monetary Commission" },
{ "key": "col_..._level_...", "title": "Level" },
{ "key": "col_..._referral_...", "title": "Referral" },
{ "key": "col_..._symbol_...", "title": "Symbol" }
],
"rows": [
{
"id": "900001", "Account": "500210", "Close Time": "2026-10-29T16:44:42+02:00",
"Monetary Commission": "0.0800000000", "Level": "level 2",
"Referral": "ROBERT LEE", "Symbol": "XAUUSD"
}
],
"totals": [], "canExportToCsv": true, "canFilter": true, "totalCount": null
}
Commission totals grouped by account, over a date range.
| Field | Type | Required | Description |
|---|---|---|---|
from / to | string (date-time) | No | Optional date range filter. |
currency | string | No | Optional currency filter. |
tableConfig | object | Yes | Required. This endpoint currently returns the complete report in a single response. |
{ "from": "2026-01-01", "to": "2026-12-31", "currency": "USD", "tableConfig": { "limit": 20 } }
200
{
"columns": [
{ "key": "col_..._account_...", "title": "Account" },
{ "key": "col_..._commissionreceived_...", "title": "Commission Received, USD" },
{ "key": "col_..._level_...", "title": "Level" },
{ "key": "col_..._referral_...", "title": "Referral" }
],
"rows": [
{ "Account": "500210", "Commission Received, USD": "9.60", "Level": "level 2", "Referral": "ROBERT LEE" }
],
"totals": [], "canExportToCsv": true, "canFilter": true, "totalCount": null
}
Same report as above, grouped by client instead of by account.
| Field | Type | Required | Description |
|---|---|---|---|
from / to | string (date-time) | No | Optional date range filter. |
currency | string | No | Optional currency filter. |
tableConfig | object | Yes | Required. This endpoint currently returns the complete report in a single response. |
{ "from": "2026-01-01", "to": "2026-12-31", "currency": "USD", "tableConfig": { "limit": 20 } }
200
{
"columns": [
{ "key": "col_..._balance_...", "title": "Balance, USD" },
{ "key": "col_..._commissionreceived_...", "title": "Commission Received, USD" },
{ "key": "col_..._referral_...", "title": "Referral" }
],
"rows": [
{ "id": "70001", "Balance, USD": "924.23", "Commission Received, USD": "9.60", "Referral": "ROBERT LEE" }
],
"totals": [], "canExportToCsv": true, "canFilter": true, "totalCount": null
}