Apidog

All-in-one Collaborative API Development Platform

API Design

API Documentation

API Debugging

API Mocking

API Automated Testing

How to Use Binance API with Python

This tutorial will guide you through the process of using the Binance API, from setting up authentication to making various types of requests.

Mark Ponomarev

Mark Ponomarev

Updated on March 28, 2025

Introduction to Binance API

The Binance API provides developers with programmatic access to Binance's trading platform, allowing them to build trading bots, applications, and tools that interact with the exchange. This tutorial will guide you through the process of using the Binance API, from setting up authentication to making various types of requests.

While many developers have traditionally relied on Postman for API testing, Apidog offers a more streamlined and specialized experience for working with cryptocurrency APIs like Binance. With its intuitive interface, enhanced authentication handling, and built-in crypto-specific features, Apidog significantly reduces the setup time needed to begin testing and implementing Binance API endpoints.

button

The platform's real-time collaboration tools and comprehensive documentation generation capabilities make it particularly valuable for teams working on crypto trading applications.

If you're serious about efficient Binance API integration, making the switch to Apidog will notably improve your development workflow and reduce time-to-deployment for your crypto projects.

button

Setting Up Binance API Authentication

Before using the Binance API, you need to create API keys from your Binance account. This section covers how to set up and secure your API keys.

Creating Binance API Keys

  1. Log in to your Binance account
  2. Navigate to "API Management" in your account settings
  3. Create a new API key
  4. Note down your API key and secret key
  5. Configure restrictions (IP whitelisting, trading permissions, etc.)

Types of API Keys Supported by Binance API

Binance supports three types of API key authentication methods:

  1. HMAC Keys - The most common authentication method
  2. RSA Keys - Offers enhanced security features
  3. Ed25519 Keys - Provides the best performance and security

HMAC Authentication Example

Here's how to authenticate with HMAC keys:

import hmac
import hashlib
import time
import requests
from urllib.parse import urlencode

# API credentials
api_key = 'your_api_key'
api_secret = 'your_api_secret'

# Base URL for Binance API
base_url = '<https://api.binance.com>'

# Function to create a signature for authenticated endpoints
def get_signature(query_string):
    return hmac.new(
        api_secret.encode('utf-8'),
        query_string.encode('utf-8'),
        hashlib.sha256
    ).hexdigest()

# Example request to get account information
def get_account():
    endpoint = '/api/v3/account'
    timestamp = int(time.time() * 1000)

    params = {
        'timestamp': timestamp,
        'recvWindow': 5000  # Optional parameter
    }

    query_string = urlencode(params)
    signature = get_signature(query_string)

    url = f"{base_url}{endpoint}?{query_string}&signature={signature}"

    headers = {
        'X-MBX-APIKEY': api_key
    }

    response = requests.get(url, headers=headers)
    return response.json()

# Call the function
account_info = get_account()
print(account_info)

Understanding Binance API Endpoints

The Binance API is organized into several categories of endpoints based on their functionality.

General Binance API Endpoints

These endpoints provide general information about the exchange:

# Test connectivity
def test_connectivity():
    endpoint = '/api/v3/ping'
    url = f"{base_url}{endpoint}"
    response = requests.get(url)
    return response.json()

# Get server time
def get_server_time():
    endpoint = '/api/v3/time'
    url = f"{base_url}{endpoint}"
    response = requests.get(url)
    return response.json()

# Get exchange information
def get_exchange_info():
    endpoint = '/api/v3/exchangeInfo'
    url = f"{base_url}{endpoint}"
    response = requests.get(url)
    return response.json()

Market Data Binance API Endpoints

These endpoints provide access to market data:

# Get order book for a symbol
def get_order_book(symbol, limit=100):
    endpoint = '/api/v3/depth'
    params = {
        'symbol': symbol,
        'limit': limit
    }
    url = f"{base_url}{endpoint}?{urlencode(params)}"
    response = requests.get(url)
    return response.json()

# Get recent trades
def get_recent_trades(symbol, limit=500):
    endpoint = '/api/v3/trades'
    params = {
        'symbol': symbol,
        'limit': limit
    }
    url = f"{base_url}{endpoint}?{urlencode(params)}"
    response = requests.get(url)
    return response.json()

# Get candlestick data
def get_klines(symbol, interval, start_time=None, end_time=None, limit=500):
    endpoint = '/api/v3/klines'
    params = {
        'symbol': symbol,
        'interval': interval,
        'limit': limit
    }

    if start_time:
        params['startTime'] = start_time
    if end_time:
        params['endTime'] = end_time

    url = f"{base_url}{endpoint}?{urlencode(params)}"
    response = requests.get(url)

    # Format the response
    klines = response.json()
    formatted_klines = []
    for k in klines:
        formatted_klines.append({
            'open_time': k[0],
            'open': float(k[1]),
            'high': float(k[2]),
            'low': float(k[3]),
            'close': float(k[4]),
            'volume': float(k[5]),
            'close_time': k[6],
            'quote_volume': float(k[7]),
            'trades': k[8],
            'taker_buy_base_volume': float(k[9]),
            'taker_buy_quote_volume': float(k[10])
        })

    return formatted_klines

Trading with Binance API

The trading endpoints allow you to place and manage orders.

Placing Orders with Binance API

Here's how to place different types of orders:

# Place a LIMIT order
def place_limit_order(symbol, side, quantity, price):
    endpoint = '/api/v3/order'
    timestamp = int(time.time() * 1000)

    params = {
        'symbol': symbol,
        'side': side,  # 'BUY' or 'SELL'
        'type': 'LIMIT',
        'timeInForce': 'GTC',  # Good Till Canceled
        'quantity': quantity,
        'price': price,
        'timestamp': timestamp,
        'recvWindow': 5000
    }

    query_string = urlencode(params)
    signature = get_signature(query_string)

    url = f"{base_url}{endpoint}?{query_string}&signature={signature}"

    headers = {
        'X-MBX-APIKEY': api_key
    }

    response = requests.post(url, headers=headers)
    return response.json()

# Place a MARKET order
def place_market_order(symbol, side, quantity):
    endpoint = '/api/v3/order'
    timestamp = int(time.time() * 1000)

    params = {
        'symbol': symbol,
        'side': side,  # 'BUY' or 'SELL'
        'type': 'MARKET',
        'quantity': quantity,
        'timestamp': timestamp,
        'recvWindow': 5000
    }

    query_string = urlencode(params)
    signature = get_signature(query_string)

    url = f"{base_url}{endpoint}?{query_string}&signature={signature}"

    headers = {
        'X-MBX-APIKEY': api_key
    }

    response = requests.post(url, headers=headers)
    return response.json()

# Place a STOP_LOSS order
def place_stop_loss_order(symbol, side, quantity, stop_price):
    endpoint = '/api/v3/order'
    timestamp = int(time.time() * 1000)

    params = {
        'symbol': symbol,
        'side': side,
        'type': 'STOP_LOSS',
        'quantity': quantity,
        'stopPrice': stop_price,
        'timestamp': timestamp,
        'recvWindow': 5000
    }

    query_string = urlencode(params)
    signature = get_signature(query_string)

    url = f"{base_url}{endpoint}?{query_string}&signature={signature}"

    headers = {
        'X-MBX-APIKEY': api_key
    }

    response = requests.post(url, headers=headers)
    return response.json()

Managing Orders with Binance API

Here's how to query, cancel, and track orders:

# Query order status
def query_order(symbol, order_id=None, orig_client_order_id=None):
    endpoint = '/api/v3/order'
    timestamp = int(time.time() * 1000)

    params = {
        'symbol': symbol,
        'timestamp': timestamp,
        'recvWindow': 5000
    }

    if order_id:
        params['orderId'] = order_id
    elif orig_client_order_id:
        params['origClientOrderId'] = orig_client_order_id
    else:
        raise ValueError("Either order_id or orig_client_order_id must be provided")

    query_string = urlencode(params)
    signature = get_signature(query_string)

    url = f"{base_url}{endpoint}?{query_string}&signature={signature}"

    headers = {
        'X-MBX-APIKEY': api_key
    }

    response = requests.get(url, headers=headers)
    return response.json()

# Cancel an order
def cancel_order(symbol, order_id=None, orig_client_order_id=None):
    endpoint = '/api/v3/order'
    timestamp = int(time.time() * 1000)

    params = {
        'symbol': symbol,
        'timestamp': timestamp,
        'recvWindow': 5000
    }

    if order_id:
        params['orderId'] = order_id
    elif orig_client_order_id:
        params['origClientOrderId'] = orig_client_order_id
    else:
        raise ValueError("Either order_id or orig_client_order_id must be provided")

    query_string = urlencode(params)
    signature = get_signature(query_string)

    url = f"{base_url}{endpoint}?{query_string}&signature={signature}"

    headers = {
        'X-MBX-APIKEY': api_key
    }

    response = requests.delete(url, headers=headers)
    return response.json()

# Get all open orders
def get_open_orders(symbol=None):
    endpoint = '/api/v3/openOrders'
    timestamp = int(time.time() * 1000)

    params = {
        'timestamp': timestamp,
        'recvWindow': 5000
    }

    if symbol:
        params['symbol'] = symbol

    query_string = urlencode(params)
    signature = get_signature(query_string)

    url = f"{base_url}{endpoint}?{query_string}&signature={signature}"

    headers = {
        'X-MBX-APIKEY': api_key
    }

    response = requests.get(url, headers=headers)
    return response.json()

Account and User Data with Binance API

These endpoints allow you to access account information and stream user data.

Account Information with Binance API

# Get account information
def get_account_information():
    endpoint = '/api/v3/account'
    timestamp = int(time.time() * 1000)

    params = {
        'timestamp': timestamp,
        'recvWindow': 5000
    }

    query_string = urlencode(params)
    signature = get_signature(query_string)

    url = f"{base_url}{endpoint}?{query_string}&signature={signature}"

    headers = {
        'X-MBX-APIKEY': api_key
    }

    response = requests.get(url, headers=headers)
    return response.json()

# Get account trade list
def get_account_trades(symbol, start_time=None, end_time=None, limit=500):
    endpoint = '/api/v3/myTrades'
    timestamp = int(time.time() * 1000)

    params = {
        'symbol': symbol,
        'timestamp': timestamp,
        'limit': limit,
        'recvWindow': 5000
    }

    if start_time:
        params['startTime'] = start_time
    if end_time:
        params['endTime'] = end_time

    query_string = urlencode(params)
    signature = get_signature(query_string)

    url = f"{base_url}{endpoint}?{query_string}&signature={signature}"

    headers = {
        'X-MBX-APIKEY': api_key
    }

    response = requests.get(url, headers=headers)
    return response.json()

User Data Streams with Binance API

# Start a user data stream
def start_user_data_stream():
    endpoint = '/api/v3/userDataStream'

    headers = {
        'X-MBX-APIKEY': api_key
    }

    response = requests.post(f"{base_url}{endpoint}", headers=headers)
    return response.json()

# Keep alive a user data stream
def keep_alive_user_data_stream(listen_key):
    endpoint = '/api/v3/userDataStream'

    params = {
        'listenKey': listen_key
    }

    headers = {
        'X-MBX-APIKEY': api_key
    }

    response = requests.put(f"{base_url}{endpoint}?{urlencode(params)}", headers=headers)
    return response.json()

# Close a user data stream
def close_user_data_stream(listen_key):
    endpoint = '/api/v3/userDataStream'

    params = {
        'listenKey': listen_key
    }

    headers = {
        'X-MBX-APIKEY': api_key
    }

    response = requests.delete(f"{base_url}{endpoint}?{urlencode(params)}", headers=headers)
    return response.json()

Advanced Binance API Features

This section covers some of the more advanced features of the Binance API.

Working with Order Lists (OCO) in Binance API

One-Cancels-the-Other (OCO) orders allow you to place a pair of orders where if one gets triggered, the other is automatically canceled:

# Place an OCO order
def place_oco_order(symbol, side, quantity, price, stop_price):
    endpoint = '/api/v3/orderList/oco'
    timestamp = int(time.time() * 1000)

    params = {
        'symbol': symbol,
        'side': side,
        'quantity': quantity,
        'price': price,
        'stopPrice': stop_price,
        'timestamp': timestamp,
        'recvWindow': 5000
    }

    # Define the types for the OCO order based on side
    if side == 'SELL':
        params['aboveType'] = 'STOP_LOSS'
        params['belowType'] = 'LIMIT_MAKER'
    else:
        params['aboveType'] = 'LIMIT_MAKER'
        params['belowType'] = 'STOP_LOSS'

    params['aboveTimeInForce'] = 'GTC'
    params['belowTimeInForce'] = 'GTC'

    query_string = urlencode(params)
    signature = get_signature(query_string)

    url = f"{base_url}{endpoint}?{query_string}&signature={signature}"

    headers = {
        'X-MBX-APIKEY': api_key
    }

    response = requests.post(url, headers=headers)
    return response.json()

Handling Rate Limits in Binance API

Binance applies rate limits to API requests. Here's how to handle them:

import time
from functools import wraps

# Decorator to handle rate limits
def handle_rate_limit(max_retries=3, retry_delay=30):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            retries = 0
            while retries <= max_retries:
                try:
                    response = func(*args, **kwargs)
                    if 'code' in response and response['code'] == -1429:  # Rate limit exceeded
                        retries += 1
                        if retries > max_retries:
                            raise Exception(f"Rate limit exceeded after {max_retries} retries")
                        print(f"Rate limit exceeded. Waiting {retry_delay} seconds before retry...")
                        time.sleep(retry_delay)
                    else:
                        return response
                except Exception as e:
                    if "429" in str(e) or "418" in str(e):
                        retries += 1
                        if retries > max_retries:
                            raise
                        print(f"Rate limit exceeded. Waiting {retry_delay} seconds before retry...")
                        time.sleep(retry_delay)
                    else:
                        raise
        return wrapper
    return decorator

# Example usage
@handle_rate_limit()
def get_exchange_info_with_retry():
    endpoint = '/api/v3/exchangeInfo'
    url = f"{base_url}{endpoint}"
    response = requests.get(url)
    return response.json()

Building a Complete Binance API Trading Bot

Now let's put everything together to build a simple trading bot:

import hmac
import hashlib
import time
import requests
import json
import websocket
import threading
from urllib.parse import urlencode

class BinanceTrader:
    def __init__(self, api_key, api_secret, symbol='BTCUSDT'):
        self.api_key = api_key
        self.api_secret = api_secret
        self.base_url = '<https://api.binance.com>'
        self.symbol = symbol
        self.ws = None
        self.listen_key = None
        self.keep_alive_thread = None

    def get_signature(self, query_string):
        return hmac.new(
            self.api_secret.encode('utf-8'),
            query_string.encode('utf-8'),
            hashlib.sha256
        ).hexdigest()

    def get_server_time(self):
        endpoint = '/api/v3/time'
        response = requests.get(f"{self.base_url}{endpoint}")
        return response.json()['serverTime']

    def get_account_info(self):
        endpoint = '/api/v3/account'
        timestamp = int(time.time() * 1000)

        params = {
            'timestamp': timestamp,
            'recvWindow': 5000
        }

        query_string = urlencode(params)
        signature = self.get_signature(query_string)

        url = f"{self.base_url}{endpoint}?{query_string}&signature={signature}"

        headers = {
            'X-MBX-APIKEY': self.api_key
        }

        response = requests.get(url, headers=headers)
        return response.json()

    def place_market_order(self, side, quantity):
        endpoint = '/api/v3/order'
        timestamp = int(time.time() * 1000)

        params = {
            'symbol': self.symbol,
            'side': side,
            'type': 'MARKET',
            'quantity': quantity,
            'timestamp': timestamp,
            'recvWindow': 5000
        }

        query_string = urlencode(params)
        signature = self.get_signature(query_string)

        url = f"{self.base_url}{endpoint}?{query_string}&signature={signature}"

        headers = {
            'X-MBX-APIKEY': self.api_key
        }

        response = requests.post(url, headers=headers)
        return response.json()

    def start_user_data_stream(self):
        endpoint = '/api/v3/userDataStream'

        headers = {
            'X-MBX-APIKEY': self.api_key
        }

        response = requests.post(f"{self.base_url}{endpoint}", headers=headers)
        self.listen_key = response.json()['listenKey']
        return self.listen_key

    def keep_alive_user_data_stream(self):
        while True:
            if self.listen_key:
                endpoint = '/api/v3/userDataStream'

                params = {
                    'listenKey': self.listen_key
                }

                headers = {
                    'X-MBX-APIKEY': self.api_key
                }

                requests.put(f"{self.base_url}{endpoint}?{urlencode(params)}", headers=headers)
            time.sleep(30 * 60)  # Keep alive every 30 minutes

    def on_message(self, ws, message):
        data = json.loads(message)

        # Handle account updates
        if data.get('e') == 'outboundAccountPosition':
            print("Account update received:")
            print(f"Update time: {data['u']}")
            print("Balances:")
            for balance in data['B']:
                print(f"Asset: {balance['a']}, Free: {balance['f']}, Locked: {balance['l']}")

        # Handle order updates
        elif data.get('e') == 'executionReport':
            print("Order update received:")
            print(f"Symbol: {data['s']}")
            print(f"Side: {data['S']}")
            print(f"Order type: {data['o']}")
            print(f"Order status: {data['X']}")
            print(f"Price: {data['p']}")
            print(f"Quantity: {data['q']}")
            print(f"Executed quantity: {data['z']}")

            # Implement trading logic here based on order updates
            if data['X'] == 'FILLED' and data['S'] == 'BUY':
                # Example: Place a sell order when buy is filled
                sell_price = float(data['p']) * 1.05  # 5% profit target
                self.place_limit_order('SELL', data['q'], sell_price)

    def on_error(self, ws, error):
        print(f"Error: {error}")

    def on_close(self, ws, close_status_code, close_msg):
        print("WebSocket connection closed")

    def on_open(self, ws):
        print("WebSocket connection opened")

    def start_websocket(self):
        self.start_user_data_stream()
        socket_url = f"wss://stream.binance.com:9443/ws/{self.listen_key}"

        self.ws = websocket.WebSocketApp(
            socket_url,
            on_message=self.on_message,
            on_error=self.on_error,
            on_close=self.on_close,
            on_open=self.on_open
        )

        # Start keep-alive thread
        self.keep_alive_thread = threading.Thread(target=self.keep_alive_user_data_stream)
        self.keep_alive_thread.daemon = True
        self.keep_alive_thread.start()

        # Run the WebSocket in a separate thread
        ws_thread = threading.Thread(target=self.ws.run_forever)
        ws_thread.daemon = True
        ws_thread.start()

        return ws_thread

# Example usage
if __name__ == "__main__":
    api_key = "your_api_key"
    api_secret = "your_api_secret"

    trader = BinanceTrader(api_key, api_secret, 'BTCUSDT')

    # Get account information
    account_info = trader.get_account_info()
    print("Account Information:")
    print(f"Can Trade: {account_info['canTrade']}")
    print(f"Can Withdraw: {account_info['canWithdraw']}")
    print(f"Can Deposit: {account_info['canDeposit']}")

    # Print balances
    print("\\\\nBalances:")
    for balance in account_info['balances']:
        if float(balance['free']) > 0 or float(balance['locked']) > 0:
            print(f"Asset: {balance['asset']}, Free: {balance['free']}, Locked: {balance['locked']}")

    # Start the WebSocket for real-time updates
    ws_thread = trader.start_websocket()

    try:
        # Keep the main thread running
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        print("Stopping...")
        trader.ws.close()

Best Practices for Using Binance API

Here are some best practices to follow when working with the Binance API:

Security Practices for Binance API

  1. Restrict API Key Permissions: Only enable the permissions you need (e.g., read-only, trading, withdrawals)
  2. Whitelist IP Addresses: Restrict your API keys to only work from specific IP addresses
  3. Secure API Key Storage: Never hardcode API keys in your code, use environment variables or secure vaults
  4. Regular Key Rotation: Change your API keys periodically to mitigate risk
import os

# Load API keys from environment variables
api_key = os.environ.get('BINANCE_API_KEY')
api_secret = os.environ.get('BINANCE_API_SECRET')

if not api_key or not api_secret:
    raise ValueError("API keys not found in environment variables")

Error Handling with Binance API

Implement robust error handling to deal with API errors and connection issues:

def safe_request(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        try:
            response = func(*args, **kwargs)
            # Check for API error codes
            if isinstance(response, dict) and 'code' in response:
                print(f"API Error: Code {response['code']}, Message: {response.get('msg', 'No message')}")
                # Handle specific error codes
                if response['code'] == -1021:  # INVALID_TIMESTAMP
                    print("Server and local time are not synchronized. Adjusting timestamp...")
                    # Implement timestamp adjustment logic here
                elif response['code'] == -2010:  # INSUFFICIENT_BALANCE
                    print("Insufficient balance for order.")
                # Add more specific error handling as needed
            return response
        except requests.exceptions.RequestException as e:
            print(f"Request Error: {e}")
            # Implement retry logic or fallback behavior
            return None
        except json.JSONDecodeError:
            print("Failed to decode JSON response")
            return None
        except Exception as e:
            print(f"Unexpected error: {e}")
            return None
    return wrapper

@safe_request
def get_account_info_safe():
    # Implementation of get_account_info with proper error handling
    # ...

Conclusion

The Binance API offers a powerful way to interact with the Binance exchange programmatically. This tutorial covered the essential aspects of using the API, from authentication to placing orders and managing your account. By following best practices and implementing proper error handling, you can build robust applications and trading bots that leverage Binance's extensive feature set.

Remember to keep your API keys secure, respect the rate limits, and thoroughly test your code in a test environment before using it with real funds. As Binance updates their API, make sure to stay informed about any changes to the endpoints or parameters to ensure your applications continue to function correctly.

With the knowledge gained from this tutorial, you should be well-equipped to start building your own trading tools and applications using the Binance API.

button

Lovable 2.0 Free Limits and How to Use It for Free: Exploring Open-Source AlternativeViewpoint

Lovable 2.0 Free Limits and How to Use It for Free: Exploring Open-Source Alternative

Discover Lovable’s free limits and learn how to use it effectively with open-source alternatives like GPT Engineer.

Ashley Innocent

April 25, 2025

Lovable Pricing BreakdownViewpoint

Lovable Pricing Breakdown

Explore Lovable pricing in this technical guide to Lovable 2.0 plans. Learn how the Pro and Teams plans enhance development with multiplayer collaboration, security scanning, and more.

Ashley Innocent

April 25, 2025

What's New with Lovable 2.0 Features: Better for Vibe Coding?Viewpoint

What's New with Lovable 2.0 Features: Better for Vibe Coding?

Discover what’s new with Lovable 2.0 features, including multiplayer collaboration, a smarter chat mode agent, and enhanced security for vibe coding. Learn how Lovable 2.0 streamlines app development with AI-driven tools, visual edits, and custom domains for beginners and pros alike.

Ashley Innocent

April 25, 2025