# Read one limit order by ID.
# Needs openssl, curl and OLYMPEX_API_KEY_ID, OLYMPEX_SECRET_KEY, OLYMPEX_PASSPHRASE.
ORDER_ID='afc47108-d059-473c-b2e1-5f2ca7951466' # from POST /limit-order
METHOD=GET
ENDPOINT="/limit-order/$ORDER_ID"
QUERY=''
BODY='' # GET has no body: the signature covers the empty string
TS="${OLYMPEX_TIMESTAMP:-$(date +%s)}"
NONCE="${OLYMPEX_NONCE:-$(openssl rand -hex 12)}"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -binary | openssl base64 -A | tr '+/' '-_' | tr -d '=')"
VALUE_INFO="$(printf '%s\n%s\n%s' "$TS" "$NONCE" "$BODY_HASH")"
MESSAGE="$(printf 'OLPX-HMAC-SHA256-V2\n%s\n%s\n%s\n%s\n%s\n%s' "$TS" "$NONCE" "$METHOD" "/api/v1$ENDPOINT" "$QUERY" "$BODY_HASH")"
curl -sS -X "$METHOD" "https://api-rest.olympex.io/api/v1$ENDPOINT${QUERY:+?$QUERY}" \
-H "content-type: application/json" \
-H "x-api-key-id: $OLYMPEX_API_KEY_ID" \
-H "x-value-info: $(printf '%s' "$VALUE_INFO" | openssl base64 -A)" \
-H "x-passphrase: $OLYMPEX_PASSPHRASE" \
-H "x-signature: $(printf '%s' "$MESSAGE" | openssl dgst -sha256 -hmac "$OLYMPEX_SECRET_KEY" -binary | od -An -v -tx1 | tr -d ' \n')"
import { olympexRequest } from "./sign-request.ts"; // /authentication/sign-requests
type LimitOrder = { id: string; status: string; expired: string; txHash: string; reasonFail: string[]; attemptNumber: number };
const FINAL = new Set(["completed", "failed", "cancelled"]);
const orderId = "afc47108-d059-473c-b2e1-5f2ca7951466"; // from POST /limit-order
let order = await olympexRequest<LimitOrder>("GET", `/limit-order/${orderId}`);
const stopAt = Number(order.expired) + 60 * 60_000; // the order's own expiry (Unix ms) plus an hour
while (!FINAL.has(order.status) && Date.now() < stopAt) { // any other status, known or not, isn't final
await new Promise((resolve) => setTimeout(resolve, 30_000)); // poll every 15 to 60 seconds
order = await olympexRequest<LimitOrder>("GET", `/limit-order/${orderId}`);
}
if (order.status === "completed") console.log(`Executed in ${order.txHash}`);
else if (order.status === "failed") console.log(`Failed after ${order.attemptNumber} attempts: ${order.reasonFail.join("; ")}`);
else if (order.status === "cancelled") console.log("Cancelled");
else console.log(`Still ${order.status} an hour after its expiry: check it again later, or cancel it`);
import time
from sign_request import olympex_request # /authentication/sign-requests
FINAL = {"completed", "failed", "cancelled"}
order_id = "afc47108-d059-473c-b2e1-5f2ca7951466" # from POST /limit-order
order = olympex_request("GET", f"/limit-order/{order_id}")
stop_at = int(order["expired"]) / 1000 + 60 * 60 # the order's own expiry (Unix ms) plus an hour, in seconds
while order["status"] not in FINAL and time.time() < stop_at: # any other status, known or not, isn't final
time.sleep(30) # poll every 15 to 60 seconds
order = olympex_request("GET", f"/limit-order/{order_id}")
if order["status"] == "completed":
print("Executed in", order["txHash"])
elif order["status"] == "failed":
print(f'Failed after {order["attemptNumber"]} attempts:', "; ".join(order["reasonFail"]))
elif order["status"] == "cancelled":
print("Cancelled")
else:
print(f'Still {order["status"]} an hour after its expiry: check it again later, or cancel it')
{
"success": true,
"data": {
"id": "afc47108-d059-473c-b2e1-5f2ca7951466",
"accountTo": "0x1E67cb01969D79B2B895179e4A07D24a839dBb52",
"chainId": 137,
"gasPrice": "35",
"inTokenAddress": "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619",
"outTokenAddress": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
"slippage": "1",
"tokenASymbol": "ETH",
"tokenBSymbol": "USDC",
"amount": 0.5,
"price": 4200,
"priceTrigger": 4200,
"expired": "1791302400000",
"txHash": "",
"status": "pending",
"reasonFail": [],
"attemptNumber": 0,
"allowance": "",
"estimateGas": "",
"effectivePriceGas": "",
"createdAt": "2026-09-29T16:01:22.237Z",
"updatedAt": "2026-09-29T16:01:22.237Z",
"deletedAt": ""
},
"meta": {
"requestId": "EdkevjVXoAMEZIw=",
"version": "v1",
"accountType": "integrator",
"apiKeyId": "00000000-0000-4000-8000-000000000000"
}
}
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "Limit order not found",
"details": []
},
"meta": {
"requestId": "EdjeXjypoAMEbrQ=",
"version": "v1",
"accountType": "integrator",
"apiKeyId": "00000000-0000-4000-8000-000000000000"
}
}
{
"message": "Forbidden"
}
Get a limit order
Read one limit order and poll it to follow its status until it completes, fails or is cancelled.
# Read one limit order by ID.
# Needs openssl, curl and OLYMPEX_API_KEY_ID, OLYMPEX_SECRET_KEY, OLYMPEX_PASSPHRASE.
ORDER_ID='afc47108-d059-473c-b2e1-5f2ca7951466' # from POST /limit-order
METHOD=GET
ENDPOINT="/limit-order/$ORDER_ID"
QUERY=''
BODY='' # GET has no body: the signature covers the empty string
TS="${OLYMPEX_TIMESTAMP:-$(date +%s)}"
NONCE="${OLYMPEX_NONCE:-$(openssl rand -hex 12)}"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -binary | openssl base64 -A | tr '+/' '-_' | tr -d '=')"
VALUE_INFO="$(printf '%s\n%s\n%s' "$TS" "$NONCE" "$BODY_HASH")"
MESSAGE="$(printf 'OLPX-HMAC-SHA256-V2\n%s\n%s\n%s\n%s\n%s\n%s' "$TS" "$NONCE" "$METHOD" "/api/v1$ENDPOINT" "$QUERY" "$BODY_HASH")"
curl -sS -X "$METHOD" "https://api-rest.olympex.io/api/v1$ENDPOINT${QUERY:+?$QUERY}" \
-H "content-type: application/json" \
-H "x-api-key-id: $OLYMPEX_API_KEY_ID" \
-H "x-value-info: $(printf '%s' "$VALUE_INFO" | openssl base64 -A)" \
-H "x-passphrase: $OLYMPEX_PASSPHRASE" \
-H "x-signature: $(printf '%s' "$MESSAGE" | openssl dgst -sha256 -hmac "$OLYMPEX_SECRET_KEY" -binary | od -An -v -tx1 | tr -d ' \n')"
import { olympexRequest } from "./sign-request.ts"; // /authentication/sign-requests
type LimitOrder = { id: string; status: string; expired: string; txHash: string; reasonFail: string[]; attemptNumber: number };
const FINAL = new Set(["completed", "failed", "cancelled"]);
const orderId = "afc47108-d059-473c-b2e1-5f2ca7951466"; // from POST /limit-order
let order = await olympexRequest<LimitOrder>("GET", `/limit-order/${orderId}`);
const stopAt = Number(order.expired) + 60 * 60_000; // the order's own expiry (Unix ms) plus an hour
while (!FINAL.has(order.status) && Date.now() < stopAt) { // any other status, known or not, isn't final
await new Promise((resolve) => setTimeout(resolve, 30_000)); // poll every 15 to 60 seconds
order = await olympexRequest<LimitOrder>("GET", `/limit-order/${orderId}`);
}
if (order.status === "completed") console.log(`Executed in ${order.txHash}`);
else if (order.status === "failed") console.log(`Failed after ${order.attemptNumber} attempts: ${order.reasonFail.join("; ")}`);
else if (order.status === "cancelled") console.log("Cancelled");
else console.log(`Still ${order.status} an hour after its expiry: check it again later, or cancel it`);
import time
from sign_request import olympex_request # /authentication/sign-requests
FINAL = {"completed", "failed", "cancelled"}
order_id = "afc47108-d059-473c-b2e1-5f2ca7951466" # from POST /limit-order
order = olympex_request("GET", f"/limit-order/{order_id}")
stop_at = int(order["expired"]) / 1000 + 60 * 60 # the order's own expiry (Unix ms) plus an hour, in seconds
while order["status"] not in FINAL and time.time() < stop_at: # any other status, known or not, isn't final
time.sleep(30) # poll every 15 to 60 seconds
order = olympex_request("GET", f"/limit-order/{order_id}")
if order["status"] == "completed":
print("Executed in", order["txHash"])
elif order["status"] == "failed":
print(f'Failed after {order["attemptNumber"]} attempts:', "; ".join(order["reasonFail"]))
elif order["status"] == "cancelled":
print("Cancelled")
else:
print(f'Still {order["status"]} an hour after its expiry: check it again later, or cancel it')
{
"success": true,
"data": {
"id": "afc47108-d059-473c-b2e1-5f2ca7951466",
"accountTo": "0x1E67cb01969D79B2B895179e4A07D24a839dBb52",
"chainId": 137,
"gasPrice": "35",
"inTokenAddress": "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619",
"outTokenAddress": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
"slippage": "1",
"tokenASymbol": "ETH",
"tokenBSymbol": "USDC",
"amount": 0.5,
"price": 4200,
"priceTrigger": 4200,
"expired": "1791302400000",
"txHash": "",
"status": "pending",
"reasonFail": [],
"attemptNumber": 0,
"allowance": "",
"estimateGas": "",
"effectivePriceGas": "",
"createdAt": "2026-09-29T16:01:22.237Z",
"updatedAt": "2026-09-29T16:01:22.237Z",
"deletedAt": ""
},
"meta": {
"requestId": "EdkevjVXoAMEZIw=",
"version": "v1",
"accountType": "integrator",
"apiKeyId": "00000000-0000-4000-8000-000000000000"
}
}
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "Limit order not found",
"details": []
},
"meta": {
"requestId": "EdjeXjypoAMEbrQ=",
"version": "v1",
"accountType": "integrator",
"apiKeyId": "00000000-0000-4000-8000-000000000000"
}
}
{
"message": "Forbidden"
}
GET /limit-order/{id} returns one limit order created with your API key. Poll it to follow the order from pending to a final status: completed, failed or cancelled. A cancelled order stays readable.
Statuses
status | Meaning | Final |
|---|---|---|
pending | Waiting for the market to reach priceTrigger. You can update or cancel it. | No |
executing, submitted | Olympex is executing the order. | No |
completed | Executed. txHash is the execution transaction on chainId. | Yes |
failed | Execution failed. reasonFail lists why, and attemptNumber counts the attempts. | Yes |
cancelled | Cancelled with DELETE /limit-order/{id}. deletedAt is the time of that call. | Yes |
Poll until a final status
- Poll every 15 to 60 seconds, and stop at
completed,failedorcancelled. - Cap the poll too, for example an hour after the order’s
expired. No documented status marks an expired order, so an order can stay at a status that isn’t final: check it again later, or cancel it. - A
pendingorder can wait a long time for the market to reachpriceTrigger. Run the poll from a background job, not while a user waits. - To follow several orders of one maker, poll
GET /limit-orderwithaccountToinstead: one call returns all of them. GETis safe to repeat. Sign every request again, as the reference helpers do: each set of signed headers works once.
After a final status
completed: the order doesn’t report the amount received. Read it from thetxHashtransaction onchainId, with your RPC or the chain’s block explorer.failed:reasonFailexplains why. A failed order doesn’t run again, so fix the cause, for example the maker’s balance or allowance, and create a new order if you still want the trade.cancelled: cancelling doesn’t change the maker’s allowance. Cancel a limit order shows how to lower it.
Not found
A404 NOT_FOUND with the message “Limit order not found” means no order with this ID belongs to your API key: the ID doesn’t exist, or another API key created the order. A 404 NOT_FOUND whose message starts with No route for means the path or method is wrong.
# Read one limit order by ID.
# Needs openssl, curl and OLYMPEX_API_KEY_ID, OLYMPEX_SECRET_KEY, OLYMPEX_PASSPHRASE.
ORDER_ID='afc47108-d059-473c-b2e1-5f2ca7951466' # from POST /limit-order
METHOD=GET
ENDPOINT="/limit-order/$ORDER_ID"
QUERY=''
BODY='' # GET has no body: the signature covers the empty string
TS="${OLYMPEX_TIMESTAMP:-$(date +%s)}"
NONCE="${OLYMPEX_NONCE:-$(openssl rand -hex 12)}"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -binary | openssl base64 -A | tr '+/' '-_' | tr -d '=')"
VALUE_INFO="$(printf '%s\n%s\n%s' "$TS" "$NONCE" "$BODY_HASH")"
MESSAGE="$(printf 'OLPX-HMAC-SHA256-V2\n%s\n%s\n%s\n%s\n%s\n%s' "$TS" "$NONCE" "$METHOD" "/api/v1$ENDPOINT" "$QUERY" "$BODY_HASH")"
curl -sS -X "$METHOD" "https://api-rest.olympex.io/api/v1$ENDPOINT${QUERY:+?$QUERY}" \
-H "content-type: application/json" \
-H "x-api-key-id: $OLYMPEX_API_KEY_ID" \
-H "x-value-info: $(printf '%s' "$VALUE_INFO" | openssl base64 -A)" \
-H "x-passphrase: $OLYMPEX_PASSPHRASE" \
-H "x-signature: $(printf '%s' "$MESSAGE" | openssl dgst -sha256 -hmac "$OLYMPEX_SECRET_KEY" -binary | od -An -v -tx1 | tr -d ' \n')"
import { olympexRequest } from "./sign-request.ts"; // /authentication/sign-requests
type LimitOrder = { id: string; status: string; expired: string; txHash: string; reasonFail: string[]; attemptNumber: number };
const FINAL = new Set(["completed", "failed", "cancelled"]);
const orderId = "afc47108-d059-473c-b2e1-5f2ca7951466"; // from POST /limit-order
let order = await olympexRequest<LimitOrder>("GET", `/limit-order/${orderId}`);
const stopAt = Number(order.expired) + 60 * 60_000; // the order's own expiry (Unix ms) plus an hour
while (!FINAL.has(order.status) && Date.now() < stopAt) { // any other status, known or not, isn't final
await new Promise((resolve) => setTimeout(resolve, 30_000)); // poll every 15 to 60 seconds
order = await olympexRequest<LimitOrder>("GET", `/limit-order/${orderId}`);
}
if (order.status === "completed") console.log(`Executed in ${order.txHash}`);
else if (order.status === "failed") console.log(`Failed after ${order.attemptNumber} attempts: ${order.reasonFail.join("; ")}`);
else if (order.status === "cancelled") console.log("Cancelled");
else console.log(`Still ${order.status} an hour after its expiry: check it again later, or cancel it`);
import time
from sign_request import olympex_request # /authentication/sign-requests
FINAL = {"completed", "failed", "cancelled"}
order_id = "afc47108-d059-473c-b2e1-5f2ca7951466" # from POST /limit-order
order = olympex_request("GET", f"/limit-order/{order_id}")
stop_at = int(order["expired"]) / 1000 + 60 * 60 # the order's own expiry (Unix ms) plus an hour, in seconds
while order["status"] not in FINAL and time.time() < stop_at: # any other status, known or not, isn't final
time.sleep(30) # poll every 15 to 60 seconds
order = olympex_request("GET", f"/limit-order/{order_id}")
if order["status"] == "completed":
print("Executed in", order["txHash"])
elif order["status"] == "failed":
print(f'Failed after {order["attemptNumber"]} attempts:', "; ".join(order["reasonFail"]))
elif order["status"] == "cancelled":
print("Cancelled")
else:
print(f'Still {order["status"]} an hour after its expiry: check it again later, or cancel it')
{
"success": true,
"data": {
"id": "afc47108-d059-473c-b2e1-5f2ca7951466",
"accountTo": "0x1E67cb01969D79B2B895179e4A07D24a839dBb52",
"chainId": 137,
"gasPrice": "35",
"inTokenAddress": "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619",
"outTokenAddress": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
"slippage": "1",
"tokenASymbol": "ETH",
"tokenBSymbol": "USDC",
"amount": 0.5,
"price": 4200,
"priceTrigger": 4200,
"expired": "1791302400000",
"txHash": "",
"status": "pending",
"reasonFail": [],
"attemptNumber": 0,
"allowance": "",
"estimateGas": "",
"effectivePriceGas": "",
"createdAt": "2026-09-29T16:01:22.237Z",
"updatedAt": "2026-09-29T16:01:22.237Z",
"deletedAt": ""
},
"meta": {
"requestId": "EdkevjVXoAMEZIw=",
"version": "v1",
"accountType": "integrator",
"apiKeyId": "00000000-0000-4000-8000-000000000000"
}
}
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "Limit order not found",
"details": []
},
"meta": {
"requestId": "EdjeXjypoAMEbrQ=",
"version": "v1",
"accountType": "integrator",
"apiKeyId": "00000000-0000-4000-8000-000000000000"
}
}
{
"message": "Forbidden"
}
Authorizations
Your API key ID (UUID). See Sign requests.
Base64 of timestamp + "\n" + nonce + "\n" + bodyHash, where timestamp is Unix seconds, nonce is 24 new hexadecimal characters and bodyHash is the unpadded base64url SHA-256 of the canonical body.
Your account passphrase. Treat it like the secret key.
Lowercase hex HMAC-SHA256 (signature v2), keyed with your secret key string (UTF-8, not decoded), of seven lines joined with \n, with no trailing newline: OLPX-HMAC-SHA256-V2, timestamp, nonce, the uppercase method, path, canonicalQuery and bodyHash. path is the request path including /api/v1, without the query string, for example /api/v1/limit-order/<id>. canonicalQuery is the query parameters decoded (+ is a space), sorted by key and then by value, re-encoded per RFC 3986 and joined with &, or the empty string when there is no query. Headers signed for one request are rejected on any other. See Sign requests.
Path Parameters
Limit order ID, as returned when it was created.
Was this page helpful?
