Skip to main content

Public WebSocket API for Binance

Last Updated: 2024-12-09

General API Information

  • The base endpoint is: wss://ws-api.binance.com:443/ws-api/v3.
    • If you experience issues with the standard 443 port, alternative port 9443 is also available.
    • The base endpoint for testnet is: wss://testnet.binance.vision/ws-api/v3
  • A single connection to the API is only valid for 24 hours; expect to be disconnected after the 24-hour mark.
  • Websocket server will send a ping frame every 3 minutes.
    • If the websocket server does not receive a pong frame back from the connection within a 10 minute period, the connection will be disconnected.
    • When you receive a ping, you must send a pong with a copy of ping's payload as soon as possible.
    • Unsolicited pong frames are allowed, but will not prevent disconnection. It is recommended that the payload for these pong frames are empty.
  • Lists are returned in chronological order, unless noted otherwise.
  • All timestamps are in milliseconds in UTC, unless noted otherwise.
  • All field names and values are case-sensitive, unless noted otherwise.

Request format

Requests must be sent as JSON in text frames, one request per frame.

Example of request:

{
"id": "e2a85d9f-07a5-4f94-8d5f-789dc3deb097",
"method": "order.place",
"params": {
"symbol": "BTCUSDT",
"side": "BUY",
"type": "LIMIT",
"price": "0.1",
"quantity": "10",
"timeInForce": "GTC",
"timestamp": 1655716096498,
"apiKey": "T59MTDLWlpRW16JVeZ2Nju5A5C98WkMm8CSzWC4oqynUlTm1zXOxyauT8LmwXEv9",
"signature": "5942ad337e6779f2f4c62cd1c26dba71c91514400a24990a3e7f5edec9323f90"
}
}

Request fields:

NameTypeMandatoryDescription
idINT / STRING / nullYESArbitrary ID used to match responses to requests
methodSTRINGYESRequest method name
paramsOBJECTNORequest parameters. May be omitted if there are no parameters
  • Request id is truly arbitrary. You can use UUIDs, sequential IDs, current timestamp, etc. The server does not interpret id in any way, simply echoing it back in the response.

    You can freely reuse IDs within a session. However, be careful to not send more than one request at a time with the same ID, since otherwise it might be impossible to tell the responses apart.

  • Request method names may be prefixed with explicit version: e.g., "v3/order.place".

  • The order of params is not significant.

Response format

Responses are returned as JSON in text frames, one response per frame.

Example of successful response:

{
"id": "e2a85d9f-07a5-4f94-8d5f-789dc3deb097",
"status": 200,
"result": {
"symbol": "BTCUSDT",
"orderId": 12510053279,
"orderListId": -1,
"clientOrderId": "a097fe6304b20a7e4fc436",
"transactTime": 1655716096505,
"price": "0.10000000",
"origQty": "10.00000000",
"executedQty": "0.00000000",
"origQuoteOrderQty": "0.000000",
"cummulativeQuoteQty": "0.00000000",
"status": "NEW",
"timeInForce": "GTC",
"type": "LIMIT",
"side": "BUY",
"workingTime": 1655716096505,
"selfTradePreventionMode": "NONE"
},
"rateLimits": [
{
"rateLimitType": "ORDERS",
"interval": "SECOND",
"intervalNum": 10,
"limit": 50,
"count": 12
},
{
"rateLimitType": "ORDERS",
"interval": "DAY",
"intervalNum": 1,
"limit": 160000,
"count": 4043
},
{
"rateLimitType": "REQUEST_WEIGHT",
"interval": "MINUTE",
"intervalNum": 1,
"limit": 6000,
"count": 321
}
]
}

Example of failed response:

{
"id": "e2a85d9f-07a5-4f94-8d5f-789dc3deb097",
"status": 400,
"error": {
"code": -2010,
"msg": "Account has insufficient balance for requested action."
},
"rateLimits": [
{
"rateLimitType": "ORDERS",
"interval": "SECOND",
"intervalNum": 10,
"limit": 50,
"count": 13
},
{
"rateLimitType": "ORDERS",
"interval": "DAY",
"intervalNum": 1,
"limit": 160000,
"count": 4044
},
{
"rateLimitType": "REQUEST_WEIGHT",
"interval": "MINUTE",
"intervalNum": 1,
"limit": 6000,
"count": 322
}
]
}

Response fields:

Name Type Mandatory Description
id INT / STRING / null YES Same as in the original request
status INT YES Response status. See Status codes
result OBJECT / ARRAY YES Response content. Present if request succeeded
error OBJECT Error description. Present if request failed
rateLimits ARRAY NO Rate limiting status. See Rate limits

Status codes

Status codes in the status field are the same as in HTTP.

Here are some common status codes that you might encounter:

  • 200 indicates a successful response.
  • 4XX status codes indicate invalid requests; the issue is on your side.
    • 400 – your request failed, see error for the reason.
    • 403 – you have been blocked by the Web Application Firewall.
    • 409 – your request partially failed but also partially succeeded, see error for details.
    • 418 – you have been auto-banned for repeated violation of rate limits.
    • 429 – you have exceeded API request rate limit, please slow down.
  • 5XX status codes indicate internal errors; the issue is on Binance's side.
    • Important: If a response contains 5xx status code, it does not necessarily mean that your request has failed. Execution status is unknown and the request might have actually succeeded. Please use query methods to confirm the status. You might also want to establish a new WebSocket connection for that.

See Error codes for Binance for a list of error codes and messages.

Event format

User Data Stream events for non-SBE sessions are sent as JSON in text frames, one event per frame.

Events in SBE sessions will be sent as binary frames.

Please refer to userDataStream.subscribe for details on how to subscribe to User Data Stream in WebSocket API.

Example of an event:

{
"event": {
"e": "outboundAccountPosition",
"E": 1728972148778,
"u": 1728972148778,
"B": [
{
"a": "ABC",
"f": "11818.00000000",
"l": "182.00000000"
},
{
"a": "DEF",
"f": "10580.00000000",
"l": "70.00000000"
}
]
}
}

Event fields:

NameTypeMandatoryDescription
eventOBJECTYESEvent payload. See User Data Streams

Rate limits

Connection limits

There is a limit of 300 connections per attempt every 5 minutes.

The connection is per IP address.

General information on rate limits

  • Current API rate limits can be queried using the exchangeInfo request.
  • There are multiple rate limit types across multiple intervals.
  • Responses can indicate current rate limit status in the optional rateLimits field.
  • Requests fail with status 429 when unfilled order count or request rate limits are violated.

How to interpret rate limits

A response with rate limit status may look like this:

{
"id": "7069b743-f477-4ae3-81db-db9b8df085d2",
"status": 200,
"result": {
"serverTime": 1656400526260
},
"rateLimits": [
{
"rateLimitType": "REQUEST_WEIGHT",
"interval": "MINUTE",
"intervalNum": 1,
"limit": 6000,
"count": 70
}
]
}

The rateLimits array describes all currently active rate limits affected by the request.

NameTypeMandatoryDescription
rateLimitTypeENUMYESRate limit type: REQUEST_WEIGHT, ORDERS
intervalENUMYESRate limit interval: SECOND, MINUTE, HOUR, DAY
intervalNumINTYESRate limit interval multiplier
limitINTYESRequest limit per interval
countINTYESCurrent usage per interval

Rate limits are accounted by intervals.

For example, a 1 MINUTE interval starts every minute. Request submitted at 00:01:23.456 counts towards the 00:01:00 minute's limit. Once the 00:02:00 minute starts, the count will reset to zero again.

Other intervals behave in a similar manner. For example, 1 DAY rate limit resets at 00:00 UTC every day, and 10 SECOND interval resets at 00, 10, 20... seconds of each minute.

APIs have multiple rate-limiting intervals. If you exhaust a shorter interval but the longer interval still allows requests, you will have to wait for the shorter interval to expire and reset. If you exhaust a longer interval, you will have to wait for that interval to reset, even if shorter rate limit count is zero.

How to show/hide rate limit information

rateLimits field is included with every response by default.

However, rate limit information can be quite bulky. If you are not interested in detailed rate limit status of every request, the rateLimits field can be omitted from responses to reduce their size.

  • Optional returnRateLimits boolean parameter in request.

    Use returnRateLimits parameter to control whether to include rateLimits fields in response to individual requests.

    Default request and response:

    {"id":1,"method":"time"}
    {"id":1,"status":200,"result":{"serverTime":1656400526260},"rateLimits":[{"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":6000,"count":70}]}

    Request and response without rate limit status:

    {"id":2,"method":"time","params":{"returnRateLimits":false}}
    {"id":2,"status":200,"result":{"serverTime":1656400527891}}
  • Optional returnRateLimits boolean parameter in connection URL.

    If you wish to omit rateLimits from all responses by default, use returnRateLimits parameter in the query string instead:

    wss://ws-api.binance.com:443/ws-api/v3?returnRateLimits=false

    This will make all requests made through this connection behave as if you have passed "returnRateLimits": false.

    If you want to see rate limits for a particular request, you need to explicitly pass the "returnRateLimits": true parameter.

Note: Your requests are still rate limited if you hide the rateLimits field in responses.

IP limits

  • Every request has a certain weight, added to your limit as you perform requests.
    • The heavier the request (e.g. querying data from multiple symbols), the more weight the request will cost.
    • Connecting to WebSocket API costs 2 weight.
  • Current weight usage is indicated by the REQUEST_WEIGHT rate limit type.
  • Use the exchangeInfo request to keep track of the current weight limits.
  • Weight is accumulated per IP address and is shared by all connections from that address.
  • If you go over the weight limit, requests fail with status 429.
    • This status code indicates you should back off and stop spamming the API.
    • Rate-limited responses include a retryAfter field, indicating when you can retry the request.
  • Repeatedly violating rate limits and/or failing to back off after receiving 429s will result in an automated IP ban and you will be disconnected.
    • Requests from a banned IP address fail with status 418.
    • retryAfter field indicates the timestamp when the ban will be lifted.
  • IP bans are tracked and scale in duration for repeat offenders, from 2 minutes to 3 days.

Successful response indicating that in 1 minute you have used 70 weight out of your 6000 limit:

{
"id": "7069b743-f477-4ae3-81db-db9b8df085d2",
"status": 200,
"result": [],
"rateLimits": [
{
"rateLimitType": "REQUEST_WEIGHT",
"interval": "MINUTE",
"intervalNum": 1,
"limit": 6000,
"count": 70
}
]
}

Failed response indicating that you are banned and the ban will last until epoch 1659146400000:

{
"id": "fc93a61a-a192-4cf4-bb2a-a8f0f0c51e06",
"status": 418,
"error": {
"code": -1003,
"msg": "Way too much request weight used; IP banned until 1659146400000. Please use WebSocket Streams for live updates to avoid bans.",
"data": {
"serverTime": 1659142907531,
"retryAfter": 1659146400000
}
},
"rateLimits": [
{
"rateLimitType": "REQUEST_WEIGHT",
"interval": "MINUTE",
"intervalNum": 1,
"limit": 6000,
"count": 2411
}
]
}

Unfilled Order Count

  • Successfully placed orders update the ORDERS rate limit type.
  • Rejected or unsuccessful orders might or might not update the ORDERS rate limit type.
  • Please note that if your orders are consistently filled by trades, you can continuously place orders on the API. For more information, please see Spot Unfilled Order Count Rules.
  • Use the account.rateLimits.orders request to keep track of how many orders you have placed within this interval.
  • If you exceed this, requests fail with status 429.
    • This status code indicates you should back off and stop spamming the API.
    • Responses that have a status 429 include a retryAfter field, indicating when you can retry the request.
  • This is maintained per account and is shared by all API keys of the account.

Successful response indicating that you have placed 12 orders in 10 seconds, and 4043 orders in the past 24 hours:

{
"id": "e2a85d9f-07a5-4f94-8d5f-789dc3deb097",
"status": 200,
"result": {
"symbol": "BTCUSDT",
"orderId": 12510053279,
"orderListId": -1,
"clientOrderId": "a097fe6304b20a7e4fc436",
"transactTime": 1655716096505,
"price": "0.10000000",
"origQty": "10.00000000",
"executedQty": "0.00000000",
"origQuoteOrderQty": "0.000000",
"cummulativeQuoteQty": "0.00000000",
"status": "NEW",
"timeInForce": "GTC",
"type": "LIMIT",
"side": "BUY",
"workingTime": 1655716096505,
"selfTradePreventionMode": "NONE"
},
"rateLimits": [
{
"rateLimitType": "ORDERS",
"interval": "SECOND",
"intervalNum": 10,
"limit": 50,
"count": 12
},
{
"rateLimitType": "ORDERS",
"interval": "DAY",
"intervalNum": 1,
"limit": 160000,
"count": 4043
},
{
"rateLimitType": "REQUEST_WEIGHT",
"interval": "MINUTE",
"intervalNum": 1,
"limit": 6000,
"count": 321
}
]
}

Request security

  • Every method has a security type which determines how to call it.
    • Security type is stated next to the method name. For example, Place new order (TRADE).
    • If no security type is stated, the security type is NONE.
Security typeAPI keySignatureDescription
NONEPublic market data
TRADErequiredrequiredTrading on the exchange, placing and canceling orders
USER_DATArequiredrequiredPrivate account information, such as order status and your trading history
USER_STREAMrequiredManaging User Data Stream subscriptions
  • Secure methods require a valid API key to be specified and authenticated.
    • API keys can be created on the API Management page of your Binance account.
    • Both API key and secret key are sensitive. Never share them with anyone. If you notice unusual activity in your account, immediately revoke all the keys and contact Binance support.
  • API keys can be configured to allow access only to certain types of secure methods.
    • For example, you can have an API key with TRADE permission for trading, while using a separate API key with USER_DATA permission to monitor your order status.
    • By default, an API key cannot TRADE. You need to enable trading in API Management first.
  • TRADE and USER_DATA requests are also known as SIGNED requests.

SIGNED (TRADE and USER_DATA) request security

Timing security

  • SIGNED requests also require a timestamp parameter which should be the current millisecond timestamp.

  • An additional optional parameter, recvWindow, specifies for how long the request stays valid.

    • If recvWindow is not sent, it defaults to 5000 milliseconds.
    • Maximum recvWindow is 60000 milliseconds.
  • Request processing logic is as follows:

    if (timestamp < (serverTime + 1000) && (serverTime - timestamp) <= recvWindow) {
    // process request
    } else {
    // reject request
    }

Serious trading is about timing. Networks can be unstable and unreliable, which can lead to requests taking varying amounts of time to reach the servers. With recvWindow, you can specify that the request must be processed within a certain number of milliseconds or be rejected by the server.

It is recommended to use a small recvWindow of 5000 or less!

SIGNED request example (HMAC)

Here is a step-by-step guide on how to sign requests using HMAC secret key.

Example API key and secret key:

KeyValue
apiKeyvmPUZE6mv9SD5VNHk4HlWFsOr6aKE2zvsw0MuIgwCIPy6utIco14y7Ju91duEh8A
secretKeyNhqPtmdSJYdKjVHjA7PZj4Mge3R5YNiP1e3UZjInClVN65XAbvqqM6A7H5fATj0j

WARNING: DO NOT SHARE YOUR API KEY AND SECRET KEY WITH ANYONE.

The example keys are provided here only for illustrative purposes.

Example of request:

{
"id": "4885f793-e5ad-4c3b-8f6c-55d891472b71",
"method": "order.place",
"params": {
"symbol": "BTCUSDT",
"side": "SELL",
"type": "LIMIT",
"timeInForce": "GTC",
"quantity": "0.01000000",
"price": "52000.00",
"newOrderRespType": "ACK",
"recvWindow": 100,
"timestamp": 1645423376532,
"apiKey": "vmPUZE6mv9SD5VNHk4HlWFsOr6aKE2zvsw0MuIgwCIPy6utIco14y7Ju91duEh8A",
"signature": "------ FILL ME ------"
}
}

As you can see, the signature parameter is currently missing.

Step 1. Construct the signature payload

Take all request params except for the signature, sort them by name in alphabetical order:

ParameterValue
apiKeyvmPUZE6mv9SD5VNHk4HlWFsOr6aKE2zvsw0MuIgwCIPy6utIco14y7Ju91duEh8A
newOrderRespTypeACK
price52000.00
quantity0.01000000
recvWindow100
sideSELL
symbolBTCUSDT
timeInForceGTC
timestamp1645423376532
typeLIMIT

Format parameters as parameter=value pairs separated by &.

Resulting signature payload:

apiKey=vmPUZE6mv9SD5VNHk4HlWFsOr6aKE2zvsw0MuIgwCIPy6utIco14y7Ju91duEh8A&newOrderRespType=ACK&price=52000.00&quantity=0.01000000&recvWindow=100&side=SELL&symbol=BTCUSDT&timeInForce=GTC&timestamp=1645423376532&type=LIMIT

Step 2. Compute the signature

  1. Interpret secretKey as ASCII data, using it as a key for HMAC-SHA-256.
  2. Sign signature payload as ASCII data.
  3. Encode HMAC-SHA-256 output as a hex string.

Note that apiKey, secretKey, and the payload are case-sensitive, while resulting signature value is case-insensitive.

You can cross-check your signature algorithm implementation with OpenSSL:

$ echo -n 'apiKey=vmPUZE6mv9SD5VNHk4HlWFsOr6aKE2zvsw0MuIgwCIPy6utIco14y7Ju91duEh8A&newOrderRespType=ACK&price=52000.00&quantity=0.01000000&recvWindow=100&side=SELL&symbol=BTCUSDT&timeInForce=GTC&timestamp=1645423376532&type=LIMIT' \
| openssl dgst -hex -sha256 -hmac 'NhqPtmdSJYdKjVHjA7PZj4Mge3R5YNiP1e3UZjInClVN65XAbvqqM6A7H5fATj0j'

cc15477742bd704c29492d96c7ead9414dfd8e0ec4a00f947bb5bb454ddbd08a

Step 3. Add signature to request params

Finally, complete the request by adding the signature parameter with the signature string.

{
"id": "4885f793-e5ad-4c3b-8f6c-55d891472b71",
"method": "order.place",
"params": {
"symbol": "BTCUSDT",
"side": "SELL",
"type": "LIMIT",
"timeInForce": "GTC",
"quantity": "0.01000000",
"price": "52000.00",
"newOrderRespType": "ACK",
"recvWindow": 100,
"timestamp": 1645423376532,
"apiKey": "vmPUZE6mv9SD5VNHk4HlWFsOr6aKE2zvsw0MuIgwCIPy6utIco14y7Ju91duEh8A",
"signature": "cc15477742bd704c29492d96c7ead9414dfd8e0ec4a00f947bb5bb454ddbd08a"
}
}

SIGNED request example (RSA)

Here is a step-by-step guide on how to sign requests using your RSA private key.

KeyValue
apiKeyCAvIjXy3F44yW6Pou5k8Dy1swsYDWJZLeoK2r8G4cFDnE9nosRppc2eKc1T8TRTQ

In this example, we assume the private key is stored in the test-prv-key.pem file.

WARNING: DO NOT SHARE YOUR API KEY AND PRIVATE KEY WITH ANYONE.

The example keys are provided here only for illustrative purposes.

Example of request:

{
"id": "4885f793-e5ad-4c3b-8f6c-55d891472b71",
"method": "order.place",
"params": {
"symbol": "BTCUSDT",
"side": "SELL",
"type": "LIMIT",
"timeInForce": "GTC",
"quantity": "0.01000000",
"price": "52000.00",
"newOrderRespType": "ACK",
"recvWindow": 100,
"timestamp": 1645423376532,
"apiKey": "CAvIjXy3F44yW6Pou5k8Dy1swsYDWJZLeoK2r8G4cFDnE9nosRppc2eKc1T8TRTQ",
"signature": "------ FILL ME ------"
}
}

Step 1. Construct the signature payload

Take all request params except for the signature, sort them by name in alphabetical order:

ParameterValue
apiKeyCAvIjXy3F44yW6Pou5k8Dy1swsYDWJZLeoK2r8G4cFDnE9nosRppc2eKc1T8TRTQ
newOrderRespTypeACK
price52000.00
quantity0.01000000
recvWindow100
sideSELL
symbolBTCUSDT
timeInForceGTC
timestamp1645423376532
typeLIMIT

Format parameters as parameter=value pairs separated by &.

Resulting signature payload:

apiKey=CAvIjXy3F44yW6Pou5k8Dy1swsYDWJZLeoK2r8G4cFDnE9nosRppc2eKc1T8TRTQ&newOrderRespType=ACK&price=52000.00&quantity=0.01000000&recvWindow=100&side=SELL&symbol=BTCUSDT&timeInForce=GTC&timestamp=1645423376532&type=LIMIT

Step 2. Compute the signature

  1. Encode signature payload as ASCII data.
  2. Sign payload using RSASSA-PKCS1-v1_5 algorithm with SHA-256 hash function.
  3. Encode output as base64 string.

Note that apiKey, the payload, and the resulting signature are case-sensitive.

You can cross-check your signature algorithm implementation with OpenSSL:

$ echo -n 'apiKey=CAvIjXy3F44yW6Pou5k8Dy1swsYDWJZLeoK2r8G4cFDnE9nosRppc2eKc1T8TRTQ&newOrderRespType=ACK&price=52000.00&quantity=0.01000000&recvWindow=100&side=SELL&symbol=BTCUSDT&timeInForce=GTC&timestamp=1645423376532&type=LIMIT' \
| openssl dgst -sha256 -sign test-prv-key.pem \
| openssl enc -base64 -A

OJJaf8C/3VGrU4ATTR4GiUDqL2FboSE1Qw7UnnoYNfXTXHubIl1iaePGuGyfct4NPu5oVEZCH4Q6ZStfB1w4ssgu0uiB/Bg+fBrRFfVgVaLKBdYHMvT+ljUJzqVaeoThG9oXlduiw8PbS9U8DYAbDvWN3jqZLo4Z2YJbyovyDAvDTr/oC0+vssLqP7NmlNb3fF3Bj7StmOwJvQJTbRAtzxK5PP7OQe+0mbW+D7RqVkUiSswR8qJFWTeSe4nXXNIdZdueYhF/Xf25L+KitJS5IHdIHcKfEw3MQzHFb2ZsGWkjDQwxkwr7Noi0Zaa+gFtxCuatGFm9dFIyx217pmSHtA==

Step 3. Add signature to request params

Finally, complete the request by adding the signature parameter with the signature string.

{
"id": "4885f793-e5ad-4c3b-8f6c-55d891472b71",
"method": "order.place",
"params": {
"symbol": "BTCUSDT",
"side": "SELL",
"type": "LIMIT",
"timeInForce": "GTC",
"quantity": "0.01000000",
"price": "52000.00",
"newOrderRespType": "ACK",
"recvWindow": 100,
"timestamp": 1645423376532,
"apiKey": "CAvIjXy3F44yW6Pou5k8Dy1swsYDWJZLeoK2r8G4cFDnE9nosRppc2eKc1T8TRTQ",
"signature": "OJJaf8C/3VGrU4ATTR4GiUDqL2FboSE1Qw7UnnoYNfXTXHubIl1iaePGuGyfct4NPu5oVEZCH4Q6ZStfB1w4ssgu0uiB/Bg+fBrRFfVgVaLKBdYHMvT+ljUJzqVaeoThG9oXlduiw8PbS9U8DYAbDvWN3jqZLo4Z2YJbyovyDAvDTr/oC0+vssLqP7NmlNb3fF3Bj7StmOwJvQJTbRAtzxK5PP7OQe+0mbW+D7RqVkUiSswR8qJFWTeSe4nXXNIdZdueYhF/Xf25L+KitJS5IHdIHcKfEw3MQzHFb2ZsGWkjDQwxkwr7Noi0Zaa+gFtxCuatGFm9dFIyx217pmSHtA=="
}
}

SIGNED Request Example (Ed25519)

Note: It is highly recommended to use Ed25519 API keys as it should provide the best performance and security out of all supported key types.

ParameterValue
symbolBTCUSDT
sideSELL
typeLIMIT
timeInForceGTC
quantity1
price0.2
timestamp1668481559918

This is a sample code in Python to show how to sign the payload with an Ed25519 key.

#!/usr/bin/env python3

import base64
import time
import json
from cryptography.hazmat.primitives.serialization import load_pem_private_key
from websocket import create_connection

# Set up authentication
API_KEY='put your own API Key here'
PRIVATE_KEY_PATH='test-prv-key.pem'

# Load the private key.
# In this example the key is expected to be stored without encryption,
# but we recommend using a strong password for improved security.
with open(PRIVATE_KEY_PATH, 'rb') as f:
private_key = load_pem_private_key(data=f.read(),
password=None)

# Set up the request parameters
params = {
'apiKey': API_KEY,
'symbol': 'BTCUSDT',
'side': 'SELL',
'type': 'LIMIT',
'timeInForce': 'GTC',
'quantity': '1.0000000',
'price': '0.20'
}

# Timestamp the request
timestamp = int(time.time() * 1000) # UNIX timestamp in milliseconds
params['timestamp'] = timestamp

# Sign the request
payload = '&'.join([f'{param}={value}' for param, value in sorted(params.items())])

signature = base64.b64encode(private_key.sign(payload.encode('ASCII')))
params['signature'] = signature.decode('ASCII')

# Send the request
request = {
'id': 'my_new_order',
'method': 'order.place',
'params': params
}

ws = create_connection("wss://ws-api.binance.com:443/ws-api/v3")
ws.send(json.dumps(request))
result = ws.recv()
ws.close()

print(result)

Session Authentication

Note: Only Ed25519 keys are supported for this feature.

If you do not want to specify apiKey and signature in each individual request, you can authenticate your API key for the active WebSocket session.

Once authenticated, you no longer have to specify apiKey and signature for those requests that need them. Requests will be performed on behalf of the account owning the authenticated API key.

Note: You still have to specify the timestamp parameter for SIGNED requests.

Authenticate after connection

You can authenticate an already established connection using session authentication requests:

  • session.logon – authenticate, or change the API key associated with the connection
  • session.status – check connection status and the current API key
  • session.logout – forget the API key associated with the connection

Regarding API key revocation:

If during an active session the API key becomes invalid for any reason (e.g. IP address is not whitelisted, API key was deleted, API key doesn't have correct permissions, etc), after the next request the session will be revoked with the following error message:

{
"id": null,
"status": 401,
"error": {
"code": -2015,
"msg": "Invalid API-key, IP, or permissions for action."
}
}

Authorize ad hoc requests

Only one API key can be authenticated with the WebSocket connection. The authenticated API key is used by default for requests that require an apiKey parameter. However, you can always specify the apiKey and signature explicitly for individual requests, overriding the authenticated API key and using a different one to authorize a specific request.

For example, you might want to authenticate your USER_DATA key to be used by default, but specify the TRADE key with an explicit signature when placing orders.

Data sources

  • The API system is asynchronous. Some delay in the response is normal and expected.

  • Each method has a data source indicating where the data is coming from, and thus how up-to-date it is.

Data SourceLatencyDescription
Matching EnginelowestThe Matching Engine produces the response directly
MemorylowData is fetched from API server's local or external memory cache
DatabasemoderateData is retrieved from the database
  • Some methods have more than one data source (e.g., Memory => Database).

    This means that the API will look for the latest data in that order: first in the cache, then in the database.