Errors & Rate Limits
How the APIs report failures, and what limits apply per endpoint.
HTTP status codes
| Status | Meaning | What to do |
|---|---|---|
2xx | Success. | Read the response body. |
4xx | Malformed request. The issue is on your end — bad parameters, missing fields, invalid signature, expired epoch. | Read message (Spot/Futures) or retMsg (HFT). Fix and retry. |
401 | Authentication failed. Bad signature, wrong API key, or X-AUTH-EPOCH skew >60s. | Verify your signing flow against the Reference Client. |
422 | Validation failed. A field is missing or has an invalid value. | The message names the field. |
429 | Rate limit exceeded. | Back off (see Backoff) and retry. |
5xx | Server error on our side. Do not assume the request failed — the operation may have succeeded but the response was lost. | For order placement and cancellation: query Get Order or Get Order Status with your client_order_id / orderLinkId before retrying. |
A 5xx is not a failed operation. The execution status is unknown. Always reconcile by querying with your client-supplied ID before retrying — otherwise you risk placing the same order twice.
Idempotency on retries
Network blips, timeouts, and 5xx errors are facts of life. The safe pattern for any state-changing call (place / cancel / transfer):
- Always send a client-supplied ID on the first attempt:
- Spot orders →
client_order_id - Futures orders →
client_order_id - HFT orders →
orderLinkId - HFT transfers →
client_txn_id
- Spot orders →
- On timeout or
5xx, do not blindly retry. Query the relevant endpoint by your client ID first:- Spot:
GET /trade/api/v2/orderwithclient_order_id - Futures:
GET /trade/api/v2/futures/orderwithclient_order_id - HFT:
GET /v5/order/realtimewithorderLinkId
- Spot:
- If the order/transaction exists, the original request succeeded — use that record, don't re-place. If it doesn't exist, retry with the same client ID. Re-sending the same client ID is safe; we de-duplicate.
Sketch:
def place_with_retry(payload, max_retries=3):
payload["client_order_id"] = str(uuid.uuid4())
for attempt in range(max_retries):
try:
return place_order(payload)
except (Timeout, ServerError):
existing = get_order(client_order_id=payload["client_order_id"])
if existing:
return existing # request actually succeeded
# else fall through and retry
raise RuntimeError("place_order failed after retries")
Error response shapes
Spot and Futures v2 return a flat error object:
{ "message": "Input symbol is missing" }
{ "message": "Amount is more than available balance" }
{ "message": "Invalid Access" }
HFT wraps errors in the standard envelope:
{
"retCode": 10001,
"retMsg": "Invalid parameter",
"result": {},
"retExtInfo": {},
"time": 1756460688504
}
For HFT, always check retCode === 0 before reading result. HTTP 200 only means the request reached the server.
Common error messages
| Status | Message | Cause |
|---|---|---|
422 | Input <field> is missing | A required parameter is absent from the request. |
422 | The value you provided for the field is not valid. Please check the documentation for valid values and try again. | A field has the wrong type or an out-of-range value. |
400 | Amount is more than available balance | Insufficient free_balance (Spot) or available equity (Futures) to cover the order. |
401 | Invalid Access | Authentication failed. Re-check your API key, signature, and epoch. |
Rate limits
Public market-data endpoints have generous limits. Order placement and cancellation are tighter — they're the most expensive operations to honour and the most abused under volatile conditions.
When you exceed a limit, the server returns HTTP 429. Limits are applied per API key.
Spot
| Endpoint | Limit |
|---|---|
| Create Order | 100 / 10s |
| List Orders | 10000 / 10s |
| Portfolio | 5000 / 10s |
| TDS | 25 / 10s |
Other Spot endpoints (Cancel Order, Get Order, Trade Info, Active Coins, Exchange Precision, Trading Fee, Trades, Depth, Candles, Tickers) do not have a published per-endpoint limit. They are subject to a global per-key fair-use limit; if you start seeing 429s on these, back off and contact api@coinswitch.co for a higher allocation.
Futures
| Endpoint | Limit |
|---|---|
| Place Order | 20 / 60s |
| Cancel Order | 10 / 60s |
| Cancel All Open Orders | 10 / 60s |
| Get Order Status | 20 / 60s |
| Open Orders | 20 / 60s |
| Closed Orders | 20 / 60s |
| Get Positions | 20 / 60s |
| Update Leverage | 10 / 60s |
| Get Leverage | 20 / 60s |
| Add Margin | 10 / 60s |
| Get Wallet Balance | 20 / 60s |
| Get Transactions | 20 / 60s |
| Get Instrument Info | 100 / 60s |
| Get Order Book | 100 / 60s |
| Get Ticker | 100 / 60s |
| Get All Pairs Ticker | 100 / 60s |
| KLines | 30 / 60s |
| Get Trades | 100 / 60s |
HFT
Treat HFT rate limits conservatively — back off on 429, monitor your error rate, and if you need a higher allocation, contact api@coinswitch.co.
Backoff
When you hit a 429:
- Stop sending for at least the duration of the limit window. For an endpoint at
100 / 10s, wait at least 10 seconds before retrying. - Use exponential backoff for repeated failures — double the wait on each consecutive
429, capped at a sensible ceiling (60s). - Add jitter — randomize each wait by ±25% to avoid thundering herds when many of your processes hit the limit at the same instant.
- Don't retry on the same connection if you're seeing
5xxand429together — the server may be shedding load. Open a fresh connection on retry.
If you find yourself hitting limits regularly under normal operation, your strategy needs adjustment (batch reads, cache aggressively, prefer WebSockets over polling) — or it may be a fit for the HFT API.