Binance API Documentation for Node.js: Complete Trading Guide
Master the Binance API with Node.js โ from authentication and market data to placing orders and building real-time trading bots with practical code examples.
Table of Contents
The Binance API is one of the most powerful tools available to crypto traders who want to go beyond manual clicking. Whether you're pulling real-time market data, automating trade execution, or building a full-blown trading bot, Node.js gives you the speed and flexibility to make it happen. The official Binance API documentation covers REST endpoints, WebSocket streams, and account management โ but reading raw docs and actually writing working code are two different things. This guide bridges that gap.
Setting Up Your Binance API Environment in Node.js
Before writing a single line of trading logic, you need API keys and a proper project setup. Head to your Binance account, navigate to API Management, and create a new key pair. Store your API key and secret securely โ never hardcode them into your source files. Use environment variables or a .env file with the dotenv package.
mkdir binance-trader && cd binance-trader
npm init -y
npm install axios crypto-js dotenv ws
Create a .env file in your project root with your credentials:
BINANCE_API_KEY=your_api_key_here
BINANCE_API_SECRET=your_api_secret_here
Now set up your base client. The Binance REST API requires HMAC SHA256 signatures for authenticated endpoints. Here's a reusable module that handles signing automatically:
// client.js
require('dotenv').config();
const axios = require('axios');
const crypto = require('crypto-js');
const BASE_URL = 'https://api.binance.com';
const API_KEY = process.env.BINANCE_API_KEY;
const API_SECRET = process.env.BINANCE_API_SECRET;
function sign(queryString) {
return crypto.HmacSHA256(queryString, API_SECRET).toString();
}
async function publicRequest(endpoint, params = {}) {
const query = new URLSearchParams(params).toString();
const url = `${BASE_URL}${endpoint}${query ? '?' + query : ''}`;
const { data } = await axios.get(url);
return data;
}
async function signedRequest(method, endpoint, params = {}) {
params.timestamp = Date.now();
params.recvWindow = 5000;
const queryString = new URLSearchParams(params).toString();
const signature = sign(queryString);
const url = `${BASE_URL}${endpoint}?${queryString}&signature=${signature}`;
const { data } = await axios({
method,
url,
headers: { 'X-MBX-APIKEY': API_KEY }
});
return data;
}
module.exports = { publicRequest, signedRequest };
Fetching Market Data from Binance REST API
Public endpoints don't require authentication and are your starting point for any trading strategy. The Binance API documentation lists dozens of market data endpoints, but three cover 90% of what traders need: ticker prices, order book depth, and candlestick (kline) data.
// market-data.js
const { publicRequest } = require('./client');
async function main() {
// Current price for a symbol
const ticker = await publicRequest('/api/v3/ticker/price', {
symbol: 'BTCUSDT'
});
console.log(`BTC Price: $${ticker.price}`);
// Order book depth โ top 5 bids and asks
const depth = await publicRequest('/api/v3/depth', {
symbol: 'ETHUSDT',
limit: 5
});
console.log('Best bid:', depth.bids[0]);
console.log('Best ask:', depth.asks[0]);
// Candlestick data โ last 10 hourly candles
const klines = await publicRequest('/api/v3/klines', {
symbol: 'BTCUSDT',
interval: '1h',
limit: 10
});
const formatted = klines.map(k => ({
open: parseFloat(k[1]),
high: parseFloat(k[2]),
low: parseFloat(k[3]),
close: parseFloat(k[4]),
volume: parseFloat(k[5])
}));
console.log('Recent candles:', formatted);
}
main().catch(console.error);
| Endpoint | Method | Description | Auth Required |
|---|---|---|---|
| GET /api/v3/ticker/price | GET | Current price for one or all symbols | No |
| GET /api/v3/depth | GET | Order book bids and asks | No |
| GET /api/v3/klines | GET | Candlestick/OHLCV data | No |
| GET /api/v3/ticker/24hr | GET | 24-hour rolling statistics | No |
| GET /api/v3/avgPrice | GET | 5-minute average price | No |
The klines endpoint is particularly valuable for technical analysis. Each candle returns an array of 12 values โ open time, OHLCV data, close time, quote volume, number of trades, and taker buy volumes. Parse them into objects for cleaner code downstream.
Placing Orders Through the Binance API with Node.js
This is where the Binance API documentation for Node.js gets serious. Placing orders requires signed requests, and the margin for error is thin. The /api/v3/order endpoint supports market, limit, stop-limit, and OCO order types. Let's start with the essentials.
// trading.js
const { signedRequest } = require('./client');
async function getAccountInfo() {
const account = await signedRequest('GET', '/api/v3/account');
const nonZero = account.balances.filter(
b => parseFloat(b.free) > 0 || parseFloat(b.locked) > 0
);
console.log('Balances:', nonZero);
return account;
}
async function placeLimitOrder(symbol, side, quantity, price) {
try {
const order = await signedRequest('POST', '/api/v3/order', {
symbol,
side, // 'BUY' or 'SELL'
type: 'LIMIT',
timeInForce: 'GTC',
quantity: quantity.toString(),
price: price.toString()
});
console.log(`Order placed: ${order.orderId}`, {
status: order.status,
executedQty: order.executedQty
});
return order;
} catch (err) {
const apiError = err.response?.data;
if (apiError) {
console.error(`Binance error ${apiError.code}: ${apiError.msg}`);
// Common errors:
// -1013: Filter failure (LOT_SIZE, PRICE_FILTER, MIN_NOTIONAL)
// -2010: Insufficient balance
// -1021: Timestamp outside recvWindow
} else {
console.error('Network error:', err.message);
}
throw err;
}
}
async function placeMarketOrder(symbol, side, quantity) {
const order = await signedRequest('POST', '/api/v3/order', {
symbol,
side,
type: 'MARKET',
quantity: quantity.toString()
});
console.log(`Market order filled at avg price:`,
order.fills.reduce((sum, f) => sum + parseFloat(f.price), 0) / order.fills.length
);
return order;
}
// Example usage โ uncomment to execute
// getAccountInfo();
// placeLimitOrder('BTCUSDT', 'BUY', 0.001, 60000);
// placeMarketOrder('ETHUSDT', 'BUY', 0.05);
A common mistake in the Binance API documentation for Node.js tutorials is ignoring quantity precision. Each symbol has a stepSize โ if BTC's stepSize is 0.00001, sending 0.000015 will get rejected. Always round your quantities to match the filter rules.
Real-Time Data with Binance WebSocket Streams
REST polling is fine for periodic checks, but real-time trading demands WebSocket streams. Binance offers individual streams for trades, klines, depth updates, and ticker data. The Node.js ws library makes connecting straightforward.
// websocket-stream.js
const WebSocket = require('ws');
function startTickerStream(symbol, onTick) {
const wsUrl = `wss://stream.binance.com:9443/ws/${symbol.toLowerCase()}@trade`;
const ws = new WebSocket(wsUrl);
ws.on('open', () => console.log(`Connected to ${symbol} trade stream`));
ws.on('message', (raw) => {
const trade = JSON.parse(raw);
onTick({
symbol: trade.s,
price: parseFloat(trade.p),
quantity: parseFloat(trade.q),
time: new Date(trade.T),
isBuyerMaker: trade.m
});
});
ws.on('error', (err) => console.error('WebSocket error:', err.message));
ws.on('close', () => {
console.log('Connection closed, reconnecting in 5s...');
setTimeout(() => startTickerStream(symbol, onTick), 5000);
});
return ws;
}
// Track real-time trades with a simple moving price tracker
let prices = [];
startTickerStream('BTCUSDT', (trade) => {
prices.push(trade.price);
if (prices.length > 100) prices.shift();
const avg = prices.reduce((a, b) => a + b, 0) / prices.length;
const direction = trade.isBuyerMaker ? 'SELL' : 'BUY';
process.stdout.write(
`\r${trade.symbol} ${direction} $${trade.price.toFixed(2)} | ` +
`MA(100): $${avg.toFixed(2)} | Trades tracked: ${prices.length}`
);
});
For monitoring multiple symbols simultaneously, use combined streams instead of opening separate connections. Binance allows up to 1024 streams on a single WebSocket connection:
// Combined stream for multiple symbols
const streams = ['btcusdt@ticker', 'ethusdt@ticker', 'solusdt@ticker'];
const wsUrl = `wss://stream.binance.com:9443/stream?streams=${streams.join('/')}`;
const ws = new WebSocket(wsUrl);
ws.on('message', (raw) => {
const { stream, data } = JSON.parse(raw);
console.log(`[${data.s}] Price: ${data.c} | 24h Change: ${data.P}%`);
});
Error Handling and Rate Limits in Production
The Binance API documentation specifies strict rate limits: 1200 request weight per minute for REST endpoints and 10 orders per second. Exceeding these gets you a 429 response and eventually a temporary IP ban (HTTP 418). In production Node.js applications, you need to track your usage and back off proactively.
- Each endpoint has a weight โ GET /api/v3/depth with limit=500 costs 5 weight, while limit=5000 costs 50
- Response headers include X-MBX-USED-WEIGHT-1M showing your current minute's consumption
- WebSocket connections don't count toward REST rate limits but have their own 5 messages/second limit for sending
- Implement exponential backoff: wait 1s, then 2s, then 4s on consecutive failures โ don't hammer a failing endpoint
// rate-limiter.js โ Simple rate-aware request wrapper
class RateLimiter {
constructor(maxWeight = 1100, windowMs = 60000) {
this.maxWeight = maxWeight;
this.windowMs = windowMs;
this.requests = [];
}
getCurrentWeight() {
const cutoff = Date.now() - this.windowMs;
this.requests = this.requests.filter(r => r.time > cutoff);
return this.requests.reduce((sum, r) => sum + r.weight, 0);
}
async throttle(weight = 1) {
while (this.getCurrentWeight() + weight > this.maxWeight) {
const oldestExpiry = this.requests[0].time + this.windowMs - Date.now();
console.log(`Rate limit approaching, waiting ${oldestExpiry}ms...`);
await new Promise(r => setTimeout(r, oldestExpiry + 100));
}
this.requests.push({ time: Date.now(), weight });
}
}
// Usage with your client
const limiter = new RateLimiter();
async function safeFetch(endpoint, params, weight = 1) {
await limiter.throttle(weight);
return publicRequest(endpoint, params);
}
Beyond rate limits, handle these common failure modes in your Node.js Binance API integration: network timeouts (set axios timeout to 10 seconds), clock drift causing signature errors (sync your server time with GET /api/v3/time), and exchange maintenance windows. A resilient bot handles all three gracefully.
Building a Simple Signal-Based Trading Bot
Let's tie everything together. Here's a basic structure that listens to WebSocket price data, applies a simple moving average crossover strategy, and executes trades. In practice, you'd want to combine this with signals from platforms like VoiceOfChain to validate entries with real-time on-chain data and market sentiment before executing.
// bot.js โ SMA crossover with Binance API
const { signedRequest, publicRequest } = require('./client');
const WebSocket = require('ws');
const SYMBOL = 'ETHUSDT';
const TRADE_QTY = '0.05';
const SHORT_PERIOD = 10;
const LONG_PERIOD = 30;
let closes = [];
let position = null; // 'long' | null
function sma(arr, period) {
if (arr.length < period) return null;
const slice = arr.slice(-period);
return slice.reduce((a, b) => a + b, 0) / period;
}
async function executeTrade(side) {
try {
const order = await signedRequest('POST', '/api/v3/order', {
symbol: SYMBOL, side, type: 'MARKET',
quantity: TRADE_QTY
});
console.log(`\n${side} executed: ${order.executedQty} @ avg ${
(order.fills.reduce((s, f) => s + parseFloat(f.price) * parseFloat(f.qty), 0) /
parseFloat(order.executedQty)).toFixed(2)
}`);
return order;
} catch (err) {
console.error(`Trade failed: ${err.response?.data?.msg || err.message}`);
}
}
// Listen to 1-minute kline closes
const ws = new WebSocket(
`wss://stream.binance.com:9443/ws/${SYMBOL.toLowerCase()}@kline_1m`
);
ws.on('message', async (raw) => {
const { k: kline } = JSON.parse(raw);
if (!kline.x) return; // Only act on closed candles
closes.push(parseFloat(kline.c));
if (closes.length > LONG_PERIOD + 10) closes.shift();
const shortSMA = sma(closes, SHORT_PERIOD);
const longSMA = sma(closes, LONG_PERIOD);
if (!shortSMA || !longSMA) return;
console.log(`\rSMA(${SHORT_PERIOD}): ${shortSMA.toFixed(2)} | ` +
`SMA(${LONG_PERIOD}): ${longSMA.toFixed(2)} | Position: ${position || 'none'}`);
// Crossover logic
if (shortSMA > longSMA && !position) {
await executeTrade('BUY');
position = 'long';
} else if (shortSMA < longSMA && position === 'long') {
await executeTrade('SELL');
position = null;
}
});
console.log(`Bot started on ${SYMBOL} โ SMA(${SHORT_PERIOD}/${LONG_PERIOD}) crossover`);
Key Takeaways
The Binance API documentation paired with Node.js gives you everything needed to build serious trading infrastructure. Start with public market data endpoints to get comfortable with the request patterns. Move to authenticated endpoints on testnet before risking real capital. Use WebSocket streams for anything time-sensitive โ REST polling introduces latency that can cost you on volatile moves.
The code examples in this guide are production-ready patterns, not toy demos. The signed request handler, rate limiter, and WebSocket reconnection logic are the same foundations used in real trading systems. Layer in additional signal sources โ on-chain analytics from VoiceOfChain, order flow data, or sentiment indicators โ and you have the building blocks of a genuinely useful automated trading pipeline.
One final piece of advice: read the official Binance API documentation thoroughly. It's dense but comprehensive. The changelog section is especially important โ Binance regularly updates endpoints, deprecates old versions, and adjusts rate limits. Your Node.js integration is only as reliable as your understanding of what the API actually guarantees.