Key takeaways/sapi/v1/system/status reports normal or maintenance state, but it does not prove that every Spot, Futures, WebSocket, account, or trading component is healthy.
/sapi/v1/system/statusreports normal or maintenance state, but it does not prove that every Spot, Futures, WebSocket, account, or trading component is healthy.- Diagnose by layers: distinguish no HTTP response, non-Binance content, Binance JSON errors, and successful but stale data before branching on an error code.
- A
5XXor-1007can leave order execution unknown; use a storednewClientOrderId, check User Data Stream, and query order state before retrying. - Validate symbols through the current product's
exchangeInfo, including status, permissions, order types, and filters; use the delist schedule as an advance-warning feed.
This summary was created with AI.
What the system status endpoint actually proves
GET /sapi/v1/system/status costs IP weight 1, requires no API key in the current global Wallet API reference, and returns two fields:
{
"status": 0,
"msg": "normal"
}
A value of 0 means this endpoint is not reporting general system maintenance. A value of 1 means it is reporting system maintenance. The response does not identify whether the work is planned, which products are affected, or when normal service will return.
That scope matters. A normal result does not prove that Spot trading, Futures, WebSocket Streams, User Data Stream, one REST cluster, or one account is healthy. The endpoint is a useful first signal, but each following check proves only one layer:
| Check | What it proves |
|---|---|
| DNS, TCP, and TLS connection | A network path to that hostname can be established |
/sapi/v1/system/status |
The endpoint is or is not reporting general maintenance |
/api/v3/ping |
A specific Spot REST host answers a public request |
/api/v3/time |
The host returns valid Spot API JSON |
/api/v3/exchangeInfo |
The public Spot metadata layer responds |
| Signed account request | The key, signature, timestamp, permissions, and account path work |
| User Data Stream | Private account events are reaching the client |
| Order query or test order | The particular trading path is available |
| Futures or WebSocket probe | That separate product or transport is available |
Binance publishes several Spot REST base endpoints: api.binance.com, api-gcp.binance.com, and api1 through api4.binance.com. The documentation says api1–api4 may offer better performance with lower stability. A failure on one host and success on another therefore points to a host- or route-specific difference; it does not by itself prove a Binance-wide outage.
The following script performs public checks without retries or account access. It records latency, content type, HTTP status, Retry-After, and any Binance JSON code instead of assuming that every failure has the standard error body:
from __future__ import annotations
import json
import time
from dataclasses import asdict, dataclass
from typing import Any
import requests
SYSTEM_STATUS_URL = "https://api.binance.com/sapi/v1/system/status"
SPOT_HOSTS = [
"https://api.binance.com",
"https://api-gcp.binance.com",
"https://api1.binance.com",
]
@dataclass
class ProbeResult:
url: str
latency_ms: float | None = None
http_status: int | None = None
content_type: str | None = None
retry_after: str | None = None
binance_code: int | None = None
message: str | None = None
exception: str | None = None
def probe(url: str, timeout: float = 5.0) -> ProbeResult:
started = time.monotonic_ns()
try:
response = requests.get(
url,
timeout=timeout,
headers={"Accept": "application/json"},
)
except requests.RequestException as exc:
return ProbeResult(
url=url,
latency_ms=(time.monotonic_ns() - started) / 1_000_000,
exception=type(exc).__name__,
message=str(exc),
)
result = ProbeResult(
url=url,
latency_ms=(time.monotonic_ns() - started) / 1_000_000,
http_status=response.status_code,
content_type=response.headers.get("Content-Type"),
retry_after=response.headers.get("Retry-After"),
)
try:
payload: Any = response.json()
except ValueError:
result.message = response.text[:300].strip() or "<empty body>"
return result
if isinstance(payload, dict):
code = payload.get("code")
result.binance_code = code if isinstance(code, int) else None
result.message = str(payload.get("msg", payload))
else:
result.message = json.dumps(payload)[:300]
return result
def get_egress_ip(timeout: float = 3.0) -> str:
try:
response = requests.get("https://api.ipify.org", timeout=timeout)
response.raise_for_status()
return response.text.strip()
except requests.RequestException as exc:
return f"unavailable ({type(exc).__name__})"
def triage() -> None:
print("egress_ip:", get_egress_ip())
urls = [SYSTEM_STATUS_URL]
for host in SPOT_HOSTS:
urls.extend([
f"{host}/api/v3/ping",
f"{host}/api/v3/time",
])
for url in urls:
print(json.dumps(asdict(probe(url)), ensure_ascii=False))
if __name__ == "__main__":
triage()
Run it from the same host, container, and egress route as the failing application. A successful check from a developer laptop does not prove that a production worker has the same DNS, routing, proxy, or eligibility conditions.
How to classify the response before reading an error code
A Binance negative code exists only when you receive a parseable Binance JSON error. Incidents can fail earlier or return a different body, so begin with the response layer:
| Result | What it usually means | Next step |
|---|---|---|
| No HTTP response | DNS, connect, TLS, proxy, timeout, or disconnect problem | Record the exception and test the route |
| HTTP response with HTML or malformed JSON | CDN, WAF, invalid route, intermediary, or nonstandard error | Log status, content type, and a short body sample |
Binance JSON with negative code |
The API classified the request | Branch on the numeric code |
| HTTP 200 with stale or missing updates | Availability and data freshness are separate | Check event time and sequence continuity |
When a Binance JSON response is present, read the HTTP family first:
| HTTP | Documented meaning | Operational response |
|---|---|---|
| 4XX | The request is malformed or rejected on the sender side | Read the Binance code and request details |
| 403 | A WAF rule fired; this may indicate rate-limit or security enforcement | Inspect rate, payload, parameters, SQL-like strings, and shared-IP traffic |
| 409 | A cancelReplace request partially succeeded |
Reconcile both the cancellation and the new order |
| 429 | A request or order limit was exceeded | Stop sending, honor Retry-After, and coordinate all workers |
| 418 | The IP was auto-banned after continued traffic following 429 responses | Stop traffic on that IP until Retry-After; fix the limiter |
| 5XX | Binance returned an internal error | Treat state-changing execution as unknown, not failed |
The final row is critical. A 5XX from an order operation does not prove that the Matching Engine rejected the order. Blindly repeating the request can create a duplicate position.
How to reconcile an order after 5XX or -1007
Build reconciliation before the first production order is sent. Supply a unique newClientOrderId that your system stores with the intended order. If a timeout or 5XX leaves the result unknown, do not create a new order immediately.
Use this sequence:
1. Pause automatic retries for that logical order.
2. Check User Data Stream for an executionReport with the client order ID.
3. If no event appears, query GET /api/v3/order using origClientOrderId.
4. Reconcile status, executedQty, cumulative quote quantity, and fills.
5. Retry only after confirming that the original order does not exist.
Binance documents a ten-second processing timeout for Spot API requests. Error -1007 explicitly says that send and execution status are unknown. The official guidance is to check User Data Stream first and perform an API status query if the event has not appeared.
The client order ID is not a replacement for reconciliation, but it gives the application a stable identifier when no Binance orderId reached the HTTP client. Store it before sending, together with the symbol, side, quantity, intended price, request time, and worker identity.
How to use Binance error codes without overfitting the ranges
The current Spot error reference says codes are universal and messages can vary. In this context, “universal” refers to the current Binance Spot interfaces documented on that page. Do not assume that a separate regional entity or another Binance product publishes an identical list.
The official reference groups 10xx as general server or network issues and 11xx as request issues, but production handling is clearer when organized by the action required:
| Category | Examples | Typical action |
|---|---|---|
| Transport or uncertain execution | -1001, -1006, -1007, 5XX |
Reconnect or reconcile state before retrying |
| Rate and connection limits | -1003, -1015, -1034, HTTP 429/418 |
Central backoff and limiter correction |
| Authentication and signing | -1002, -1021, -1022, -2014, -2015 |
Check clock, signature, key, IP, and permissions |
| Request validation | -1100, -1102, -1111, -1121, -1130 |
Correct parameters using current metadata |
| Matching or order state | -2010, -2011, -2013, -2026, -2039 |
Inspect order state and matching-engine message |
Log the numeric code as its own field. Also keep the HTTP status, endpoint, host, and message text: the number drives handling, while the message remains useful context when one code has several documented forms.
What invalid symbol means
Code -1121 means BAD_SYMBOL: the supplied symbol is invalid for that endpoint. Do not construct API symbols by stripping / or - from a display pair and assuming the result exists. Use the exact value returned by exchangeInfo on the product and host you call.
For Spot, inspect more than the name:
curl -sS \
"https://api.binance.com/api/v3/exchangeInfo?symbol=BTCUSDT" \
| jq '.symbols[0] | {
symbol,
status,
orderTypes,
permissionSets,
quoteOrderQtyMarketAllowed,
filters
}'
Check:
- the exact symbol string;
- its current
status; - whether the account satisfies the relevant
permissionSets; - whether the intended order type is supported;
PRICE_FILTER,LOT_SIZE,MIN_NOTIONAL,NOTIONAL, and other applicable filters;- whether the code is calling Spot, Futures, Binance.US, or another platform.
A valid symbol name can still be unusable for a particular operation. The current error list also includes -1220 SYMBOL_DOES_NOT_MATCH_STATUS, which is separate from an unknown symbol.
For future removals, Binance provides GET /sapi/v1/spot/delist-schedule. It requires X-MBX-APIKEY and consumes IP weight 100. Poll it on a schedule suitable for the trading universe—for example, once per day—and cache the result instead of calling it inside an order loop:
curl -sS \
"https://api.binance.com/sapi/v1/spot/delist-schedule" \
-H "X-MBX-APIKEY: $BINANCE_API_KEY" \
| jq '.[] | {delistTime, symbols}'
This endpoint is an advance-warning source. exchangeInfo remains the runtime source for the symbols and filters currently exposed by the Spot API.
Why HTTP 200 is not enough for market-data health
An API can accept connections while a client is no longer processing current market data. For WebSocket-driven systems, monitor freshness separately from connectivity:
- age of the latest event time;
- time since the last message was received;
- expected update cadence for that stream;
- sequence or update-ID continuity where the stream defines it;
- reconnect and resynchronization count;
- age of the local order-book snapshot;
- difference between REST and locally maintained state during recovery.
A connected socket with no recent events should not be reported as healthy merely because the TCP session remains open. Likewise, a successful REST ping does not prove that a WebSocket consumer is current.
Which incident fields to log
A useful incident record should preserve enough context to reproduce the exact path:
timestamp
product
host
endpoint
method
HTTP status
Binance code
message
request latency
response content type
Retry-After
X-MBX-USED-WEIGHT-*
X-MBX-ORDER-COUNT-*
clientOrderId
egress IP
exception type
latest market-event age
Keep product and host explicit. A failure on fapi.binance.com, api.binance.com, and a regional platform should not be merged into one metric called binance_api_down.
Useful production counters and gauges include:
binance_http_errors_total{product,host,status}
binance_api_errors_total{product,host,code}
binance_request_latency_ms{product,host,endpoint}
binance_unknown_execution_total{endpoint}
binance_market_event_age_ms{stream}
binance_stream_reconnect_total{stream}
binance_egress_ip_info{worker,ip}
Where to check official service notices
The general Binance announcements center may contain maintenance notices, but it is not a component-level machine-readable status page. Binance also directs API developers to its official API announcements channel for service notices, API changes, upgrades, and deprecations.
Use notices as context alongside your own component checks. Third-party outage trackers aggregate user reports; they can show that many users are seeing problems, but they do not identify which Binance component failed or whether the issue affects your route.
A proxy does not fix Binance maintenance, stale application state, WAF enforcement, or a broken rate limiter. Its relevant role here is providing a stable egress identity for IP whitelisting and incident attribution. Our proxies for Binance include dedicated IPv4 addresses reserved exclusively for you for the plan term, so a worker can keep the same logged and IP-whitelisted egress after redeployment.