Best Practice
This guide provides instructions for using the ApeX Omni API and is designed to help developers integrate quickly and securely.
Guide
Preparation
To use the API, please first log in to the web portal, apply for an API key, and configure the necessary permissions.
Afterward, you can proceed with development and trading according to the details in this document.
API key credentials
APIKey
,Secretkey
,Passphrase
— generate them at https://omni.apex.exchange/keyManagement by clicking Generate API.
ZkKeys
seeds
— obtain at https://omni.apex.exchange/keyManagement by clicking Omni Key.l2Key
— not displayed in keyManagement; set to''
(empty) or derive locally if needed.
If you are familiar with zkLink, you may also use their SDK to obtain seeds
and l2Key
.
However, this requires access to your private key, so please exercise caution.
Once created, make sure to securely store the following information:
APIKey
: Identifier for API trading, generated randomly by the system.Secretkey
: Private key, randomly generated by the system, used for request signing.Passphrase
: A user-defined password. Please note that if forgotten, it cannot be recovered, and a new APIKey must be created.
API Types
APIs are divided into two main categories:
- Public APIs
- Private APIs
Public APIs - Used to obtain configuration and market data. - Public requests do not require authentication.
Private APIs - Used for order management and account management. - Each private request must use standardized authentication. - APIKey credentials are required for all private requests.
Rate Limits
This section outlines API rate limits:
- For REST API, if the request frequency exceeds the allowed limit, the system will return 403 status code: too many requests.
REST API Rules - Some endpoints are limited by UID. - Some endpoints are limited by IP. - Specific rules are noted in the documentation for each endpoint.
For details, please see Rate Limits.
Market-data
WebSocket Overview
WebSocket is a new protocol in HTML5. It enables full-duplex communication between client and server, allowing fast bidirectional data transfer. A connection can be established through a simple handshake, and the server can actively push information to the client based on business rules. Its advantages include:
- Very small request headers during data transmission, approximately 2 bytes.
- Both client and server can actively send data to each other.
- No need to repeatedly create and destroy TCP requests, saving bandwidth and server resources.
- Strongly recommended for developers to use the WebSocket API to access market data and order book depth.
Domain | WebSocket API | Recommended Usage |
---|---|---|
Public | wss://quote.omni.apex.exchange/realtime_public | Main domain, public |
Private | wss://quote.omni.apex.exchange/realtime_private | Main domain, private |
Subscribing to Market Data
Subscribe to topics via WebSocket to receive real-time market data updates.
- It is recommended to send a
ping
every 15 seconds to keep the connection alive; the server responds with apong
. - It is recommended to subscribe in batches, automatically resubscribe after reconnection, and verify order and handle errors for incremental data.
Heartbeat Example
// client -> server
{"op":"ping"}
// server -> client
{"op":"pong","ts":1699999999999}
Topic Categories
Public Topics (no authentication required)
Market data, trades, order book depth, K-line, etc.Private Topics (authentication required)
Order status, trade reports, positions, account updates, etc., e.g.,ws_zk_accounts_v3
.
Message Structure and Types
- Server push messages include the topic and data payload, for example:
{
"channel":"orderBook200",
"symbol":"BTC-USDT",
"type":"snapshot | delta",
"ts":1699999999999,
"data":{ ... }
}
Type Explanation
snapshot
: Full snapshot (e.g., first push of order book)delta
: Incremental update (only returns changes)
Subscribe / Unsubscribe
// Subscribe
{"op":"subscribe","args":[ "<topic-1>", "<topic-2>" ]}
// Unsubscribe
{"op":"unsubscribe","args":[ "<topic-1>", "<topic-2>" ]}
Public Topics
Description | Arg Format | Key Params | Notes |
---|---|---|---|
Trade | recentlyTrade.H.{symbol} |
symbol |
High-frequency (H) trades |
K-line | candle.{interval}.{symbol} |
interval , symbol |
Intervals: 1 5 15 30 60 120 240 360 720 D W M |
Ticker | instrumentInfo.H.{symbol} |
symbol |
Single trading pair |
All Tickers | instrumentInfo.all |
- | All trading pairs |
Depth Snapshot/Delta | orderBook{limit}.H.{symbol} |
limit , symbol |
limit ∈ {25,200} ; initial snapshot, then deltas |
Example Subscription Request
{"op":"subscribe","args":[
"recentlyTrade.H.BTC-USDT",
"candle.1.BTC-USDT",
"instrumentInfo.H.BTC-USDT",
"orderBook200.H.BTC-USDT"
]}
Depth: The first message is a full snapshot, followed by incremental updates. Apply updates in sequence by timestamp or ID, detect packet loss, and rebuild snapshot if needed.
Private Topics
- After connecting to
realtime_private
, you must authenticate first before subscribing to private topics. - Authentication fields are consistent with REST (
APEX-API-KEY
,APEX-PASSPHRASE
,APEX-TIMESTAMP
,APEX-SIGNATURE
).
Subscribe / Unsubscribe Examples
// Subscribe Example
{"op":"subscribe","args":[ "ws_zk_accounts_v3" ]}
// Unsubscribe Example
{"op":"unsubscribe","args":[ "ws_zk_accounts_v3" ]}
Delta Message Structure Explanation
When there is an update for a subscribed topic, the server sends a delta
message.
This message only includes fields that have changed. Fields with no changes will not be included.
Field Description
type
: Message type, fixed as"delta"
.timestamp
: Server timestamp (in milliseconds).topic
: Name of the subscribed topic.contents
: Data content, only includes changed fields:fills
: Trade fill updates.positions
: Position updates.orders
: Order status updates.accounts
: Account asset updates.transfers
: Fund transfer record updates.
Example Delta Message
{
"type": "delta",
"timestamp": 1647502440973,
"topic": "ws_zk_accounts_v3",
"contents": {
"fills": [ ... ],
"positions": [ ... ],
"orders": [ ... ],
"accounts": [ ... ],
"transfers": [ ... ]
}
}
Private topics only return the fields that have changed.
If there are no changes, those fields will not appear in the response.
Recommendations and Error Handling
- Heartbeat & Timeout: Send regular
ping
; if no data orpong
is received for a long time, reconnect proactively. - Reconnect & Recovery: After reconnecting, authenticate (for private) → resubscribe to original topics → for stateful data like order book retrieve full snapshot first, then resume deltas.
- Rate Limiting & Batching: Avoid subscribing to too many symbols in one
args
to prevent traffic spikes. - Ordering & Sequence: Apply incremental updates in order. If out-of-order or missing data is detected, rollback and rebuild.
Order Management
Subscribing to Order Channel
Before placing an order, users should first subscribe to the order channel via WebSocket. This enables monitoring of order statuses (e.g., pending, filled) and allows responsive actions (e.g., placing a new order upon fill).
The order channel supports subscriptions from multiple dimensions. Users can access order data after connecting to and authenticating on the private WebSocket.
Placing an Order
clientOrderId
uniqueness check only applies to all open orders, but we still recommend using a unique clientOrderId
for all orders for easier troubleshooting.
Once subscribed to the order channel, users are ready to receive incremental updates for order placement.
REST API
Users can place orders via the following REST API. The server returns the order id
and clientOrderId
after receiving the request.
POST /v3/order — See order API details
Market Orders
In ApeX, when placing a market order, the price
field must be provided.
This is different from traditional CEXs (centralized exchanges), which usually do not require a price for market orders. ApeX needs price
for zkLink signature purposes.
Where to get the price:
- Use the API
GET /v3/get-worst-price
to get the current worst price; - Alternatively, you may also obtain the best available quote from the order book (top of the opposite side) and use it as the parameter for a market order.
Checking Order Status
After placing an order, if the API returns no error ("code": "200"
), users will receive a PENDING
status update for the order via WebSocket. If the order is accepted, it will change to OPEN
.
Once an order is fully filled, users will receive an update via WebSocket with the order status FILLED
, along with other fill-related fields.
For order types like IOC (Immediate-Or-Cancel), FOK (Fill-Or-Kill), and Post Only, the order may be rejected by the matching engine. In that case, the user will receive a could_not_fill
status.
Orders may also be canceled by the system for various reasons, such as market orders not executing immediately or L2 verification failure.
Refer to the Cancelation Reason
for specific causes:
Order Cancelation Reason {
"UNKNOWN_ORDER_CANCEL_REASON" // Unknown reason
"EXPIRED" // Order expired
"USER_CANCELED" // User manually canceled
"COULD_NOT_FILL" // Could not be filled (FOK/IOC/Post-only condition not met)
"REDUCE_ONLY_CANCELED" // Reduce-only order couldn't execute
"LIQUIDATE_CANCELED" // Order canceled due to liquidation
"INTERNAL_FAILED" // Internal failure (e.g. matching or L2 verification failed)
}
An order’s final state is either canceled
or filled
.
Possible order statuses:
PENDING
: Order submitted but not yet processed.OPEN
: Order placed and may be partially filled.FILLED
: Order completely filled.CANCELED
: Order canceled, may have partial fills.EXPIRED
: Order expired, may have partial fills.UNTRIGGERED
: Conditional order not yet triggered.
Canceling Orders
Users can cancel orders via a REST request in a similar way.
Users should receive a success response via REST/WebSocket. Only when the order update via WebSocket shows canceled
, the cancelation is confirmed.
Orders that are fully filled or already canceled cannot be canceled again.
A successful response only indicates that the request has been received; users should rely on the WebSocket update to confirm the cancellation.
Order Timestamps
There are multiple timestamps in the order data for tracking status and latency.
createdAt
: Time when the order was created after risk checks.updatedTime
: Last time the order was updated (e.g., modified, filled, or canceled).expiresAt
: Time at which the order expires and is canceled by the system.unfillableAt
: Time when a timed order was executed or canceled.timestamp
: Time when the WebSocket/REST gateway sent the response.
Pagination
ApeX provides pagination to help users navigate large datasets. Parameters:
Parameter | Type | Required | Description |
---|---|---|---|
beginTimeInclusive | String | No | Start time |
endTimeExclusive | String | No | End time |
limit | String | No | Max number of results (up to 100), default 100 |
page | String | No | Page numbers start from 0 |
Trading Account and Positions Information
Account
The account API provides real-time status of user assets, including balances, frozen funds, and available funds.
Users can obtain real-time updates via WebSocket subscriptions, or pull snapshot data via REST API.
WebSocket Subscription
Subscribe to account-related topics to receive real-time updates on balances and positions.
Subscription Example:
{"op":"subscribe","args":["ws_zk_accounts_v3"]}
Example Response: See Subscription Success Push Data
REST API
Users can also query account information via REST API.
Request:
GET /v3/account
Example Response: See GET Account Data & Positions
Wallets
To obtain both spot and contract asset information, you can use the account balance endpoint:
Example Response:
"spotWallets": [
{
"userId": "12137",
"accountId": "350",
"subAccountId": "350",
"balance": "1191781.577364",
"tokenId": "1",
"pendingDepositAmount": "0.000000",
"pendingWithdrawAmount": "0.000000",
"pendingTransferOutAmount": "0.000000",
"pendingTransferInAmount": "0.000000",
"createdAt": 1690365436385,
"updatedAt": 1690365436385
}
],
"contractWallets": [
{
"userId": "121372485302",
"accountId": "350522584833",
"balance": "1191778.137753",
"asset": "USDT",
"pendingDepositAmount": "0.000000",
"pendingWithdrawAmount": "0.000000",
"pendingTransferOutAmount": "0.000000",
"pendingTransferInAmount": "0.000000"
}
]
Positions
Position data is returned under the positions
field, showing current holdings across all trading pairs.
Key fields:
symbol
: Trading pair (e.g.,BTC-USDT
)side
: Direction (LONG
orSHORT
)size
: Position sizeentryPrice
: Entry pricefee
: Fee paidfundingFee
: Funding feecustomInitialMarginRate
: Customized initial margin rate
Example:
"positions": [
{
"symbol": "BTC-USDT",
"side": "LONG",
"size": "0.000",
"entryPrice": "0.00",
"exitPrice": "",
"fee": "0.000000",
"fundingFee": "0.000000",
"customInitialMarginRate": "0"
}
]
Available and TotalEquity
To retrieve account financial data such as available balance, total equity value, and margin details, you can use the following endpoint:
This endpoint provides the most up-to-date account information and is recommended for building asset monitoring and account overview features.