REST API Reference
Complete reference for the ZenOTC REST API. Use this documentation to integrate directly without the SDK.
Base URL
Production: https://api.zenotc.com
Staging: https://api-staging.zenotc.com
Authentication
All API requests require authentication via API key headers.
Required Headers
| Header | Description |
|---|---|
X-API-Key | Your API key |
X-API-Timestamp | Unix timestamp in milliseconds |
X-API-Signature | HMAC-SHA256 signature |
Generating the Signature
import hmac
import hashlib
import time
import json
def generate_signature(api_secret: str, method: str, path: str, body: str = "") -> tuple[str, str]:
timestamp = str(int(time.time() * 1000))
message = f"{timestamp}{method.upper()}{path}{body}"
signature = hmac.new(
api_secret.encode(),
message.encode(),
hashlib.sha256
).hexdigest()
return timestamp, signature
Example Request
curl -X GET "https://api.zenotc.com/api/sdk/portfolio/balances" \
-H "X-API-Key: your_api_key" \
-H "X-API-Timestamp: 1705312200000" \
-H "X-API-Signature: abc123..."
Rate Limits
| Endpoint Category | Rate Limit |
|---|---|
| Market Data | 30 requests/second |
| All Other Endpoints | 10 requests/second |
Rate limit headers are included in responses:
X-RateLimit-Limit: Maximum requests per windowX-RateLimit-Remaining: Remaining requestsX-RateLimit-Reset: Window reset timestamp
API Key Scopes
| Scope | Description |
|---|---|
READ | Read-only access to orders, portfolio, market data |
TRADE | Create, amend, cancel orders |
MARKET_MAKING | Submit and manage quotes |
WITHDRAW | Initiate withdrawals |
Orders API
Create Order
Create a new order.
Endpoint: POST /api/sdk/orders
Scope: TRADE
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
side | string | Yes | buy or sell |
asset | string | Yes | Asset symbol (e.g., BTC) |
quantity | number | Yes | Order quantity |
price | number | No | Limit price (required for limit orders) |
orderType | string | No | limit (default) or market |
timeInForce | string | No | GTC (default), IOC, or FOK |
clientOrderId | string | No | Your custom order ID (max 64 chars) |
metadata | object | No | Custom metadata |
Example Request
curl -X POST "https://api.zenotc.com/api/sdk/orders" \
-H "Content-Type: application/json" \
-H "X-API-Key: your_api_key" \
-H "X-API-Timestamp: 1705312200000" \
-H "X-API-Signature: abc123..." \
-d '{
"side": "buy",
"asset": "BTC",
"quantity": 1.5,
"price": 50000.00,
"orderType": "limit",
"timeInForce": "GTC",
"clientOrderId": "my-order-123"
}'
Example Response
{
"orderId": "ord_abc123",
"clientOrderId": "my-order-123",
"side": "buy",
"asset": "BTC",
"quantity": 1.5,
"price": 50000.00,
"orderType": "limit",
"timeInForce": "GTC",
"status": "open",
"filledQuantity": 0,
"remainingQuantity": 1.5,
"averagePrice": null,
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
List Orders
Get a list of orders with optional filters.
Endpoint: GET /api/sdk/orders
Scope: READ
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
statuses | string | - | Comma-separated: open, partially_filled, filled, cancelled |
asset | string | - | Filter by asset |
side | string | - | Filter by side (buy/sell) |
page | number | 1 | Page number |
limit | number | 50 | Results per page (max 100) |
Example Request
curl -X GET "https://api.zenotc.com/api/sdk/orders?statuses=open,partially_filled&asset=BTC&limit=10" \
-H "X-API-Key: your_api_key" \
-H "X-API-Timestamp: 1705312200000" \
-H "X-API-Signature: abc123..."
Example Response
{
"orders": [
{
"orderId": "ord_abc123",
"side": "buy",
"asset": "BTC",
"quantity": 1.5,
"price": 50000.00,
"status": "open",
"filledQuantity": 0,
"createdAt": "2024-01-15T10:30:00.000Z"
}
],
"pagination": {
"page": 1,
"limit": 10,
"total": 1,
"totalPages": 1
}
}
Get Order
Get details of a specific order.
Endpoint: GET /api/sdk/orders/:orderId
Scope: READ
Example Request
curl -X GET "https://api.zenotc.com/api/sdk/orders/ord_abc123" \
-H "X-API-Key: your_api_key" \
-H "X-API-Timestamp: 1705312200000" \
-H "X-API-Signature: abc123..."
Get Order by Client ID
Retrieve an order using your custom client order ID.
Endpoint: GET /api/sdk/orders/by-client-id
Scope: READ
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
clientOrderId | string | Yes | Your custom order ID |
Example Request
curl -X GET "https://api.zenotc.com/api/sdk/orders/by-client-id?clientOrderId=my-order-123" \
-H "X-API-Key: your_api_key" \
-H "X-API-Timestamp: 1705312200000" \
-H "X-API-Signature: abc123..."
Amend Order
Modify an existing order's quantity or price.
Endpoint: PATCH /api/sdk/orders/:orderId
Scope: TRADE
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
quantity | number | No | New quantity |
price | number | No | New price |
Example Request
curl -X PATCH "https://api.zenotc.com/api/sdk/orders/ord_abc123" \
-H "Content-Type: application/json" \
-H "X-API-Key: your_api_key" \
-H "X-API-Timestamp: 1705312200000" \
-H "X-API-Signature: abc123..." \
-d '{
"quantity": 2.0,
"price": 51000.00
}'
Cancel Order
Cancel an open order.
Endpoint: DELETE /api/sdk/orders/:orderId
Scope: TRADE
Example Request
curl -X DELETE "https://api.zenotc.com/api/sdk/orders/ord_abc123" \
-H "X-API-Key: your_api_key" \
-H "X-API-Timestamp: 1705312200000" \
-H "X-API-Signature: abc123..."
Example Response
{
"orderId": "ord_abc123",
"status": "cancelled",
"cancelledAt": "2024-01-15T10:35:00.000Z"
}
Get Order Fills
Get fills/trades for a specific order.
Endpoint: GET /api/sdk/orders/:orderId/fills
Scope: READ
Example Response
{
"fills": [
{
"fillId": "fill_xyz789",
"orderId": "ord_abc123",
"price": 50000.00,
"quantity": 0.5,
"fee": 25.00,
"feeCurrency": "USD",
"executedAt": "2024-01-15T10:32:00.000Z"
}
]
}
Create Batch Orders
Create multiple orders in a single request.
Endpoint: POST /api/sdk/orders/batch
Scope: TRADE
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
orders | array | Yes | Array of order objects (max 100) |
Example Request
curl -X POST "https://api.zenotc.com/api/sdk/orders/batch" \
-H "Content-Type: application/json" \
-H "X-API-Key: your_api_key" \
-H "X-API-Timestamp: 1705312200000" \
-H "X-API-Signature: abc123..." \
-d '{
"orders": [
{"side": "buy", "asset": "BTC", "quantity": 1.0, "price": 49000},
{"side": "buy", "asset": "BTC", "quantity": 1.0, "price": 48000},
{"side": "sell", "asset": "ETH", "quantity": 10.0, "price": 2500}
]
}'
Example Response
{
"results": [
{"success": true, "orderId": "ord_001", "clientOrderId": null},
{"success": true, "orderId": "ord_002", "clientOrderId": null},
{"success": true, "orderId": "ord_003", "clientOrderId": null}
],
"summary": {
"total": 3,
"successful": 3,
"failed": 0
}
}
Cancel All Orders
Cancel all open orders, optionally filtered by asset or side.
Endpoint: DELETE /api/sdk/orders/batch
Scope: TRADE
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
asset | string | No | Cancel only orders for this asset |
side | string | No | Cancel only buy or sell orders |
Example Request
curl -X DELETE "https://api.zenotc.com/api/sdk/orders/batch" \
-H "Content-Type: application/json" \
-H "X-API-Key: your_api_key" \
-H "X-API-Timestamp: 1705312200000" \
-H "X-API-Signature: abc123..." \
-d '{"asset": "BTC"}'
Quotes API (Market Making)
Submit Quote
Submit a two-sided quote (bid and ask).
Endpoint: POST /api/sdk/quotes
Scope: MARKET_MAKING
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
asset | string | Yes | Asset symbol |
bidPrice | number | Yes | Bid price |
askPrice | number | Yes | Ask price |
bidSize | number | Yes | Bid quantity |
askSize | number | Yes | Ask quantity |
validForSeconds | number | No | Quote validity (1-300, default 30) |
clientQuoteId | string | No | Your custom quote ID |
metadata | object | No | Custom metadata |
Example Request
curl -X POST "https://api.zenotc.com/api/sdk/quotes" \
-H "Content-Type: application/json" \
-H "X-API-Key: your_api_key" \
-H "X-API-Timestamp: 1705312200000" \
-H "X-API-Signature: abc123..." \
-d '{
"asset": "BTC",
"bidPrice": 49900.00,
"askPrice": 50100.00,
"bidSize": 5.0,
"askSize": 5.0,
"validForSeconds": 30
}'
Example Response
{
"quoteId": "quote_abc123",
"asset": "BTC",
"bidPrice": 49900.00,
"askPrice": 50100.00,
"bidSize": 5.0,
"askSize": 5.0,
"status": "active",
"expiresAt": "2024-01-15T10:30:30.000Z",
"createdAt": "2024-01-15T10:30:00.000Z"
}
List Quotes
Get a list of your quotes.
Endpoint: GET /api/sdk/quotes
Scope: READ
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
status | string | - | Filter: active, expired, filled, cancelled |
asset | string | - | Filter by asset |
limit | number | 50 | Results per page |
offset | number | 0 | Pagination offset |
Get Quote
Get details of a specific quote.
Endpoint: GET /api/sdk/quotes/:quoteId
Scope: READ
Update Quote
Update an active quote.
Endpoint: PATCH /api/sdk/quotes/:quoteId
Scope: MARKET_MAKING
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
bidPrice | number | No | New bid price |
askPrice | number | No | New ask price |
bidSize | number | No | New bid size |
askSize | number | No | New ask size |
validForSeconds | number | No | Extend validity |
Cancel Quote
Cancel a specific quote.
Endpoint: DELETE /api/sdk/quotes/:quoteId
Scope: MARKET_MAKING
Cancel All Quotes
Cancel all active quotes.
Endpoint: DELETE /api/sdk/quotes
Scope: MARKET_MAKING
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
asset | string | No | Cancel only quotes for this asset |
Bulk Update Quotes
Update multiple quotes in a single request.
Endpoint: PATCH /api/sdk/quotes/batch/update
Scope: MARKET_MAKING
Request Body
Array of quote updates:
[
{"quoteId": "quote_001", "bidPrice": 49950, "askPrice": 50050},
{"quoteId": "quote_002", "bidSize": 10, "askSize": 10}
]
Market Data API
Get Prices
Get current prices for assets.
Endpoint: GET /api/sdk/market-data/prices
Scope: READ
Query Parameters
| Parameter | Type | Description |
|---|---|---|
assets | string | Comma-separated list of assets (optional) |
Example Request
curl -X GET "https://api.zenotc.com/api/sdk/market-data/prices?assets=BTC,ETH" \
-H "X-API-Key: your_api_key" \
-H "X-API-Timestamp: 1705312200000" \
-H "X-API-Signature: abc123..."
Example Response
{
"prices": [
{
"asset": "BTC",
"bid": 49950.00,
"ask": 50050.00,
"mid": 50000.00,
"last": 50010.00,
"change24h": 2.5,
"updatedAt": "2024-01-15T10:30:00.000Z"
},
{
"asset": "ETH",
"bid": 2495.00,
"ask": 2505.00,
"mid": 2500.00,
"last": 2502.00,
"change24h": 1.8,
"updatedAt": "2024-01-15T10:30:00.000Z"
}
]
}
Get Single Asset Price
Endpoint: GET /api/sdk/market-data/prices/:asset
Scope: READ
Get Order Book
Get the order book for an asset.
Endpoint: GET /api/sdk/market-data/orderbook/:asset
Scope: READ
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
depth | number | 10 | Number of levels |
Example Response
{
"asset": "BTC",
"bids": [
{"price": 49950.00, "quantity": 5.0},
{"price": 49900.00, "quantity": 10.0}
],
"asks": [
{"price": 50050.00, "quantity": 5.0},
{"price": 50100.00, "quantity": 8.0}
],
"timestamp": "2024-01-15T10:30:00.000Z"
}
Get Multiple Order Books
Endpoint: GET /api/sdk/market-data/orderbooks
Scope: READ
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
assets | string | Yes | Comma-separated list of assets |
depth | number | No | Number of levels (default 10) |
Get Trading Pairs
Get available trading pairs.
Endpoint: GET /api/sdk/market-data/trading-pairs
Scope: READ
Example Response
{
"pairs": [
{"base": "BTC", "quote": "USD", "minQuantity": 0.001, "maxQuantity": 100},
{"base": "ETH", "quote": "USD", "minQuantity": 0.01, "maxQuantity": 1000}
]
}
Get 24h Statistics
Endpoint: GET /api/sdk/market-data/stats/24h
Scope: READ
Query Parameters
| Parameter | Type | Description |
|---|---|---|
asset | string | Filter by asset (optional) |
Example Response
{
"stats": [
{
"asset": "BTC",
"high": 51000.00,
"low": 48500.00,
"open": 49000.00,
"close": 50000.00,
"volume": 1250.5,
"volumeUsd": 62525000.00,
"trades": 847
}
]
}
Portfolio API
Get Balances
Get account balances.
Endpoint: GET /api/sdk/portfolio/balances
Scope: READ
Query Parameters
| Parameter | Type | Description |
|---|---|---|
assets | string | Comma-separated list of assets (optional) |
Example Response
{
"balances": [
{
"asset": "BTC",
"total": 10.5,
"available": 8.0,
"locked": 2.5,
"usdValue": 525000.00
},
{
"asset": "USD",
"total": 100000.00,
"available": 75000.00,
"locked": 25000.00,
"usdValue": 100000.00
}
]
}
Get Single Asset Balance
Endpoint: GET /api/sdk/portfolio/balances/:asset
Scope: READ
Get Positions
Get open positions.
Endpoint: GET /api/sdk/portfolio/positions
Scope: READ
Query Parameters
| Parameter | Type | Description |
|---|---|---|
asset | string | Filter by asset (optional) |
Example Response
{
"positions": [
{
"asset": "BTC",
"quantity": 5.0,
"averageEntryPrice": 48000.00,
"currentPrice": 50000.00,
"unrealizedPnl": 10000.00,
"unrealizedPnlPercent": 4.17
}
]
}
Get Single Asset Position
Endpoint: GET /api/sdk/portfolio/positions/:asset
Scope: READ
Get Portfolio Exposure
Endpoint: GET /api/sdk/portfolio/exposure
Scope: READ
Example Response
{
"totalExposure": 625000.00,
"netExposure": 525000.00,
"longExposure": 525000.00,
"shortExposure": 0,
"byAsset": [
{"asset": "BTC", "exposure": 525000.00, "weight": 84.0},
{"asset": "USD", "exposure": 100000.00, "weight": 16.0}
]
}
Get Asset Exposure
Endpoint: GET /api/sdk/portfolio/exposure/:asset
Scope: READ
Get Portfolio Summary
Endpoint: GET /api/sdk/portfolio/summary
Scope: READ
Example Response
{
"totalValue": 625000.00,
"totalPnl": 15000.00,
"totalPnlPercent": 2.46,
"dayPnl": 5000.00,
"dayPnlPercent": 0.81,
"positions": 3,
"openOrders": 5
}
Get P&L Breakdown
Endpoint: GET /api/sdk/portfolio/pnl
Scope: READ
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
period | string | 24h | Period: 1h, 24h, 7d, 30d |
Get Transaction History
Endpoint: GET /api/sdk/portfolio/transactions
Scope: READ
Query Parameters
| Parameter | Type | Description |
|---|---|---|
asset | string | Filter by asset |
type | string | Filter by type: deposit, withdrawal, trade |
page | number | Page number |
limit | number | Results per page |
Get Trade History
Endpoint: GET /api/sdk/portfolio/trades
Scope: READ
Query Parameters
| Parameter | Type | Description |
|---|---|---|
asset | string | Filter by asset |
side | string | Filter by side |
startDate | string | ISO date string |
endDate | string | ISO date string |
page | number | Page number |
limit | number | Results per page |
Get Available for Trading
Endpoint: GET /api/sdk/portfolio/available/:asset
Scope: READ
Risk API
Get Risk Limits
Get your configured risk limits.
Endpoint: GET /api/sdk/risk/limits
Scope: READ
Example Response
{
"limits": {
"maxOrderSize": {"BTC": 10, "ETH": 100},
"maxDailyVolume": 1000000.00,
"maxOpenOrders": 100,
"maxExposure": 5000000.00,
"maxExposurePerAsset": {"BTC": 1000000, "ETH": 500000}
}
}
Pre-Trade Risk Check
Validate an order against risk limits before submission.
Endpoint: POST /api/sdk/risk/pre-trade-check
Scope: TRADE
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
side | string | Yes | buy or sell |
asset | string | Yes | Asset symbol |
quantity | number | Yes | Order quantity |
price | number | Yes | Order price |
Example Request
curl -X POST "https://api.zenotc.com/api/sdk/risk/pre-trade-check" \
-H "Content-Type: application/json" \
-H "X-API-Key: your_api_key" \
-H "X-API-Timestamp: 1705312200000" \
-H "X-API-Signature: abc123..." \
-d '{
"side": "buy",
"asset": "BTC",
"quantity": 5.0,
"price": 50000.00
}'
Example Response
{
"approved": true,
"checks": {
"orderSize": {"passed": true, "limit": 10, "value": 5},
"exposure": {"passed": true, "limit": 5000000, "value": 775000},
"dailyVolume": {"passed": true, "limit": 1000000, "value": 350000}
},
"warnings": []
}
Get Risk Exposure
Endpoint: GET /api/sdk/risk/exposure
Scope: READ
Get Asset Risk Exposure
Endpoint: GET /api/sdk/risk/exposure/:asset
Scope: READ
Get Limit Utilization
Endpoint: GET /api/sdk/risk/utilization
Scope: READ
Example Response
{
"utilization": {
"exposure": {"used": 625000, "limit": 5000000, "percent": 12.5},
"dailyVolume": {"used": 350000, "limit": 1000000, "percent": 35.0},
"openOrders": {"used": 5, "limit": 100, "percent": 5.0}
}
}
Get Max Order Quantity
Calculate the maximum quantity you can order.
Endpoint: GET /api/sdk/risk/max-quantity
Scope: READ
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
side | string | Yes | buy or sell |
asset | string | Yes | Asset symbol |
price | number | Yes | Order price |
Example Response
{
"maxQuantity": 8.5,
"limitingFactor": "available_balance",
"details": {
"byBalance": 8.5,
"byExposure": 20.0,
"byOrderSizeLimit": 10.0
}
}
Get Risk Metrics
Endpoint: GET /api/sdk/risk/metrics
Scope: READ
Simulate Order Impact
Simulate how an order would affect your portfolio.
Endpoint: POST /api/sdk/risk/simulate
Scope: READ
Request Body
Same as Pre-Trade Check.
Example Response
{
"currentState": {
"exposure": 625000,
"btcPosition": 5.0
},
"afterOrder": {
"exposure": 875000,
"btcPosition": 10.0
},
"impact": {
"exposureChange": 250000,
"exposureChangePercent": 40.0
}
}
Error Responses
All errors follow a consistent format:
{
"statusCode": 400,
"message": "Invalid order parameters",
"error": "Bad Request",
"details": {
"field": "quantity",
"reason": "Must be greater than 0"
}
}
Common Error Codes
| Status Code | Description |
|---|---|
| 400 | Bad Request - Invalid parameters |
| 401 | Unauthorized - Invalid or missing API key |
| 403 | Forbidden - Insufficient scope |
| 404 | Not Found - Resource doesn't exist |
| 429 | Too Many Requests - Rate limit exceeded |
| 500 | Internal Server Error |
Error Types
| Error | Description |
|---|---|
INVALID_API_KEY | API key not found or revoked |
INVALID_SIGNATURE | Request signature verification failed |
TIMESTAMP_EXPIRED | Request timestamp too old (>30s) |
INSUFFICIENT_SCOPE | API key lacks required scope |
RATE_LIMIT_EXCEEDED | Too many requests |
INSUFFICIENT_BALANCE | Not enough balance for operation |
ORDER_NOT_FOUND | Order ID doesn't exist |
QUOTE_NOT_FOUND | Quote ID doesn't exist |
RISK_LIMIT_EXCEEDED | Order would breach risk limits |