Blackwell Global

Client API — Reference Guide

⚠️ All data on this page is fictional. Every name, email address, account number, balance and trade shown in the examples below (John Doe, Jane Smith, Maria Garcia, Robert Lee, and every figure alongside them) is made up for illustration only and does not correspond to any real person or account. Only the field names, data shapes and status codes are real.

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

StatusMeaning
200 / 202Success. 202 is returned by /login specifically, when the account has 2FA enabled and a verification code is required before an access token is issued.
400Validation 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":{...}}.
401Missing, invalid or expired access token — call /tokens/refresh or /login again.
403Permission denied for reasons other than a bad token — e.g. calling /2fa-check with no two-factor process in progress.
404The requested route or resource does not exist.
500Unexpected server error.

1. Authentication

POST
/login

Exchanges an email/password for an access token (or starts the 2FA flow if the account has it enabled).

FieldTypeRequiredDescription
emailstringYesAccount email.
passwordstringYesAccount password.
rememberMebooleanNotrue issues a longer-lived session; omit/false for a short one.
Example request
{
  "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.
POST
/2fa-check

Completes login when 2FA is enabled. Must follow a /login call that returned 202.

FieldTypeRequiredDescription
_auth_codestringYesThe 6-digit code from the authenticator app.
twoFactorTokenstringYesThe token from /login's 202 response.
rememberMebooleanNotrue gives a 30-day token instead of 1 hour.
Example request
{
  "_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": []
}
POST
/tokens/refresh

Issues a new access/refresh token pair without re-entering credentials.

FieldTypeRequiredDescription
refreshTokenstringYesA refresh token previously issued by /login or /2fa-check.
Example request
{ "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"
}
POST
/logout

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

POST
/ib/tree

Returns the caller's referral tree (or a sub-IB's tree, via ibId) as nested nodes. Supports pagination via tableConfig.limit / tableConfig.offset.

FieldTypeRequiredDescription
calculatedGroupFieldsbooleanYesWhether per-node totals are grouped/aggregated.
tableConfig.limitintegerNoPage size.
tableConfig.offsetintegerNoPage offset.
ibIdintegerNoA sub-IB's id, to drill into their downline instead of your own top-level tree.
Example request
{ "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 }
}
POST
/ib/referrals

Returns the full referral downline as a flat, paginated table instead of a tree.

FieldTypeRequiredDescription
tableConfig.limitintegerNoPage size.
tableConfig.offsetintegerNoPage offset.
from / tostring (date)NoOptional date range filter.
currencystringNoOptional currency filter.
Example request
{ "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
}
POST
/ib/referrals/accounts

Lists the trading accounts belonging to one referral.

FieldTypeRequiredDescription
referralIdintegerYesThe referral's id, from /ib/tree or /ib/referrals.
tableConfigobjectYesRequired by the schema. This endpoint currently returns all of a referral's accounts in a single response.
Example request
{ "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.
POST
/ib/referrals/accounts/trading-history

Returns closed-trade history for one of a referral's trading accounts.

FieldTypeRequiredDescription
loginSidstringYesFormat "{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 / .offsetintegerNoOptional paging hints. This endpoint currently returns the complete trade list in one response.
Example request
{ "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

POST
/ib/commissions

Per-trade commission ledger across the whole downline.

FieldTypeRequiredDescription
tableConfigobjectYesRequired. This endpoint currently returns the complete commission ledger in a single response (large accounts may return several thousand rows).
Example request
{ "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
}
POST
/ib/reports/accounts-commissions

Commission totals grouped by account, over a date range.

FieldTypeRequiredDescription
from / tostring (date-time)NoOptional date range filter.
currencystringNoOptional currency filter.
tableConfigobjectYesRequired. This endpoint currently returns the complete report in a single response.
Example request
{ "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
}
POST
/ib/reports/clients-commissions

Same report as above, grouped by client instead of by account.

FieldTypeRequiredDescription
from / tostring (date-time)NoOptional date range filter.
currencystringNoOptional currency filter.
tableConfigobjectYesRequired. This endpoint currently returns the complete report in a single response.
Example request
{ "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
}