Read Order State
POST https://trade-uk.sandbox.zodiamarkets.com/api/3/zm/rest/orders/state
Order State Lookup
Section titled “Order State Lookup”Look up the current state of an order you placed over the WebSocket, by the clientRequestId you sent on it.
This is the recovery path that does not require a WebSocket connection. Use it when an order’s outcome never reached you — the connection dropped, your process restarted, or you are reconciling after the fact.
Why a Read Is a POST
Section titled “Why a Read Is a POST”Every /api/3 request carries its anti-replay element — tonce or nonce — in the signed body, so this read is a POST with a body even though it changes nothing. A request with no body, or with neither element, is rejected with 401.
Sign it exactly as any other /api/3 endpoint: see Generate Signature →.
What You Get Back
Section titled “What You Get Back”A JSON array, not an object. clientRequestId is unique only within your own account and may be reused, so a lookup can match more than one order.
An order that is not yours returns 200 with an empty array — not 403, not 404. An empty array means “no order of yours matches”, and nothing more.
Reading orderStatus
Section titled “Reading orderStatus”orderStatus |
Meaning |
|---|---|
PENDING |
No outcome recorded yet. Returned for orders on either delivery model — it does not imply a subscription. |
SUCCESS |
The order filled. |
FAILED |
The order did not fill. code carries the reason. |
INDETERMINATE |
The outcome is genuinely unknown — the order may have filled. Do not re-place it; confirm with your desk. |
timestamp is the moment this response was produced, not the time of any order event. To reconcile against settled trades, use Get Trades →, where your clientRequestId appears as clientRef.
Retention
Section titled “Retention”Order records are held for 24 hours. Beyond that, use Get Trades for anything that executed.
Code Example
Section titled “Code Example”import hashlibimport hmacimport jsonimport time
import requests
api_key = "<your_api_key>"api_secret = "<your_api_secret>"base_url = "https://trade-uk.sandbox.zodiamarkets.com"
path = "api/3/zm/rest/orders/state"client_request_id = "TESTCLIENT1"
# Every signed request must carry a nonce or toncebody = {"tonce": int(time.time() * 1000000)}body_json = json.dumps(body)
# The signature covers the path and the body - never the query stringmessage = f"{path}\0{body_json}"signature = hmac.new(api_secret.encode(), message.encode(), hashlib.sha512).hexdigest()
response = requests.post( f"{base_url}/{path}", params={"clientRequestId": client_request_id}, headers={ "Rest-Key": api_key, "Rest-Sign": signature, "Content-Type": "application/json", }, data=body_json,)
orders = response.json()
if not orders: print(f"No order found for {client_request_id}")
for order in orders: print(f"{order['transactionId']}: {order['orderStatus']}")
if order["orderStatus"] == "INDETERMINATE": # The order may have executed. Do not re-place it. escalate_to_desk(order)Related Documentation
Section titled “Related Documentation”- Order Sessions and Recovery - the three ways to recover an order outcome, and when to use which
- List Orders - the same data for all your orders, rather than one
clientRequestId - Order Execution - placing the order in the first place
- Get Trades - the settled record of an executed trade
Domain: Trading
Request
Section titled “Request”POST https://trade-uk.sandbox.zodiamarkets.com/api/3/zm/rest/orders/stateHeaders
Section titled “Headers”| Header | Required | Description |
|---|---|---|
Rest-Key |
yes | API key for authentication |
Rest-Sign |
yes | Calculated API Signature |
Parameters
Section titled “Parameters”| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
clientRequestId |
query | string | yes | The clientRequestId you sent on the order. Not unique — it may match more than one order, so the response is always an array. |
| Field | Type | Required | Description |
|---|---|---|---|
tonce |
integer (int64) | yes | The current Unix time in microseconds. |
nonce |
integer (int64) | Alternative to tonce. Every request must carry either nonce or tonce, and the value must parse as a whole number; a request with neither is rejected with 401. |
Responses
Section titled “Responses”200 — The matching orders, as a JSON array. An empty array when there are none.
Section titled “200 — The matching orders, as a JSON array. An empty array when there are none.”| Field | Type | Required | Description |
|---|---|---|---|
[].messageType |
string | yes | Always orderState |
[].timestamp |
integer (int64) | yes | When this response was produced, in milliseconds. Not the time of any order event — it is set as the record is serialised for your read. |
[].transactionId |
string | yes | Zodia Markets transaction reference for the order |
[].clientRequestId |
string | yes | Your identifier from the order request. Empty until the order has an outcome recorded, including on a lookup by clientRequestId. |
[].orderStatus |
string (enum) | yes | Outcome of the order. PENDING means no outcome has been recorded yet, and is returned for orders on either delivery model. INDETERMINATE means the outcome is genuinely unknown and the order may have executed — do not re-place it. — One of: SUCCESS, FAILED, INDETERMINATE, PENDING |
[].subscriptionStatus |
string (enum) | yes | NOT_SUBSCRIBED for an order sent without autoSubscribe. SUBSCRIBED until you send orderUnsubscribe, then UNSUBSCRIBED. — One of: NOT_SUBSCRIBED, SUBSCRIBED, UNSUBSCRIBED |
[].sessionId |
string | The session the order is bound to. null for an order sent without autoSubscribe — the field is present on the wire, carrying null. |
|
[].message |
string | yes | Outcome message, empty when there is none |
[].code |
string | yes | Outcome code, empty when there is none. See the Response / Error Code Reference. |
400 — clientRequestId or sessionId breaches the identifier rules. A request missing a required header or query parameter is also rejected with 400, but by the framework and with a different body.
Section titled “400 — clientRequestId or sessionId breaches the identifier rules. A request missing a required header or query parameter is also rejected with 400, but by the framework and with a different body.”| Field | Type | Required | Description |
|---|---|---|---|
resultCode |
string | ||
timestamp |
string | Unix time in milliseconds, as a string |
401 — Authentication failed. A bad signature, a missing or stale tonce/nonce, and a replayed one are not distinguished.
Section titled “401 — Authentication failed. A bad signature, a missing or stale tonce/nonce, and a replayed one are not distinguished.”| Field | Type | Required | Description |
|---|---|---|---|
resultCode |
string | ||
timestamp |
string | Unix time in milliseconds, as a string |