Start with V3 REST
Use RestClientV3 for UTA market data, account reads, balances, positions, orders, and fills.
Open sectionBuild Bitget integrations without writing your own request signing, UTA routing, WebSocket authentication, reconnect loops, resubscribe logic, or WebSocket API response matching.
import { RestClientV3 } from 'bitget-api';
const client = new RestClientV3();
async function main() {
const serverTime = await client.getServerTime();
const instruments = await client.getInstruments({
category: 'SPOT',
symbol: 'BTCUSDT',
});
const tickers = await client.getTickers({
category: 'SPOT',
symbol: 'BTCUSDT',
});
const orderBook = await client.getOrderBook({
category: 'SPOT',
symbol: 'BTCUSDT',
limit: '5',
});
const candles = await client.getCandles({
category: 'SPOT',
symbol: 'BTCUSDT',
interval: '1m',
limit: '5',
});
console.log({
serverTime: serverTime.data.serverTime,
instrument: instruments.data[0]?.symbol,
ticker: tickers.data[0],
bestBid: orderBook.data.b[0],
bestAsk: orderBook.data.a[0],
candles: candles.data,
});
}
main().catch(console.error);API surface map
Bitget integrations often need both current UTA flows and a clear boundary for Classic endpoints. Use the SDK surface that matches the account, endpoint family, and stream topic shape.
Your app
Bot, dashboard, worker, tool
Any Node.js or JavaScript-compatible service that needs Bitget market data, account state, order management, or reconciliation.
npm package
npm install bitget-apiRestClientV3
Current V3/UTA REST API
WebsocketClientV3
V3 public and private streams
WebsocketAPIClient
Awaitable order commands
RestClientV2
Classic REST fallback
WebsocketClientV2
Classic stream fallback
Bitget APIs
V3/UTA REST API calls
Public market streams
Private account streams
WebSocket API order commands
V2/Classic fallback workflows
Product values
Keep product routing values close to the client and method that use them. V3 REST, WebSocket streams, WebSocket API commands, and Classic APIs do not all use the same casing.
V3 REST
category: 'SPOT'REST category values are upper-case and include SPOT, MARGIN, USDT-FUTURES, USDC-FUTURES, and COIN-FUTURES.
V3 public WebSocket
instType: 'spot'Public stream instType values are lower-case, such as spot and usdt-futures.
V3 private WebSocket
instType: 'UTA'Private account, position, fill, and order topics use UTA as the account stream instType.
V3 WebSocket API
category: 'spot'WebSocket API command categories are lower-case and have their own order option casing.
What this tutorial covers
Start with a working public request, then build through credentials, UTA product values, private streams, demo trading, WebSocket API commands, Classic boundaries, reconnect recovery, and production rollout checks.
Install the package, create RestClientV3, make public reads, add private credentials, and test demo order flows.
Use WebsocketClientV3 with the right WS_KEY_MAP entry, then handle reconnect and resubscribe behavior.
Use WebsocketAPIClient for promise-wrapped place, batch place, cancel, and batch cancel commands.
Keep Classic REST and WebSocket usage separate from UTA assumptions, categories, and topic casing.
Start building
Run one focused example first, then add the surrounding account-state and recovery workflow once the client, credentials, and product values are correct.
import { RestClientV3 } from 'bitget-api'; const client = new RestClientV3(); async function main() { const serverTime = await client.getServerTime(); const instruments = await client.getInstruments({ category: 'SPOT', symbol: 'BTCUSDT', }); const tickers = await client.getTickers({ category: 'SPOT', symbol: 'BTCUSDT', }); const orderBook = await client.getOrderBook({ category: 'SPOT', symbol: 'BTCUSDT', limit: '5', }); const candles = await client.getCandles({ category: 'SPOT', symbol: 'BTCUSDT', interval: '1m', limit: '5', }); console.log({ serverTime: serverTime.data.serverTime, instrument: instruments.data[0]?.symbol, ticker: tickers.data[0], bestBid: orderBook.data.b[0], bestAsk: orderBook.data.a[0], candles: candles.data, });} main().catch(console.error);Workflow diagrams
A REST API response, stream update, and WebSocket API acknowledgement each carry different operational meaning. These flows show where routing, subscription state, reconnect recovery, and command acknowledgement fit.
Keep category and symbol explicit, then let the SDK handle timestamp, signature, routing, and response parsing.
choose(category)Appbuild typed requestAppcall RestClientV3SDKsign and routeSDKreceive Bitget responseBitgetcheck code and stateAppAfter reconnect, automatic resubscribe is only transport recovery. Reconcile account state before sensitive actions resume.
on(reconnect)Eventpause private writesAppautomatic reconnectSDKautomatic resubscribeSDKREST backfillAppresume from known stateAppUse the WebSocket API for awaitable commands, then confirm final state through streams or REST.
connectWSAPI()AppauthenticateSDKsubmitNewOrder()Appmatch response idSDKreceive ackBitgetconfirm order stateAppProduction rollout
The important work starts after the first request succeeds: credentials, account mode, product values, reconnect behavior, final order state, and Classic boundaries all need to be predictable and observable.
Use separate live and demo trading keys, and never put private keys in frontend code.
Make category, instType, symbol, account mode, and product family explicit in request builders.
Set clientOid on every order before sending so retries and restarts can reconcile state.
After private WebSocket reconnects, backfill balances, positions, open orders, history, and recent fills through REST.
Check Bitget code values, per-item batch codes, and final order status before treating a command as complete.
Keep the host clock synced for private signed requests and avoid widening recvWindow unless needed.
Use V2/Classic clients only in isolated workflows that still depend on Classic API semantics.
Choose your path
Use RestClientV3 for UTA market data, account reads, balances, positions, orders, and fills.
Open sectionSubscribe to V3 private account, position, fill, and order topics with instType set to UTA.
Open sectionUse separate demo keys and demoTrading: true before small live order tests.
Open sectionUse V2 clients only for workflows that still depend on Classic endpoints and topic shapes.
Open sectionThis tutorial focuses on the Bitget API pieces developers usually need first: V3 REST API calls, UTA public and private streams, WebSocket API commands, demo trading, V2/Classic boundaries, reconnects, and rollout checks.
This guide shows how to connect to Bitget with our bitget-api package - the Bitget Node.js, JavaScript, and TypeScript SDK by Siebly.io. You'll cover REST, WebSocket streams, and the WebSocket API.
The SDK handles signing, routing, reconnects, and resubscribes so you don't have to. Below: install, public and private REST, live streams, demo trading, WebSocket API orders, V2/Classic where you still need it, and a few production notes.
Key links
bitget-apitiagosiebler/bitget-apiBitget has several API surfaces, and they don't all work the same way:
That adds up - auth, routing, WebSocket lifecycle, topic tracking, reconnects, typed request shapes. The SDK handles those parts. You focus on the work: pull market data, check balances, place orders, subscribe to updates, reconcile after reconnects.
The main SDK surfaces are:
| Use case | SDK surface | Common usage |
|---|---|---|
| Current REST API | RestClientV3 | V3/UTA public market data, account reads, transfers, positions, orders, fills, and other endpoint groups |
| Current WebSocket streams | WebsocketClientV3 | V3/UTA public market streams and private account streams |
| Current WebSocket API commands | WebsocketAPIClient | Promise-driven V3 order placement, batch placement, cancellation, and batch cancellation over WebSocket |
| Classic REST API | RestClientV2 | V2/Classic public, private, and trading workflows |
| Classic WebSocket streams | WebsocketClientV2 | V2/Classic public and private stream topics |
For new UTA work, start with RestClientV3, WebsocketClientV3, and WebsocketAPIClient. Reach for RestClientV2 and WebsocketClientV2 only when the account or workflow is still on Bitget Classic.
Install the SDK with npm:
npm install bitget-apiOr use another npm-compatible package manager:
pnpm install bitget-api
yarn add bitget-apiPublic market data does not require API keys. Private REST API calls, private WebSocket streams, and WebSocket API order commands require three Bitget API credentials:
| SDK option | Bitget credential |
|---|---|
apiKey | API key |
apiSecret | API secret |
apiPass | API passphrase set when the API key is created |
apiPass is the Bitget API passphrase, not the account login password.
Use separate credentials for live and demo trading. Demo trading API calls need demo API keys plus demoTrading: true in the SDK options.
Our private examples use environment variables for convenience - use whatever secret store fits your setup.
When creating API keys, grant the minimum permissions you need. Dashboards usually only need read access. Trading needs read/write on orders. Withdrawal isn't required for anything here. Whitelist IPs if your server has fixed outbound addresses.
Bitget has a few naming differences across their API:
| Surface | Product values shown in this guide |
|---|---|
V3 REST category | SPOT, MARGIN, USDT-FUTURES, USDC-FUTURES, COIN-FUTURES |
V3 public WebSocket instType | spot, usdt-futures, usdc-futures, coin-futures |
V3 private WebSocket instType | UTA |
| V3 WebSocket API category | spot, usdt-futures, usdc-futures, coin-futures |
V2 WebSocket instType | SPOT, USDT-FUTURES, USDC-FUTURES, COIN-FUTURES |
REST, WebSocket streams, and the WebSocket API are separate integration flows:
| Flow | SDK surface | Best for | What the SDK handles |
|---|---|---|---|
| REST API | RestClientV3 or RestClientV2 | Request/response reads, writes, order reconciliation, broad endpoint coverage | Base URLs, timestamps, auth headers, signatures, response parsing |
| Public WebSocket streams | WebsocketClientV3.subscribe or WebsocketClientV2.subscribeTopic | Live market data such as tickers and order books | Connection routing, subscribe requests, heartbeats, reconnects, resubscribe |
| Private WebSocket streams | WebsocketClientV3.subscribe or WebsocketClientV2.subscribeTopic with credentials | Live account, order, fill, balance, and position updates | Authentication, private endpoint routing, reconnects, resubscribe |
| WebSocket API commands | WebsocketAPIClient | Awaitable order commands over a persistent V3 WebSocket connection | Connection setup, authentication, request IDs, promise resolution, response matching |
Order option casing can differ by surface. V3 REST order requests use reduceOnly: 'yes' | 'no'. V3 WebSocket API and V2 futures request types use reduceOnly: 'YES' | 'NO'. When unsure, check the type definitions for the client you're using.
Want the quickest path to something working? Start here.
Public REST calls work without credentials.
import { RestClientV3 } from 'bitget-api';
const client = new RestClientV3();
async function main() {
const serverTime = await client.getServerTime();
const instruments = await client.getInstruments({
category: 'SPOT',
symbol: 'BTCUSDT',
});
const tickers = await client.getTickers({
category: 'SPOT',
symbol: 'BTCUSDT',
});
const orderBook = await client.getOrderBook({
category: 'SPOT',
symbol: 'BTCUSDT',
limit: '5',
});
const candles = await client.getCandles({
category: 'SPOT',
symbol: 'BTCUSDT',
interval: '1m',
limit: '5',
});
console.log({
serverTime: serverTime.data.serverTime,
instrument: instruments.data[0]?.symbol,
ticker: tickers.data[0],
bestBid: orderBook.data.b[0],
bestAsk: orderBook.data.a[0],
candles: candles.data,
});
}
main().catch(console.error);If that prints data, public REST is working.
See also: V3 public REST examples
Private REST uses the same RestClientV3 with credentials - the SDK signs requests for you.
import { RestClientV3 } from 'bitget-api';
function readBitgetCredentials() {
const apiKey = process.env.BITGET_API_KEY;
const apiSecret = process.env.BITGET_API_SECRET;
const apiPass = process.env.BITGET_API_PASS;
if (!apiKey || !apiSecret || !apiPass) {
throw new Error(
'Set BITGET_API_KEY, BITGET_API_SECRET, and BITGET_API_PASS before running private examples.',
);
}
return { apiKey, apiSecret, apiPass };
}
const client = new RestClientV3(readBitgetCredentials());
async function main() {
const balances = await client.getBalances();
const settings = await client.getAccountSettings();
console.log({
assetMode: settings.data.assetMode,
holdMode: settings.data.holdMode,
usdtEquity: balances.data.usdtEquity,
assets: balances.data.assets.slice(0, 5),
});
}
main().catch(console.error);If you get balances back, auth is set up correctly.
See also: V3 private REST examples
WebsocketClientV3 handles V3/UTA streams. Public ones don't need credentials.
import { WebsocketClientV3, WS_KEY_MAP } from 'bitget-api';
const ws = new WebsocketClientV3({});
ws.on('open', (data) => {
console.log('connected', data.wsKey);
});
ws.on('response', (data) => {
console.log('response', JSON.stringify(data));
});
ws.on('update', (data) => {
console.log('market update', JSON.stringify(data));
});
ws.on('reconnect', ({ wsKey }) => {
console.log('reconnecting', wsKey);
});
ws.on('reconnected', (data) => {
console.log('reconnected', data?.wsKey);
});
ws.on('exception', console.error);
ws.subscribe(
[
{
topic: 'ticker',
payload: {
instType: 'spot',
symbol: 'BTCUSDT',
},
},
{
topic: 'books',
payload: {
instType: 'spot',
symbol: 'BTCUSDT',
},
},
],
WS_KEY_MAP.v3Public,
);The SDK keeps the connection up, reconnects on drops, and resubscribes automatically.
See also: V3 public WebSocket example
Private streams are where trading systems usually watch account and order changes instead of polling constantly.
import { WebsocketClientV3, WS_KEY_MAP } from 'bitget-api';
function readBitgetCredentials() {
const apiKey = process.env.BITGET_API_KEY;
const apiSecret = process.env.BITGET_API_SECRET;
const apiPass = process.env.BITGET_API_PASS;
if (!apiKey || !apiSecret || !apiPass) {
throw new Error(
'Set BITGET_API_KEY, BITGET_API_SECRET, and BITGET_API_PASS before running private WebSocket examples.',
);
}
return { apiKey, apiSecret, apiPass };
}
const ws = new WebsocketClientV3(readBitgetCredentials());
ws.on('authenticated', (data) => {
console.log('authenticated', data.wsKey);
});
ws.on('update', (data) => {
console.log('account update', JSON.stringify(data));
});
ws.on('response', (data) => {
console.log('response', JSON.stringify(data));
});
ws.on('reconnect', ({ wsKey }) => {
console.log('reconnecting', wsKey);
});
ws.on('reconnected', (data) => {
console.log('reconnected', data?.wsKey);
// After reconnect, use REST to reconcile balances, positions, open orders, or recent fills.
});
ws.on('exception', console.error);
ws.subscribe(
[
{ topic: 'account', payload: { instType: 'UTA' } },
{ topic: 'position', payload: { instType: 'UTA' } },
{ topic: 'fill', payload: { instType: 'UTA' } },
{ topic: 'order', payload: { instType: 'UTA' } },
],
WS_KEY_MAP.v3Private,
);For V3 private account streams, use instType: 'UTA'.
See also: V3 private WebSocket example
Test with demo keys before going live. Demo uses separate Bitget API keys.
The snippet below sets demoTrading: true - leave it on while testing. A successful response means Bitget accepted the order, not that it filled.
import { RestClientV3 } from 'bitget-api';
function readBitgetCredentials() {
const apiKey = process.env.BITGET_API_KEY;
const apiSecret = process.env.BITGET_API_SECRET;
const apiPass = process.env.BITGET_API_PASS;
if (!apiKey || !apiSecret || !apiPass) {
throw new Error(
'Set BITGET_API_KEY, BITGET_API_SECRET, and BITGET_API_PASS with demo API credentials before placing demo orders.',
);
}
return { apiKey, apiSecret, apiPass };
}
const credentials = readBitgetCredentials();
const client = new RestClientV3({
apiKey: credentials.apiKey,
apiSecret: credentials.apiSecret,
apiPass: credentials.apiPass,
demoTrading: true,
});
async function main() {
const ticker = await client.getTickers({
category: 'SPOT',
symbol: 'BTCUSDT',
});
const lastPrice = ticker.data[0]?.lastPrice;
if (!lastPrice) {
throw new Error('No BTCUSDT ticker price returned.');
}
const orderRequest = {
category: 'SPOT',
symbol: 'BTCUSDT',
side: 'buy',
orderType: 'limit',
price: lastPrice,
qty: '0.001',
timeInForce: 'gtc',
clientOid: `demo-rest-${Date.now()}`,
} as const;
const result = await client.submitNewOrder(orderRequest);
console.log(result);
}
main().catch(console.error);Check order status via private streams or REST: getOrderInfo, getUnfilledOrders, getHistoryOrders, or getTradeFills.
See also: V3 spot trading example
The WebSocket API sends order commands over a persistent connection and waits for a response. WebsocketAPIClient wraps that in promises - write orders like normal async calls.
This example uses demoTrading: true with demo API keys.
import { WebsocketAPIClient } from 'bitget-api';
function readBitgetCredentials() {
const apiKey = process.env.BITGET_API_KEY;
const apiSecret = process.env.BITGET_API_SECRET;
const apiPass = process.env.BITGET_API_PASS;
if (!apiKey || !apiSecret || !apiPass) {
throw new Error(
'Set BITGET_API_KEY, BITGET_API_SECRET, and BITGET_API_PASS with demo API credentials before placing demo orders.',
);
}
return { apiKey, apiSecret, apiPass };
}
const credentials = readBitgetCredentials();
const wsApi = new WebsocketAPIClient({
apiKey: credentials.apiKey,
apiSecret: credentials.apiSecret,
apiPass: credentials.apiPass,
demoTrading: true,
});
const ws = wsApi.getWSClient();
ws.on('open', (data) => console.log('ws open', data.wsKey));
ws.on('authenticated', (data) => console.log('authenticated', data.wsKey));
ws.on('exception', console.error);
async function main() {
await ws.connectWSAPI();
const clientOid = `demo-wsapi-${Date.now()}`;
const placed = await wsApi.submitNewOrder('spot', {
symbol: 'BTCUSDT',
side: 'buy',
orderType: 'limit',
price: '10000',
qty: '0.001',
timeInForce: 'gtc',
clientOid,
});
console.log('placed', placed);
const cancelled = await wsApi.cancelOrder('spot', {
clientOid,
});
console.log('cancelled', cancelled);
}
main().catch(console.error);connectWSAPI() is optional - call it before your first command if you want the connection warm and ready.
See also: V3 WebSocket API client example
RestClientV3 is the client for current Bitget UTA REST endpoints.
Public client:
import { RestClientV3 } from 'bitget-api';
const publicClient = new RestClientV3();Private client:
import { RestClientV3 } from 'bitget-api';
const privateClient = new RestClientV3({
apiKey: process.env.BITGET_API_KEY!,
apiSecret: process.env.BITGET_API_SECRET!,
apiPass: process.env.BITGET_API_PASS!,
});Demo trading client:
import { RestClientV3 } from 'bitget-api';
const demoClient = new RestClientV3({
apiKey: process.env.BITGET_API_KEY!,
apiSecret: process.env.BITGET_API_SECRET!,
apiPass: process.env.BITGET_API_PASS!,
demoTrading: true,
});import { RestClientV3 } from 'bitget-api';
const client = new RestClientV3();
async function main() {
const instruments = await client.getInstruments({
category: 'SPOT',
symbol: 'BTCUSDT',
});
const tickers = await client.getTickers({
category: 'USDT-FUTURES',
symbol: 'BTCUSDT',
});
const orderBook = await client.getOrderBook({
category: 'SPOT',
symbol: 'BTCUSDT',
limit: '20',
});
const candles = await client.getCandles({
category: 'SPOT',
symbol: 'BTCUSDT',
interval: '1m',
limit: '20',
});
const openInterest = await client.getOpenInterest({
category: 'USDT-FUTURES',
symbol: 'BTCUSDT',
});
const fundingRate = await client.getCurrentFundingRate({
symbol: 'BTCUSDT',
});
console.log({
instrument: instruments.data[0],
ticker: tickers.data[0],
orderBook,
candles: candles.data.length,
openInterest,
fundingRate,
});
}
main().catch(console.error);import { RestClientV3 } from 'bitget-api';
const client = new RestClientV3({
apiKey: process.env.BITGET_API_KEY!,
apiSecret: process.env.BITGET_API_SECRET!,
apiPass: process.env.BITGET_API_PASS!,
});
async function main() {
const settings = await client.getAccountSettings();
const balances = await client.getBalances();
const positions = await client.getCurrentPosition({
category: 'USDT-FUTURES',
symbol: 'BTCUSDT',
});
const openOrders = await client.getUnfilledOrders({
category: 'SPOT',
symbol: 'BTCUSDT',
});
const recentFills = await client.getTradeFills({
limit: '20',
});
console.log({
settings: settings.data,
balanceCount: balances.data.assets.length,
positions: positions.data.list,
openOrders: openOrders.data.list,
recentFills: recentFills.data.list,
});
}
main().catch(console.error);import { RestClientV3 } from 'bitget-api';
const client = new RestClientV3({
apiKey: process.env.BITGET_API_KEY!,
apiSecret: process.env.BITGET_API_SECRET!,
apiPass: process.env.BITGET_API_PASS!,
demoTrading: true,
});
async function main() {
const clientOid = `rest-${Date.now()}`;
const placed = await client.submitNewOrder({
category: 'SPOT',
symbol: 'BTCUSDT',
side: 'buy',
orderType: 'limit',
price: '10000',
qty: '0.001',
timeInForce: 'gtc',
clientOid,
});
const orderInfo = await client.getOrderInfo({
clientOid,
});
const cancelled = await client.cancelOrder({
clientOid,
});
console.log({ placed, orderInfo, cancelled });
}
main().catch(console.error);For futures close-only orders, V3 REST uses lower-case reduceOnly values:
await client.submitNewOrder({
category: 'USDT-FUTURES',
symbol: 'BTCUSDT',
side: 'sell',
orderType: 'limit',
price: '100000',
qty: '0.001',
timeInForce: 'gtc',
posSide: 'long',
reduceOnly: 'yes',
});For live market or account updates, use WebsocketClientV3.
import { WebsocketClientV3 } from 'bitget-api';
const ws = new WebsocketClientV3({});
ws.on('open', (data) => console.log('open', data.wsKey));
ws.on('response', (data) => console.log('response', JSON.stringify(data)));
ws.on('update', (data) => console.log('update', JSON.stringify(data)));
ws.on('reconnect', (data) => console.log('reconnect', data.wsKey));
ws.on('reconnected', (data) => console.log('reconnected', data?.wsKey));
ws.on('authenticated', (data) => console.log('authenticated', data.wsKey));
ws.on('exception', console.error);response events are subscribe/control acks. update events carry stream data.
import { WebsocketClientV3, WS_KEY_MAP } from 'bitget-api';
const ws = new WebsocketClientV3({});
ws.on('update', (data) => {
console.log('public update', JSON.stringify(data));
});
ws.subscribe(
[
{
topic: 'ticker',
payload: {
instType: 'spot',
symbol: 'BTCUSDT',
},
},
{
topic: 'books',
payload: {
instType: 'usdt-futures',
symbol: 'BTCUSDT',
},
},
],
WS_KEY_MAP.v3Public,
);V3 public instType values are lower-case: spot, usdt-futures, usdc-futures, and coin-futures.
import { WebsocketClientV3, WS_KEY_MAP } from 'bitget-api';
const ws = new WebsocketClientV3({
apiKey: process.env.BITGET_API_KEY!,
apiSecret: process.env.BITGET_API_SECRET!,
apiPass: process.env.BITGET_API_PASS!,
});
ws.on('update', (data) => {
console.log('private update', JSON.stringify(data));
});
ws.subscribe(
[
{ topic: 'account', payload: { instType: 'UTA' } },
{ topic: 'position', payload: { instType: 'UTA' } },
{ topic: 'fill', payload: { instType: 'UTA' } },
{ topic: 'order', payload: { instType: 'UTA' } },
],
WS_KEY_MAP.v3Private,
);V3 private account topics use instType: 'UTA'.
ws.unsubscribe(
{
topic: 'ticker',
payload: {
instType: 'spot',
symbol: 'BTCUSDT',
},
},
WS_KEY_MAP.v3Public,
);The SDK remembers subscriptions per connection and resubscribes after reconnects.
WebsocketAPIClient sends V3 order commands over WebSocket and returns a promise for each response.
import { WebsocketAPIClient } from 'bitget-api';
const wsApi = new WebsocketAPIClient({
apiKey: process.env.BITGET_API_KEY!,
apiSecret: process.env.BITGET_API_SECRET!,
apiPass: process.env.BITGET_API_PASS!,
demoTrading: true,
});
async function main() {
await wsApi.getWSClient().connectWSAPI();
const clientOid = `wsapi-${Date.now()}`;
const placed = await wsApi.submitNewOrder('spot', {
symbol: 'BTCUSDT',
side: 'buy',
orderType: 'limit',
price: '10000',
qty: '0.001',
timeInForce: 'gtc',
clientOid,
});
const cancelled = await wsApi.cancelOrder('spot', {
clientOid,
});
console.log({ placed, cancelled });
}
main().catch(console.error);The helper methods are:
| Method | WebSocket API operation |
|---|---|
submitNewOrder(category, orderRequest) | place-order |
placeBatchOrders(category, orders) | batch-place |
cancelOrder(category, cancelRequest) | cancel-order |
cancelBatchOrders(category, cancels) | batch-cancel |
For batch operations, check each item in the returned args array - one batch can mix accepted and rejected orders.
For futures close-only orders over the WebSocket API, use upper-case reduceOnly values:
await wsApi.submitNewOrder('usdt-futures', {
symbol: 'BTCUSDT',
side: 'sell',
orderType: 'limit',
price: '100000',
qty: '0.001',
timeInForce: 'gtc',
posSide: 'long',
reduceOnly: 'YES',
});Reach for V2/Classic clients only when the account or workflow still uses Classic APIs. Don't mix V2 and V3 assumptions - category names, topics, request fields, and account modes all differ.
import { RestClientV2 } from 'bitget-api';
const client = new RestClientV2();
async function main() {
const spotCandles = await client.getSpotCandles({
symbol: 'BTCUSDT',
granularity: '1min',
limit: '100',
});
const futuresCandles = await client.getFuturesCandles({
symbol: 'BTCUSDT',
productType: 'USDT-FUTURES',
granularity: '1m',
limit: '100',
});
console.log({
spotCandles: spotCandles.data.length,
futuresCandles: futuresCandles.data.length,
});
}
main().catch(console.error);See also: V2 public REST examples
import { WebsocketClientV2 } from 'bitget-api';
const ws = new WebsocketClientV2({});
ws.on('update', (data) => {
console.log('classic update', JSON.stringify(data));
});
ws.on('response', (data) => {
console.log('classic response', JSON.stringify(data));
});
ws.on('exception', console.error);
ws.subscribeTopic('SPOT', 'ticker', 'BTCUSDT');V2 WebSocket instType values are upper-case, such as SPOT, USDT-FUTURES, USDC-FUTURES, and COIN-FUTURES.
See also: V2 WebSocket examples
Public REST first, then private read-only REST, then public streams, private streams, demo trading, and finally small live tests. None of the examples here need withdrawal permissions.
Set clientOid on every order and store it before you send. You'll need it to match state after retries, reconnects, or restarts.
Reconnects happen. After a private stream comes back, hit REST for balances, positions, open orders, history, and recent fills before trusting local state.
A resolved promise means the SDK got a response - not that the trade worked. Check Bitget's code, per-item batch code values, and order status. Accepted ≠ filled.
Private requests are timestamp-sensitive. Keep the host clock synced. Only touch recvWindow if you know you have clock skew.
Separate live and demo keys. Read-only keys for dashboards. Trading permissions only where you actually submit orders. Never put private keys in frontend code.
BITGETTRACE=true is handy for local debugging - it logs raw requests and responses. Don't turn it on where logs might leak account data.
No. Public REST market data and public WebSocket streams can be used without API keys.
The API passphrase is the passphrase set when creating the Bitget API key. In the SDK constructor it is passed as apiPass.
Start with RestClientV3, WebsocketClientV3, and WebsocketAPIClient for current V3/UTA workflows.
Use RestClientV2 and WebsocketClientV2 when the account or endpoint is still on Bitget Classic. Do not mix V2 and V3 request assumptions in the same snippet.
Bitget isn't consistent. V3 REST uses upper-case categories. V3 public WebSocket uses lower-case instType. Private account streams use UTA. V2 WebSocket uses upper-case instType.
Streams push updates - market data, account changes, fills. The WebSocket API is for sending commands (place/cancel orders) and getting a direct response. Watch state on streams; send orders on the WebSocket API.
Yes. The SDK works in JavaScript and TypeScript. TypeScript users also get request and response types from the package.
Yes. Pass your RSA private key as apiSecret; the SDK auto-detects RSA vs HMAC signing. See the GitHub repository.
Normal - let the SDK reconnect and resubscribe. Then reconcile balances, orders, and fills over REST before acting on cached state.
More in the repo:
Return to install snippets, direct examples, endpoint maps, and package links.
Open the runnable Bitget WebSocket API client example referenced in the tutorial.
Review private account, position, fill, and order topic subscriptions.
Browse SDK source, releases, issues, and endpoint coverage from GitHub.