BingX Sub-Account Management
Authenticated endpoints for managing BingX sub-accounts (master account operations). All endpoints require HMAC SHA256 signature authentication. Several write endpoints require Content-Type: application/json instead of the standard form encoding — see the Quick Start helper below.
Base URLs: see references/base-urls.md | Authentication: see references/authentication.md
Quick Reference
| Endpoint | Method | Description | Auth | Body Type |
|---|---|---|---|---|
/openApi/account/v1/uid | GET | Query account UID | Yes | — |
/openApi/v1/account/apiPermissions | GET | Query API Key permissions | Yes | — |
/openApi/v1/account/apiPermissions | GET | Query API Key restrictions | Yes | — |
/openApi/account/v1/apiKey/query | GET | Query API Key info (own or sub-account) | Yes | — |
/openApi/subAccount/v1/create | POST | Create sub-account | Yes | JSON |
/openApi/subAccount/v1/list | GET | List sub-accounts | Yes | — |
/openApi/subAccount/v1/assets | GET | Query sub-account fund assets | Yes | — |
/openApi/subAccount/v1/updateStatus | POST | Freeze / unfreeze sub-account | Yes | JSON |
/openApi/subAccount/v1/allAccountBalance | GET | Batch query sub-account asset overview | Yes | — |
/openApi/subAccount/v1/apiKey/create | POST | Create API Key for sub-account | Yes | JSON |
/openApi/subAccount/v1/apiKey/edit | POST | Edit sub-account API Key | Yes | JSON |
/openApi/subAccount/v1/apiKey/del | POST | Delete sub-account API Key | Yes | JSON |
/openApi/account/v1/innerTransfer/authorizeSubAccount | POST | Authorize sub-account internal transfers | Yes | form |
/openApi/wallets/v1/capital/subAccountInnerTransfer/apply | POST | Sub-account internal transfer | Yes | form |
/openApi/wallets/v1/capital/subAccount/deposit/address | GET | Get sub-account deposit addresses | Yes | — |
/openApi/wallets/v1/capital/deposit/subHisrec | GET | Get sub-account deposit records | Yes | — |
/openApi/wallets/v1/capital/subAccount/innerTransfer/records | GET | Query sub-account internal transfer records | Yes | — |
/openApi/account/transfer/v1/subAccount/asset/transferHistory | GET | Query sub-account transfer history | Yes | — |
/openApi/account/transfer/v1/subAccount/transferAsset/supportCoins | POST | Query transferable amounts | Yes | form |
/openApi/account/transfer/v1/subAccount/transferAsset | POST | Sub-account asset transfer | Yes | form |
/openApi/v1/account/apiRestrictions | GET | Query API Key permissions for sub-account | Yes | — |
/openApi/wallets/v1/capital/deposit/createSubAddress | POST | Create deposit address for sub-account | Yes | form |
Parameters
Sub-account Parameters
- subAccountString: Sub-account username — must start with a letter, contain a number, and be longer than 6 characters
- subUid: Sub-account UID (long integer)
- note: Remark/note string for the sub-account or API Key
- isFeeze: Boolean — filter sub-accounts by frozen status (note: the API parameter name is
isFeeze, notisFreeze) - page: Page number, starting from 1
- limit: Page size, maximum 1000
- freeze: Boolean —
trueto freeze,falseto unfreeze
API Key Parameters
- apiKey: The API Key string of the sub-account
- uid: User UID (used when querying API Key info)
- permissions: Array of integers — permissions to assign (see Enums)
- ipAddresses: Array of IP address strings for the whitelist (optional)
Transfer Parameters
- coin: Currency/asset name (e.g.,
USDT) - amount / transferAmount: Transfer amount (float)
- userAccountType:
1=UID,2=Phone number,3=Email - userAccount: Recipient identifier (UID, phone, or email)
- walletType / fromAccountType / toAccountType: Account type (see Enums)
- fromUid / toUid: Sender / receiver UID
- fromType / toType:
1=Master account,2=Sub-account - subUids: Comma-separated UID list string (used for bulk authorization)
- transferable: Boolean —
trueto allow,falseto prohibit internal transfers - transferClientId: Custom client-side transfer ID string
Enums
permissions (API Key permission flags):
1— Spot Trading2— Read3— Perpetual Futures Trading4— Universal Transfer5— Withdraw7— Allow internal transfer of sub-accounts
walletType / accountType (account type codes):
1— Fund Account2— Standard Futures Account3— Perpetual Futures Account (USDⓢ-M)
status (deposit record status):
0— In progress1— Completed6— Chain uploaded
Parameter Validation Rules
- subAccountString: Must start with a letter, contain at least one number, and be longer than 6 characters
- subUid: Positive integer (long)
- coin: Uppercase letters and digits only; pattern
^[A-Z0-9]{1,20}$(e.g.,USDT) - amount / transferAmount: Must be a positive number (> 0)
- permissions: Array of integers; each must be one of
1, 2, 3, 4, 5, 7 - ipAddresses: When provided, each must be a valid IPv4 address
- page: Positive integer, starting from 1
- limit: Positive integer, 1–1000
- recvWindow: Integer, 1–5000 ms (see Replay Protection)
- timestamp: Unix time in milliseconds; must be within
recvWindowof server time
Quick Start
Important: Several sub-account write endpoints require
Content-Type: application/jsonwith the params sent as a JSON body. PassbodyType: "json"for those calls. All other POST endpoints use the standard form encoding (bodyType: "form").
CONSTRAINT: You MUST copy the
fetchSignedfunction below verbatim when generating code. Do NOT rewrite the signing, request, or JSON parsing logic. Only modify: (1)BASEURL entries for custom environments, (2) business parameters passed tofetchSigned. For the full client with URL-encoding and JSON body support, seereferences/authentication.md.
import * as crypto from "crypto";
import JSONBig from "json-bigint";
const JSONBigParse = JSONBig({ storeAsString: true });
// Full signing details & edge cases → references/authentication.md
// Domain priority: .com is mandatory primary; .pro is fallback for network/timeout errors ONLY.
const BASE = {
"prod-live": ["https://open-api.bingx.com", "https://open-api.bingx.pro"],
"prod-vst": ["https://open-api-vst.bingx.com", "https://open-api-vst.bingx.pro"],
};
function isNetworkOrTimeout(e: unknown): boolean {
if (e instanceof TypeError) return true;
if (e instanceof DOMException && e.name === "AbortError") return true;
if (e instanceof Error && e.name === "TimeoutError") return true;
return false;
}
async function fetchSigned(env: string, apiKey: string, secretKey: string,
method: "GET" | "POST", path: string, params: Record<string, unknown> = {},
bodyType: "form" | "json" = "form"
) {
const urls = BASE[env] ?? BASE["prod-live"];
const all = { ...params, timestamp: Date.now() };
const qs = Object.keys(all).sort().map(k => {
const v = all[k]; return `${k}=${Array.isArray(v) ? JSON.stringify(v) : v}`;
}).join("&");
const sig = crypto.createHmac("sha256", secretKey).update(qs).digest("hex");
for (const base of urls) {
try {
if (method === "GET") {
const r = await fetch(`${base}${path}?${qs}&signature=${sig}`,
{ headers: { "X-BX-APIKEY": apiKey, "X-SOURCE-KEY": "BX-AI-SKILL" },
signal: AbortSignal.timeout(10000) });
const j = JSONBigParse.parse(await r.text()); if (j.code !== 0) throw new Error(`BingX error ${j.code}: ${j.msg}`);
return j.data;
}
const ct = bodyType === "json" ? "application/json" : "application/x-www-form-urlencoded";
const body = bodyType === "json" ? JSON.stringify({ ...all, signature: sig }) : `${qs}&signature=${sig}`;
const r = await fetch(`${base}${path}`, { method: "POST",
headers: { "X-BX-APIKEY": apiKey, "X-SOURCE-KEY": "BX-AI-SKILL", "Content-Type": ct }, body,
signal: AbortSignal.timeout(10000) });
const j = JSONBigParse.parse(await r.text()); if (j.code !== 0) throw new Error(`BingX error ${j.code}: ${j.msg}`);
return j.data;
} catch (e) {
if (!isNetworkOrTimeout(e) || base === urls[urls.length - 1]) throw e;
}
}
}
Code Usage Rules
- MUST copy
fetchSignedverbatim -- do not simplify or rewrite - MUST use
json-bigint(JSONBigParse.parse) for response parsing -- notJSON.parse - MUST include
X-SOURCE-KEY: BX-AI-SKILLheader on every request - MUST NOT remove the domain fallback loop or
isNetworkOrTimeoutcheck
Common Calls
Query account UID:
const data = await fetchSigned("prod-live", API_KEY, SECRET, "GET",
"/openApi/account/v1/uid"
);
// data.uid
Create a sub-account:
const data = await fetchSigned("prod-live", API_KEY, SECRET, "POST",
"/openApi/subAccount/v1/create",
{ subAccountString: "alice001", note: "trading sub" },
"json" // must use JSON body
);
// data.subUid, data.subAccountString
List sub-accounts (paginated):
const data = await fetchSigned("prod-live", API_KEY, SECRET, "GET",
"/openApi/subAccount/v1/list",
{ page: 1, limit: 100 }
);
// data.subAccountList[].uid, .subAccountString, .isFreeze
Create API Key for a sub-account:
const data = await fetchSigned("prod-live", API_KEY, SECRET, "POST",
"/openApi/subAccount/v1/apiKey/create",
{
subUid: 16477999,
note: "read-only key",
permissions: [2], // 2 = Read only
ipAddresses: ["1.2.3.4"],
},
"json" // must use JSON body
);
// data.apiKey, data.secretKey
Freeze a sub-account:
await fetchSigned("prod-live", API_KEY, SECRET, "POST",
"/openApi/subAccount/v1/updateStatus",
{ subUid: 16477999, freeze: true },
"json" // must use JSON body
);
Transfer assets between sub-accounts (master only):
const data = await fetchSigned("prod-live", API_KEY, SECRET, "POST",
"/openApi/account/transfer/v1/subAccount/transferAsset",
{
assetName: "USDT",
transferAmount: 100,
fromUid: 11111111,
fromType: 1, // 1 = master account
fromAccountType: 1, // 1 = fund account
toUid: 22222222,
toType: 2, // 2 = sub-account
toAccountType: 1,
remark: "funding sub",
}
// default form body
);
// data.tranId
Additional Resources
For full parameter descriptions and response schemas for all 21 endpoints, see api-reference.md.
Agent Interaction Rules
All write operations require CONFIRM on prod-live. Read-only queries do not.
- prod-live: Ask user to type CONFIRM before any create, edit, delete, freeze, or transfer operation.
- prod-vst: No CONFIRM required. Inform user: "You are operating in the Production Simulated (VST) environment."
Step 1 — Identify the Operation
If the user's intent is unclear, present options:
What would you like to do?
- Query account UID or API Key permissions
- Create a new sub-account
- List sub-accounts
- Query sub-account assets / asset overview
- Freeze or unfreeze a sub-account
- Create / edit / delete a sub-account API Key
- Query a sub-account's API Keys
- Authorize sub-account internal transfers
- Transfer assets between accounts
- Query deposit address or deposit records
- Query transfer history
Step 2 — Collect sub-account identifier (if applicable)
Please provide the sub-account UID, or sub-account username if creating a new one.
Step 3 — Collect operation-specific parameters
Create sub-account: Ask for subAccountString (must start with letter, contain number, >6 chars). Ask for optional note.
Create / Edit API Key: Ask for:
subUid(sub-account UID)note(label)permissions(present the list: 1=Spot, 2=Read, 3=Perp Futures, 4=Universal Transfer, 5=Withdraw, 7=Internal Transfer)ipAddresses(optional IP whitelist)
Freeze / Unfreeze: Ask whether to freeze (true) or unfreeze (false).
Asset Transfer: Ask for:
assetName(e.g., USDT)transferAmount- sender UID + account type
- receiver UID + account type
Step 4 — Confirm (prod-live write ops only)
You are about to {action} on Production Live:
- {Summary of parameters}
Type CONFIRM to proceed, or anything else to cancel.
Step 5 — Execute and report
Execute the API call using the helper function (use bodyType: "json" for create, updateStatus, apiKey/create, apiKey/edit, apiKey/del; use default "form" for all other POST endpoints).
Return key fields to the user (e.g., subUid, apiKey, tranId).
JSON Body Endpoints (Reminder)
Always pass bodyType: "json" for these paths:
POST /openApi/subAccount/v1/createPOST /openApi/subAccount/v1/updateStatusPOST /openApi/subAccount/v1/apiKey/createPOST /openApi/subAccount/v1/apiKey/editPOST /openApi/subAccount/v1/apiKey/del
All other POST endpoints use the default form encoding.