Binance API Documentation: Node.js Trading Guide
Learn how to use Binance API with Node.js to automate crypto trading, fetch market data, and build bots with real code examples.
Learn how to use Binance API with Node.js to automate crypto trading, fetch market data, and build bots with real code examples.
If you've ever watched a trade slip by because you were a second too late, you already understand why serious traders automate. The Binance API is one of the most powerful tools in a crypto trader's arsenal — and Node.js is arguably the cleanest way to work with it. Fast, async by default, and with a massive ecosystem of packages, JavaScript on the server side fits the real-time nature of crypto trading like a glove. This guide walks you through everything from initial setup to placing live orders, with actual working code you can adapt immediately.
Before writing a single line of code, you need API credentials from Binance. Log into your Binance account, navigate to Account > API Management, and create a new API key. Give it a descriptive label like 'nodejs-bot'. For read-only market data you only need 'Enable Reading' permissions. If you plan to place orders, enable 'Enable Spot & Margin Trading' as well. Never enable withdrawals on a trading bot key — there's no scenario where your bot needs that permission, and it dramatically reduces your risk exposure if the key is ever compromised.
Always whitelist your server's IP address in the Binance API key settings. This single step prevents your key from being usable even if it leaks.
On the Node.js side, the most widely used library is `node-binance-api`, though `@binance/connector` is the official SDK maintained by Binance themselves. For production work, the official connector is preferable since it tracks the latest API documentation changes. Install it along with `dotenv` to keep credentials out of your code:
npm init -y
npm install @binance/connector dotenv
touch .env .gitignore
echo ".env" >> .gitignore
Store your credentials in the `.env` file:
BINANCE_API_KEY=your_api_key_here
BINANCE_API_SECRET=your_api_secret_here
The most common starting point is pulling market data. Binance's REST API provides ticker prices, order book depth, recent trades, and OHLCV candlestick data. Here's a complete example that fetches the current BTC/USDT price and the last 10 hourly candles:
require('dotenv').config();
const { Spot } = require('@binance/connector');
const client = new Spot(
process.env.BINANCE_API_KEY,
process.env.BINANCE_API_SECRET
);
async function getMarketData() {
try {
// Current price
const tickerRes = await client.tickerPrice('BTCUSDT');
console.log('BTC Price:', tickerRes.data.price);
// Last 10 hourly candles (OHLCV)
const candleRes = await client.klines('BTCUSDT', '1h', { limit: 10 });
const candles = candleRes.data.map(c => ({
openTime: new Date(c[0]).toISOString(),
open: parseFloat(c[1]),
high: parseFloat(c[2]),
low: parseFloat(c[3]),
close: parseFloat(c[4]),
volume: parseFloat(c[5])
}));
console.log('Last 10 candles:', candles);
// Order book depth
const depthRes = await client.depth('BTCUSDT', { limit: 5 });
console.log('Top 5 bids:', depthRes.data.bids);
console.log('Top 5 asks:', depthRes.data.asks);
} catch (err) {
console.error('API Error:', err.response?.data || err.message);
}
}
getMarketData();
The candle array from Binance returns raw arrays where each index corresponds to open time, open, high, low, close, volume, and several other fields. Always parse these as floats — they come back as strings. The klines endpoint is the backbone of any technical analysis system; you can pull intervals from `1m` up to `1M` (monthly).
Placing orders requires SIGNED requests — Binance adds an HMAC-SHA256 signature to your request using your API secret. The official connector handles this automatically, but it's worth understanding what's happening under the hood. Every signed request includes a `timestamp` parameter and a `signature` computed from the query string. The server rejects requests where the timestamp is more than 5 seconds old, which is why server time sync matters.
require('dotenv').config();
const { Spot } = require('@binance/connector');
const client = new Spot(
process.env.BINANCE_API_KEY,
process.env.BINANCE_API_SECRET
);
async function placeMarketOrder(symbol, side, quantity) {
try {
const order = await client.newOrder(symbol, side, 'MARKET', {
quantity: quantity
});
console.log('Order placed successfully:');
console.log(' Order ID:', order.data.orderId);
console.log(' Status:', order.data.status);
console.log(' Executed Qty:', order.data.executedQty);
console.log(' Avg Price:', order.data.fills?.[0]?.price || 'N/A');
return order.data;
} catch (err) {
const apiError = err.response?.data;
if (apiError) {
console.error(`Binance Error ${apiError.code}: ${apiError.msg}`);
// Common codes:
// -1121: Invalid symbol
// -2010: Insufficient balance
// -1100: Illegal characters in parameter
} else {
console.error('Network error:', err.message);
}
throw err;
}
}
// Buy 0.001 BTC at market price
// CAUTION: This places a REAL order on your account
// placeMarketOrder('BTCUSDT', 'BUY', '0.001');
// For testing, use Binance Testnet first:
// const client = new Spot(key, secret, { baseURL: 'https://testnet.binance.vision' });
Always test with the Binance Testnet (testnet.binance.vision) before running any order logic on mainnet. Testnet uses separate API keys — create them at testnet.binance.vision directly.
For limit orders, you supply `price` and `timeInForce` (typically `GTC` — Good Till Cancelled). Compared to platforms like Bybit and OKX which have slightly different parameter naming conventions, Binance's API documentation is more verbose but also more explicit about every field. The Binance API documentation at binance-docs.github.io is genuinely well-maintained and worth bookmarking.
REST calls are fine for placing orders, but for real-time price feeds you want WebSockets. Polling the REST API every second burns your rate limit quota fast — Binance enforces a 1200 requests-per-minute weight limit. WebSocket streams push data to you the moment it changes, with no polling overhead. The connector library includes a WebSocket client:
require('dotenv').config();
const { WebsocketStream } = require('@binance/connector');
const logger = {
info: (msg) => console.log(`[INFO] ${new Date().toISOString()} ${msg}`),
error: (msg) => console.error(`[ERROR] ${msg}`)
};
const callbacks = {
open: () => logger.info('WebSocket connected'),
close: () => logger.info('WebSocket disconnected'),
error: (err) => logger.error(`WebSocket error: ${err.message}`),
message: (data) => {
const parsed = JSON.parse(data);
// Trade stream format
if (parsed.e === 'trade') {
logger.info(`${parsed.s} Trade — Price: ${parsed.p}, Qty: ${parsed.q}`);
}
// Kline stream format
if (parsed.e === 'kline') {
const k = parsed.k;
if (k.x) { // x = true means the candle is closed
logger.info(`Closed candle — O:${k.o} H:${k.h} L:${k.l} C:${k.c} V:${k.v}`);
}
}
}
};
const wsClient = new WebsocketStream({ logger, callbacks });
// Subscribe to BTC/USDT trade stream
wsClient.trade('btcusdt');
// Subscribe to 1-minute kline stream
wsClient.kline('btcusdt', '1m');
// Graceful shutdown
process.on('SIGINT', () => {
logger.info('Shutting down...');
wsClient.disconnect();
process.exit(0);
});
The `x` field on kline messages is key — it tells you whether the candle has closed. Most strategies should only trigger on closed candles to avoid acting on incomplete data. For multi-asset monitoring, you can subscribe to multiple streams simultaneously. Binance supports combined streams via a single WebSocket connection, which is more efficient than opening one connection per symbol.
Platforms like VoiceOfChain take a similar approach — processing real-time streams across multiple exchanges to surface trading signals before they become obvious to manual traders. If you're building signal detection logic, real-time WebSocket data is the foundation.
The single biggest mistake developers make with the Binance API is ignoring rate limits until they get banned. Binance uses a weight system — each endpoint costs a certain number of 'weight' points, and you're capped at 1200 per minute for most endpoints. The `/api/v3/depth` endpoint with `limit=5000` costs 250 weight by itself. Check your current usage by reading the `X-MBX-USED-WEIGHT-1M` response header.
| Endpoint | Method | Weight | Use Case |
|---|---|---|---|
| /api/v3/ticker/price | GET | 1 (single), 2 (all) | Current price |
| /api/v3/klines | GET | 1 | Candlestick data |
| /api/v3/depth | GET | 1-50 (by limit) | Order book |
| /api/v3/order | POST | 1 | Place order |
| /api/v3/account | GET | 10 | Account balance |
| /api/v3/exchangeInfo | GET | 10 | Symbol rules/filters |
For production bots, implement exponential backoff when you receive a 429 (rate limit) or 418 (IP ban) response. Cache `exchangeInfo` locally — it changes rarely and costs 10 weight every call. Use WebSockets for anything you'd otherwise poll more than once per minute. When comparing approaches across exchanges, Bybit's API has slightly more generous rate limits, while OKX uses a token bucket system that can be more forgiving for burst traffic — worth knowing if you're building a multi-exchange system.
The Binance API paired with Node.js gives you a genuinely capable trading infrastructure — real-time data via WebSockets, order execution with full control over parameters, and a well-documented endpoint library that covers everything from simple price lookups to complex conditional orders. The code patterns shown here — authenticated clients, WebSocket streams, proper error handling — form the skeleton of any production trading bot. Whether you're building a simple DCA bot, a signal executor that acts on alerts from platforms like VoiceOfChain, or a full algorithmic strategy, the fundamentals are the same: connect securely, stream data efficiently, handle errors explicitly, and always test on Binance Testnet before touching mainnet funds.