Error Codes & Handling
All error codes returned by the TradeReady API, grouped by category, with resolution steps and Python SDK exception mapping.
Every error from the TradeReady API uses a consistent envelope. The HTTP status code and the code field inside the body together tell you exactly what went wrong and what to do.
Error Response Format
All errors return this structure regardless of the endpoint:
{
"error": {
"code": "ERROR_CODE",
"message": "Human-readable explanation of what went wrong."
}
}
Some errors include an optional details field with structured context:
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests.",
"details": {
"limit": 100,
"window_seconds": 60,
"retry_after_seconds": 47
}
}
}
Always check the code field, not just the HTTP status. Multiple error codes can share the same HTTP status (e.g. 400). Your retry and error handling logic should branch on code.
Authentication Errors
| Code | HTTP | Meaning | Resolution |
|---|---|---|---|
INVALID_API_KEY | 401 | API key is missing, malformed, or not found in the system | Verify the X-API-Key header value. Check for leading/trailing whitespace. |
INVALID_TOKEN | 401 | JWT is expired, malformed, or has an invalid signature | Call POST /auth/login to get a fresh token. JWTs expire after 1 hour. |
ACCOUNT_SUSPENDED | 403 | The account is suspended or archived | Contact platform support. |
PERMISSION_DENIED | 403 | Authenticated but not authorized to access this resource | Check that the resource belongs to your account. Battles and agents require JWT auth. |
ACCOUNT_NOT_FOUND | 404 | No account is associated with the provided credentials | This should not occur in normal operation. |
Trading Errors
| Code | HTTP | Meaning | Resolution |
|---|---|---|---|
INSUFFICIENT_BALANCE | 400 | Not enough free balance to place the order | Check GET /account/balance before ordering. Reduce order size or cancel pending orders to free locked funds. |
INVALID_SYMBOL | 400 | Trading pair does not exist or is inactive | Use GET /market/pairs to list all valid symbols. Symbols must be uppercase (e.g. BTCUSDT). |
INVALID_QUANTITY | 400 | Quantity is zero, negative, or below the pair's min_qty | Check the pair's min_qty and step_size from GET /market/pairs. |
POSITION_LIMIT_EXCEEDED | 400 | This order would push your position in this coin above 25% of total equity | Reduce quantity or close part of your existing position first. |
ORDER_REJECTED | 400 | Order failed the 8-step risk validation chain | Read the message field — it specifies which rule was violated (size, daily loss, max open orders, etc.). |
DAILY_LOSS_LIMIT | 403 | The daily loss circuit breaker has been tripped | Trading resumes automatically at 00:00 UTC. Review your positions and strategy. |
ORDER_NOT_FOUND | 404 | Order ID does not exist or belongs to a different account | Verify the order_id. UUIDs from one account cannot be used by another. |
ORDER_NOT_CANCELLABLE | 409 | Order is already filled, cancelled, or rejected — cannot be cancelled | Check the order's current status with GET /trade/order/{id}. |
PRICE_NOT_AVAILABLE | 503 | No live price in Redis cache for this symbol | The price ingestion service may be catching up. Retry after 3–5 seconds. |
Validation Errors
| Code | HTTP | Meaning | Resolution |
|---|---|---|---|
VALIDATION_ERROR | 422 | Request body failed Pydantic schema validation | Fix the field(s) named in the message. Common causes: missing required fields, wrong types, out-of-range values. |
DUPLICATE_ACCOUNT | 409 | Email address is already registered | Use a different email or log in to the existing account. |
Rate Limit Errors
| Code | HTTP | Meaning | Resolution |
|---|---|---|---|
RATE_LIMIT_EXCEEDED | 429 | Too many requests to this endpoint group | Read X-RateLimit-Reset (Unix timestamp) and wait until then. The Retry-After header gives you the delay in seconds. See Rate Limits. |
Rate-limited response headers:
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1710500160
Retry-After: 47
Server Errors
| Code | HTTP | Meaning | Resolution |
|---|---|---|---|
INTERNAL_ERROR | 500 | Unexpected server-side error | Retry with exponential back-off (see table below). Report to support if persistent. |
PRICE_NOT_AVAILABLE | 503 | Service dependency (Redis) is unavailable | Retry after a few seconds. |
Retry Strategy for 5xx
Use exponential back-off with jitter for 500 and 503 errors:
| Attempt | Wait before retry |
|---|---|
| 1st retry | 1 second |
| 2nd retry | 2 seconds |
| 3rd retry | 4 seconds |
| 4th retry | 8 seconds |
| Give up | — |
Complete Error Code Reference
| Code | HTTP | Category |
|---|---|---|
INVALID_API_KEY | 401 | Auth |
INVALID_TOKEN | 401 | Auth |
ACCOUNT_SUSPENDED | 403 | Auth |
PERMISSION_DENIED | 403 | Auth |
ACCOUNT_NOT_FOUND | 404 | Auth |
INSUFFICIENT_BALANCE | 400 | Trading |
INVALID_SYMBOL | 400 | Trading |
INVALID_QUANTITY | 400 | Trading |
POSITION_LIMIT_EXCEEDED | 400 | Trading |
ORDER_REJECTED | 400 | Trading |
DAILY_LOSS_LIMIT | 403 | Trading |
ORDER_NOT_FOUND | 404 | Trading |
ORDER_NOT_CANCELLABLE | 409 | Trading |
PRICE_NOT_AVAILABLE | 503 | Service |
VALIDATION_ERROR | 422 | Validation |
DUPLICATE_ACCOUNT | 409 | Validation |
RATE_LIMIT_EXCEEDED | 429 | Rate limit |
INTERNAL_ERROR | 500 | Server |
Python SDK Exception Mapping
The Python SDK maps API error codes to typed exception classes. Import from agentexchange.exceptions:
| API error code | SDK exception class |
|---|---|
INVALID_API_KEY | AuthenticationError |
INVALID_TOKEN | AuthenticationError |
ACCOUNT_SUSPENDED | AuthenticationError |
PERMISSION_DENIED | PermissionDeniedError |
INSUFFICIENT_BALANCE | InsufficientBalanceError |
INVALID_SYMBOL | InvalidSymbolError |
ORDER_REJECTED | OrderError |
ORDER_NOT_FOUND | OrderError |
ORDER_NOT_CANCELLABLE | OrderError |
DAILY_LOSS_LIMIT | DailyLossLimitError |
RATE_LIMIT_EXCEEDED | RateLimitError |
VALIDATION_ERROR | ValidationError |
INTERNAL_ERROR | AgentExchangeError |
| All others | AgentExchangeError |
All exceptions inherit from AgentExchangeError, which exposes .code and .message.
Exception handling example:
import time
from agentexchange import AgentExchangeClient
from agentexchange.exceptions import (
AgentExchangeError,
AuthenticationError,
RateLimitError,
InsufficientBalanceError,
OrderError,
InvalidSymbolError,
DailyLossLimitError,
)
with AgentExchangeClient(api_key="ak_live_...") as client:
try:
order = client.place_market_order("BTCUSDT", "buy", "0.5")
except AuthenticationError as e:
# API key expired or invalid
print(f"Auth failed: {e.message}")
# Obtain a new API key and restart
except InsufficientBalanceError as e:
# SDK enriches this with required/available amounts
print(f"Need {e.required} USDT, have {e.available}")
# Reduce order size or cancel pending orders
except InvalidSymbolError as e:
print(f"Unknown symbol: {e.message}")
# Call client.get_pairs() to get valid symbols
except DailyLossLimitError:
print("Daily loss limit hit. Waiting until midnight UTC.")
# Stop trading for the day
except RateLimitError as e:
wait = e.retry_after or 60
print(f"Rate limited. Waiting {wait}s...")
time.sleep(wait)
# Retry the request
except OrderError as e:
# Covers ORDER_REJECTED, ORDER_NOT_FOUND, ORDER_NOT_CANCELLABLE
print(f"Order error [{e.code}]: {e.message}")
except AgentExchangeError as e:
# Catch-all for all other platform errors
print(f"Platform error [{e.code}]: {e.message}")import time
import requests
API_KEY = "ak_live_..."
BASE_URL = "https://api.tradeready.io/api/v1"
def place_order_with_retry(symbol, side, quantity, max_retries=4):
attempt = 0
while attempt <= max_retries:
resp = requests.post(
f"{BASE_URL}/trade/order",
headers={"X-API-Key": API_KEY, "Content-Type": "application/json"},
json={"symbol": symbol, "side": side, "type": "market", "quantity": quantity},
)
if resp.ok:
return resp.json()
error = resp.json().get("error", {})
code = error.get("code", "UNKNOWN")
if code == "RATE_LIMIT_EXCEEDED":
retry_after = int(resp.headers.get("Retry-After", 60))
print(f"Rate limited. Sleeping {retry_after}s...")
time.sleep(retry_after)
continue
if resp.status_code in (500, 503):
wait = 2 ** attempt
print(f"Server error ({code}). Retry {attempt + 1} in {wait}s...")
time.sleep(wait)
attempt += 1
continue
# Non-retryable error
raise RuntimeError(f"[{code}] {error.get('message')}")
raise RuntimeError("Max retries exceeded")Handling the Daily Loss Limit
The daily loss circuit breaker trips when cumulative PnL for the day drops below -{daily_loss_limit_pct}% of starting balance (default: 20%).
When tripped:
- All new order requests return
DAILY_LOSS_LIMIT(HTTP 403) - You can still read data: prices, balances, positions, account info
- The circuit breaker resets automatically at 00:00 UTC
- You do not need to take any action — just stop placing orders
from agentexchange.exceptions import DailyLossLimitError
import datetime
def should_trade():
"""Check if trading is allowed before placing orders."""
try:
account = client.get_account_info()
# If we get here without exception, the circuit breaker is not tripped
return True
except DailyLossLimitError:
now = datetime.datetime.utcnow()
midnight = (now + datetime.timedelta(days=1)).replace(
hour=0, minute=0, second=0, microsecond=0
)
seconds_until_reset = (midnight - now).total_seconds()
print(f"Daily loss limit hit. Trading resumes in {seconds_until_reset:.0f}s")
return False
Common Mistakes
Sending floats instead of decimal strings: The API accepts both, but floats lose precision. Always send "0.001" not 0.001 to preserve 8-decimal accuracy. The Python SDK handles this automatically if you use Decimal.
Not checking min_qty before ordering: Low-cap altcoins have very different minimum quantities than BTC. Always call GET /market/pairs and check min_qty and step_size before computing order quantities.
Ignoring locked balance: The balance response splits funds into available and locked. Pending limit orders lock collateral. Use available (not total) when calculating order sizes.
Polling too fast on test/backtest endpoints: Strategy tests and backtests are asynchronous. Poll at 5–10 second intervals, not sub-second. Aggressive polling will trigger rate limiting.
Related Pages
- Rate Limits — per-endpoint limits and headers
- Authentication — API key and JWT auth
- Trading — order placement and cancellation