API
Read SpotEx.trade market data with no key, or trade from your own software with a signed private API.
/api/public/v1/*Market data anyone may read — prices, the order book, trades, candles, markets and assets.
No key and no signature. 1200 requests per minute per address, and readable from a browser on any site.
/api/private/v1/*Your account — balances, orders, fills and a private live feed.
Every request is signed with an API key. No key can ever withdraw.
/api/public/v1 is 404.| Request | Parameters | Does |
|---|---|---|
| GET /api/public/v1/time | — | Server time in ms — the clock private signatures are checked against |
| GET /api/public/v1/ping | — | Connectivity check |
| GET /api/public/v1/exchangeInfo | — | Every market: status, precision, tick and step size, minimum notional, fees |
| GET /api/public/v1/coins | symbol? | Assets, their price, and whether deposits and withdrawals are open |
| GET /api/public/v1/ticker/24hr | symbol? | 24-hour statistics for one market, or all |
| GET /api/public/v1/ticker/price | symbol? | Last price for one market, or all |
| GET /api/public/v1/ticker/bookTicker | symbol? | Best bid and ask for one market, or all |
| GET /api/public/v1/depth | symbol, limit (20–100) | Order book as [price, amount] pairs, best price first |
| GET /api/public/v1/trades | symbol, limit (50–200) | Recent trades |
| GET /api/public/v1/aggTrades | symbol, limit (50–200) | Recent trades, aggregated |
| GET /api/public/v1/klines | symbol, interval, limit (200–1000), endTime? | Candles — intervals 1m 5m 15m 30m 1h 4h 1D 1W |
Every response carries X-RateLimit-Limit and X-RateLimit-Remaining; past the limit you get 429 rate_limited with Retry-After. Market data is cached for one second.
For updates as they happen, subscribe to public topics on the WebSocket — no ticket needed. See streaming.
curl "https://spotex.trade/api/public/v1/depth?symbol=BTC-USDT&limit=5"
// in a browser, from any site — reads are CORS-open
const book = await fetch("https://spotex.trade/api/public/v1/ticker/24hr?symbol=BTC-USDT")
.then((r) => r.json());Create keys under Security → API keys. A key can read your account and, if you allow it, place and cancel orders. No key can ever withdraw.
The secret is shown once and stored only encrypted. Restrict trading keys to your server's IP address, and revoke a key the moment you suspect it has leaked — it stops working at once.
X-SPOTEX-KEY— your key idX-SPOTEX-TIMESTAMP— milliseconds since the epoch; within 5 s of server time (setX-SPOTEX-RECV-WINDOWup to 60000 ms for more). Sync fromGET /api/public/v1/time.X-SPOTEX-SIGNATURE— hex HMAC-SHA256 oftimestamp + METHOD + path + query + bodywith your secret
Path and query exactly as sent; the body is the exact JSON string sent, or nothing. Amounts are decimal strings — "0.015", never 0.015.
import { createHmac } from "node:crypto";
async function call(method, pathAndQuery, body) {
const timestamp = String(Date.now());
const raw = body ? JSON.stringify(body) : "";
const signature = createHmac("sha256", SECRET)
.update(timestamp + method + pathAndQuery + raw)
.digest("hex");
const res = await fetch(BASE_URL + pathAndQuery, {
method,
headers: {
"X-SPOTEX-KEY": KEY_ID,
"X-SPOTEX-TIMESTAMP": timestamp,
"X-SPOTEX-SIGNATURE": signature,
...(raw && { "Content-Type": "application/json" }),
},
body: raw || undefined,
});
return res.json();
}
await call("POST", "/api/private/v1/order", {
symbol: "BTC-USDT", side: "BUY", type: "LIMIT",
price: "78000.00", size: "0.0150", timeInForce: "GTC",
clientOrderId: "grid-42",
});import hashlib, hmac, json, time, requests
def call(method, path_and_query, body=None):
ts = str(int(time.time() * 1000))
raw = json.dumps(body, separators=(",", ":")) if body else ""
sig = hmac.new(SECRET.encode(), (ts + method + path_and_query + raw).encode(),
hashlib.sha256).hexdigest()
headers = {"X-SPOTEX-KEY": KEY_ID, "X-SPOTEX-TIMESTAMP": ts, "X-SPOTEX-SIGNATURE": sig}
if raw:
headers["Content-Type"] = "application/json"
return requests.request(method, BASE_URL + path_and_query,
headers=headers, data=raw or None).json(){"op":"auth","token":"…"}, then subscribe to book:, trades: or tickers. Your own balances, orders and fills arrive without subscribing.| Request | Key needs | Does |
|---|---|---|
| GET /api/private/v1/account | read | Balances (available, locked) and whether the key can trade |
| GET /api/private/v1/openOrders?symbol= | read | Orders still holding funds |
| GET /api/private/v1/order?clientOrderId= | ?orderId= | read | One order |
| GET /api/private/v1/myTrades?symbol=&limit= | read | Your fills, newest first (limit up to 500) |
| GET /api/private/v1/stream | read | A short-lived ticket for the private WebSocket feed |
| POST /api/private/v1/order | trade | Place an order |
| DELETE /api/private/v1/order?clientOrderId= | ?orderId= | trade | Ask to cancel one order |
| DELETE /api/private/v1/openOrders?symbol= | trade | Ask to cancel every resting order |
A limit order needs price and size; timeInForce is GTC (default), IOC or FOK, and postOnly applies to GTC. A market sell needs size; a market buy needs quoteAmount, the total to spend. Market orders never fill beyond the exchange's price-protection band; a limit priced far through the book is refused.
The response state is open (resting), processing (IOC/FOK/market — read the order back for the result), queued (held until the matching engine answers), waiting (a stop order held until its trigger) or replayed (nothing new was placed).
Send a clientOrderId (1–40 of A–Z a–z 0–9 . _ : -) and a retry is always safe: the same id returns the existing order. Without one, the id is derived from the signature, so replaying the identical signed request places nothing new. A cancel is a request — the order closes when the engine confirms, usually within a second.
Both APIs answer errors as { "error": { "code", "message" } } — for example invalid_signature, timestamp_outside_window, ip_not_allowed, trading_not_permitted, rate_limited (with Retry-After), rejected, engine_unavailable and, on the public API, not_found and market_data_unavailable.
Public: 1200 requests per minute per address. Private, per key: 120 reads and 100 order or cancel requests per 10 seconds; 300 orders per 10 seconds across all of an account's keys; 10 cancel-alls per 10 seconds.