curl --request POST \
--url https://api.arcus.xyz/v1/placeOrder \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--header 'X-Signature: <api-key>' \
--header 'X-Timestamp: <api-key>' \
--data '
{
"address": "<string>",
"marketId": 32767,
"accountIndex": 4,
"quantity": "0.1",
"price": "50000.5",
"goodTilTime": "4102444800000000",
"timestamp": 4611686018427388000,
"minSize": "<string>",
"stopPrice": "<string>",
"isPositionTPSL": false,
"parentOrderId": "<string>",
"clientId": "<string>",
"clientTime": "<string>",
"fillMode": "<string>",
"reduceOnly": false,
"signature": "<string>"
}
'import requests
url = "https://api.arcus.xyz/v1/placeOrder"
payload = {
"address": "<string>",
"marketId": 32767,
"accountIndex": 4,
"quantity": "0.1",
"price": "50000.5",
"goodTilTime": "4102444800000000",
"timestamp": 4611686018427388000,
"minSize": "<string>",
"stopPrice": "<string>",
"isPositionTPSL": False,
"parentOrderId": "<string>",
"clientId": "<string>",
"clientTime": "<string>",
"fillMode": "<string>",
"reduceOnly": False,
"signature": "<string>"
}
headers = {
"X-API-Key": "<api-key>",
"X-Timestamp": "<api-key>",
"X-Signature": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-API-Key': '<api-key>',
'X-Timestamp': '<api-key>',
'X-Signature': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
address: '<string>',
marketId: 32767,
accountIndex: 4,
quantity: '0.1',
price: '50000.5',
goodTilTime: '4102444800000000',
timestamp: 4611686018427388000,
minSize: '<string>',
stopPrice: '<string>',
isPositionTPSL: false,
parentOrderId: '<string>',
clientId: '<string>',
clientTime: '<string>',
fillMode: '<string>',
reduceOnly: false,
signature: '<string>'
})
};
fetch('https://api.arcus.xyz/v1/placeOrder', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.arcus.xyz/v1/placeOrder",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'address' => '<string>',
'marketId' => 32767,
'accountIndex' => 4,
'quantity' => '0.1',
'price' => '50000.5',
'goodTilTime' => '4102444800000000',
'timestamp' => 4611686018427388000,
'minSize' => '<string>',
'stopPrice' => '<string>',
'isPositionTPSL' => false,
'parentOrderId' => '<string>',
'clientId' => '<string>',
'clientTime' => '<string>',
'fillMode' => '<string>',
'reduceOnly' => false,
'signature' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>",
"X-Signature: <api-key>",
"X-Timestamp: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.arcus.xyz/v1/placeOrder"
payload := strings.NewReader("{\n \"address\": \"<string>\",\n \"marketId\": 32767,\n \"accountIndex\": 4,\n \"quantity\": \"0.1\",\n \"price\": \"50000.5\",\n \"goodTilTime\": \"4102444800000000\",\n \"timestamp\": 4611686018427388000,\n \"minSize\": \"<string>\",\n \"stopPrice\": \"<string>\",\n \"isPositionTPSL\": false,\n \"parentOrderId\": \"<string>\",\n \"clientId\": \"<string>\",\n \"clientTime\": \"<string>\",\n \"fillMode\": \"<string>\",\n \"reduceOnly\": false,\n \"signature\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("X-Timestamp", "<api-key>")
req.Header.Add("X-Signature", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.arcus.xyz/v1/placeOrder")
.header("X-API-Key", "<api-key>")
.header("X-Timestamp", "<api-key>")
.header("X-Signature", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"address\": \"<string>\",\n \"marketId\": 32767,\n \"accountIndex\": 4,\n \"quantity\": \"0.1\",\n \"price\": \"50000.5\",\n \"goodTilTime\": \"4102444800000000\",\n \"timestamp\": 4611686018427388000,\n \"minSize\": \"<string>\",\n \"stopPrice\": \"<string>\",\n \"isPositionTPSL\": false,\n \"parentOrderId\": \"<string>\",\n \"clientId\": \"<string>\",\n \"clientTime\": \"<string>\",\n \"fillMode\": \"<string>\",\n \"reduceOnly\": false,\n \"signature\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.arcus.xyz/v1/placeOrder")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["X-Timestamp"] = '<api-key>'
request["X-Signature"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"address\": \"<string>\",\n \"marketId\": 32767,\n \"accountIndex\": 4,\n \"quantity\": \"0.1\",\n \"price\": \"50000.5\",\n \"goodTilTime\": \"4102444800000000\",\n \"timestamp\": 4611686018427388000,\n \"minSize\": \"<string>\",\n \"stopPrice\": \"<string>\",\n \"isPositionTPSL\": false,\n \"parentOrderId\": \"<string>\",\n \"clientId\": \"<string>\",\n \"clientTime\": \"<string>\",\n \"fillMode\": \"<string>\",\n \"reduceOnly\": false,\n \"signature\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"address": "0x1234567890abcdef1234567890abcdef12345678",
"accountIndex": 4,
"orderId": "a1b2c3d4e5f67890",
"marketId": 32767,
"marketDisplayName": "BTC-USD",
"side": "BUY",
"quantity": "<string>",
"price": "<string>",
"status": "ACK",
"createdAt": 123,
"clientId": "<string>",
"type": "LIMIT",
"timeInForce": "GTT",
"goodTilTime": "<string>",
"reduceOnly": true,
"stopPrice": "<string>",
"tpslType": "STOP_LOSS",
"updatedAt": 123,
"remainingSize": "<string>",
"filledSize": "<string>",
"rejectionReason": "POST_ONLY_WOULD_CROSS",
"error": "<string>",
"rateLimit": {
"pool": "order",
"remaining": 9958
}
}{
"address": "0x1234567890abcdef1234567890abcdef12345678",
"accountIndex": 4,
"orderId": "a1b2c3d4e5f67890",
"marketId": 32767,
"marketDisplayName": "BTC-USD",
"side": "BUY",
"quantity": "<string>",
"price": "<string>",
"status": "ACK",
"createdAt": 123,
"clientId": "<string>",
"type": "LIMIT",
"timeInForce": "GTT",
"goodTilTime": "<string>",
"reduceOnly": true,
"stopPrice": "<string>",
"tpslType": "STOP_LOSS",
"updatedAt": 123,
"remainingSize": "<string>",
"filledSize": "<string>",
"rejectionReason": "POST_ONLY_WOULD_CROSS",
"error": "<string>",
"rateLimit": {
"pool": "order",
"remaining": 9958
}
}{
"error": "Invalid request body",
"code": "GEO_RESTRICTED",
"errorSource": "Order",
"errorType": "Tick",
"rejectionReason": "POST_ONLY_WOULD_CROSS"
}{
"error": "Invalid request body",
"code": "GEO_RESTRICTED",
"errorSource": "Order",
"errorType": "Tick",
"rejectionReason": "POST_ONLY_WOULD_CROSS"
}{
"error": "Invalid request body",
"code": "GEO_RESTRICTED",
"errorSource": "Order",
"errorType": "Tick",
"rejectionReason": "POST_ONLY_WOULD_CROSS"
}{
"error": "rate limited",
"reason": "account_empty",
"retryAfterMs": 850,
"clientId": "my-order-42"
}{
"error": "Invalid request body",
"code": "GEO_RESTRICTED",
"errorSource": "Order",
"errorType": "Tick",
"rejectionReason": "POST_ONLY_WOULD_CROSS"
}{
"error": "Invalid request body",
"code": "GEO_RESTRICTED",
"errorSource": "Order",
"errorType": "Tick",
"rejectionReason": "POST_ONLY_WOULD_CROSS"
}{
"error": "Invalid request body",
"code": "GEO_RESTRICTED",
"errorSource": "Order",
"errorType": "Tick",
"rejectionReason": "POST_ONLY_WOULD_CROSS"
}Place order
Place a single order.
curl --request POST \
--url https://api.arcus.xyz/v1/placeOrder \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--header 'X-Signature: <api-key>' \
--header 'X-Timestamp: <api-key>' \
--data '
{
"address": "<string>",
"marketId": 32767,
"accountIndex": 4,
"quantity": "0.1",
"price": "50000.5",
"goodTilTime": "4102444800000000",
"timestamp": 4611686018427388000,
"minSize": "<string>",
"stopPrice": "<string>",
"isPositionTPSL": false,
"parentOrderId": "<string>",
"clientId": "<string>",
"clientTime": "<string>",
"fillMode": "<string>",
"reduceOnly": false,
"signature": "<string>"
}
'import requests
url = "https://api.arcus.xyz/v1/placeOrder"
payload = {
"address": "<string>",
"marketId": 32767,
"accountIndex": 4,
"quantity": "0.1",
"price": "50000.5",
"goodTilTime": "4102444800000000",
"timestamp": 4611686018427388000,
"minSize": "<string>",
"stopPrice": "<string>",
"isPositionTPSL": False,
"parentOrderId": "<string>",
"clientId": "<string>",
"clientTime": "<string>",
"fillMode": "<string>",
"reduceOnly": False,
"signature": "<string>"
}
headers = {
"X-API-Key": "<api-key>",
"X-Timestamp": "<api-key>",
"X-Signature": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-API-Key': '<api-key>',
'X-Timestamp': '<api-key>',
'X-Signature': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
address: '<string>',
marketId: 32767,
accountIndex: 4,
quantity: '0.1',
price: '50000.5',
goodTilTime: '4102444800000000',
timestamp: 4611686018427388000,
minSize: '<string>',
stopPrice: '<string>',
isPositionTPSL: false,
parentOrderId: '<string>',
clientId: '<string>',
clientTime: '<string>',
fillMode: '<string>',
reduceOnly: false,
signature: '<string>'
})
};
fetch('https://api.arcus.xyz/v1/placeOrder', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.arcus.xyz/v1/placeOrder",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'address' => '<string>',
'marketId' => 32767,
'accountIndex' => 4,
'quantity' => '0.1',
'price' => '50000.5',
'goodTilTime' => '4102444800000000',
'timestamp' => 4611686018427388000,
'minSize' => '<string>',
'stopPrice' => '<string>',
'isPositionTPSL' => false,
'parentOrderId' => '<string>',
'clientId' => '<string>',
'clientTime' => '<string>',
'fillMode' => '<string>',
'reduceOnly' => false,
'signature' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>",
"X-Signature: <api-key>",
"X-Timestamp: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.arcus.xyz/v1/placeOrder"
payload := strings.NewReader("{\n \"address\": \"<string>\",\n \"marketId\": 32767,\n \"accountIndex\": 4,\n \"quantity\": \"0.1\",\n \"price\": \"50000.5\",\n \"goodTilTime\": \"4102444800000000\",\n \"timestamp\": 4611686018427388000,\n \"minSize\": \"<string>\",\n \"stopPrice\": \"<string>\",\n \"isPositionTPSL\": false,\n \"parentOrderId\": \"<string>\",\n \"clientId\": \"<string>\",\n \"clientTime\": \"<string>\",\n \"fillMode\": \"<string>\",\n \"reduceOnly\": false,\n \"signature\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("X-Timestamp", "<api-key>")
req.Header.Add("X-Signature", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.arcus.xyz/v1/placeOrder")
.header("X-API-Key", "<api-key>")
.header("X-Timestamp", "<api-key>")
.header("X-Signature", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"address\": \"<string>\",\n \"marketId\": 32767,\n \"accountIndex\": 4,\n \"quantity\": \"0.1\",\n \"price\": \"50000.5\",\n \"goodTilTime\": \"4102444800000000\",\n \"timestamp\": 4611686018427388000,\n \"minSize\": \"<string>\",\n \"stopPrice\": \"<string>\",\n \"isPositionTPSL\": false,\n \"parentOrderId\": \"<string>\",\n \"clientId\": \"<string>\",\n \"clientTime\": \"<string>\",\n \"fillMode\": \"<string>\",\n \"reduceOnly\": false,\n \"signature\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.arcus.xyz/v1/placeOrder")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["X-Timestamp"] = '<api-key>'
request["X-Signature"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"address\": \"<string>\",\n \"marketId\": 32767,\n \"accountIndex\": 4,\n \"quantity\": \"0.1\",\n \"price\": \"50000.5\",\n \"goodTilTime\": \"4102444800000000\",\n \"timestamp\": 4611686018427388000,\n \"minSize\": \"<string>\",\n \"stopPrice\": \"<string>\",\n \"isPositionTPSL\": false,\n \"parentOrderId\": \"<string>\",\n \"clientId\": \"<string>\",\n \"clientTime\": \"<string>\",\n \"fillMode\": \"<string>\",\n \"reduceOnly\": false,\n \"signature\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"address": "0x1234567890abcdef1234567890abcdef12345678",
"accountIndex": 4,
"orderId": "a1b2c3d4e5f67890",
"marketId": 32767,
"marketDisplayName": "BTC-USD",
"side": "BUY",
"quantity": "<string>",
"price": "<string>",
"status": "ACK",
"createdAt": 123,
"clientId": "<string>",
"type": "LIMIT",
"timeInForce": "GTT",
"goodTilTime": "<string>",
"reduceOnly": true,
"stopPrice": "<string>",
"tpslType": "STOP_LOSS",
"updatedAt": 123,
"remainingSize": "<string>",
"filledSize": "<string>",
"rejectionReason": "POST_ONLY_WOULD_CROSS",
"error": "<string>",
"rateLimit": {
"pool": "order",
"remaining": 9958
}
}{
"address": "0x1234567890abcdef1234567890abcdef12345678",
"accountIndex": 4,
"orderId": "a1b2c3d4e5f67890",
"marketId": 32767,
"marketDisplayName": "BTC-USD",
"side": "BUY",
"quantity": "<string>",
"price": "<string>",
"status": "ACK",
"createdAt": 123,
"clientId": "<string>",
"type": "LIMIT",
"timeInForce": "GTT",
"goodTilTime": "<string>",
"reduceOnly": true,
"stopPrice": "<string>",
"tpslType": "STOP_LOSS",
"updatedAt": 123,
"remainingSize": "<string>",
"filledSize": "<string>",
"rejectionReason": "POST_ONLY_WOULD_CROSS",
"error": "<string>",
"rateLimit": {
"pool": "order",
"remaining": 9958
}
}{
"error": "Invalid request body",
"code": "GEO_RESTRICTED",
"errorSource": "Order",
"errorType": "Tick",
"rejectionReason": "POST_ONLY_WOULD_CROSS"
}{
"error": "Invalid request body",
"code": "GEO_RESTRICTED",
"errorSource": "Order",
"errorType": "Tick",
"rejectionReason": "POST_ONLY_WOULD_CROSS"
}{
"error": "Invalid request body",
"code": "GEO_RESTRICTED",
"errorSource": "Order",
"errorType": "Tick",
"rejectionReason": "POST_ONLY_WOULD_CROSS"
}{
"error": "rate limited",
"reason": "account_empty",
"retryAfterMs": 850,
"clientId": "my-order-42"
}{
"error": "Invalid request body",
"code": "GEO_RESTRICTED",
"errorSource": "Order",
"errorType": "Tick",
"rejectionReason": "POST_ONLY_WOULD_CROSS"
}{
"error": "Invalid request body",
"code": "GEO_RESTRICTED",
"errorSource": "Order",
"errorType": "Tick",
"rejectionReason": "POST_ONLY_WOULD_CROSS"
}{
"error": "Invalid request body",
"code": "GEO_RESTRICTED",
"errorSource": "Order",
"errorType": "Tick",
"rejectionReason": "POST_ONLY_WOULD_CROSS"
}address query parameter matching the master Ethereum address for X-API-Key (same as POST /createApiKey response).
Response behavior
Asynchronous. The endpoint returns either202 Accepted (the common case — the signed request was forwarded to the matching engine and the body does not carry terminal state) or 200 OK (the gateway already had definitive state for the order by the time it responded; status reflects that state). In both cases the body echoes the accepted orderId / clientId so subscribers can correlate WebSocket events with the request. To observe the full order lifecycle (OPEN, FILLED, CANCELED, REJECTED, fills, rejection reasons, etc.) clients must subscribe to the orders WebSocket channel (and userFills for trade-level events).Authorizations
Unix time in nanoseconds as a decimal string (e.g. "1713825891591000000"). Millisecond or second epochs are rejected with 401 Unauthorized. Must be within ±30,000 ms of server wall-clock, or the request is rejected with 401 Unauthorized. Required on all mutating / credential-creating endpoints. This same value must appear as the ct field in the ordersign typed canonical payload (single-order endpoints) or in each element's ct field (batch endpoints).
Lowercase hex-encoded Ed25519 signature (128 chars).
Single-order endpoints (placeOrder, cancelOrder, modifyOrder, and other non-batch mutating routes) sign over the ordersign typed canonical payload — a compact, key-sorted JSON object built from parsed request fields using engine-native integer values:
placeOrder: {"ad":"0x…","ai":N,[,"c":"…"],"ct":N,"g":N,"m":N,"op":1,"p":N,"q":N,"r":0|1,"s":N,"t":N,"v":1}
cancelOrder: {"ad":"0x…","ai":N,[,"c":"…"],"ct":N,[,"id":"…"],"m":N,"op":2,"v":1}
modifyOrder: {"ad":"0x…","ai":N,[,"c":"…"],"ct":N,"g":N,[,"id":"…"],"m":N,"op":3,"p":N,"q":N,"r":0|1,"s":N,"t":N,"v":1} (exactly one of id / c)
ct must equal the X-Timestamp header value. Keys in brackets are conditional (omitted when empty). op values: 1=place, 2=cancel, 3=modify. See the ordersign package for field definitions and reference signing code.
Other signed routes (e.g. createApiKey) still use the legacy scheme: signing_message = X-Timestamp + ACTION + canonicalJSON(body), where ACTION is the camelCase final path segment.
Batch endpoints (batchPlaceOrders, batchCancelOrders, batchModifyOrders) do NOT use this header. They authenticate with per-element typed ordersign signatures embedded in the request body (see the global auth description and the per-field signature descriptions on OrderRequest / CancelOrderRequest / ModifyOrderRequest).
Read endpoints are authenticated by ?address= (and optionally X-API-Key) only — no signature is required, except for the signed affiliate reads (see the Referral tag), which require the full header triple; with no body their signing message is X-Timestamp + ACTION. canonicalJSON(body) is the JSON body with object keys sorted lexicographically at every level and no whitespace; the server canonicalizes the received body before verifying, so only the bytes signed over must be canonical. Required on all mutating / credential-creating endpoints.
Query Parameters
Master Ethereum address for this API key (must match address from POST /createApiKey for the same key). Required on REST for account-scoped reads and for place/cancel. Invalid hex → 400; mismatch with key → 403.
20-byte EVM address as hex: optional 0x or 0X prefix and exactly 40 hexadecimal digits. API responses normalize to lowercase a–f after 0x.
^(0x|0X)?[0-9a-fA-F]{40}$Body
Execution style of the order. Use tpslType to mark an order as stop-loss or take-profit.
LIMIT— rests at the specifiedpriceuntil matched or expired.MARKET— executes immediately at best available price. Apricefield is required and serves as a protective slippage bound. The price must be a positive decimal within 10% of the current mark price; deviations beyond that are rejected withMarketPriceSlippageToleranceTooHigh. TPSL MARKET legs must also supply aprice, but it is validated against thestopPrice(trigger price) rather than the live mark price — the price must be within 10% ofstopPrice, since at trigger time the mark price ≈ stopPrice.
LIMIT, MARKET Order size in human-readable base-asset units (e.g. "0.1" for 0.1 BTC). Must be a positive value divisible by the market's step size (see GET /markets), and at most the market's maxOrderSize (reduce-only orders are not exempt). Set to "0" for positionTpsl grouping — the engine resizes to the full open position at trigger time.
1^(0|0\.[0-9]*[1-9][0-9]*|[1-9][0-9]*\.?[0-9]*)$"0.1"
Order price in human-readable USD (e.g. "50000.5"). Must be a positive decimal divisible by the market's tick size (see GET /markets).
- LIMIT — the resting limit price.
- MARKET — required protective slippage bound (see
orderType). Must be within 10% of the current mark price; deviations beyond that are rejected withMarketPriceSlippageToleranceTooHigh. - TPSL MARKET — also required. Must be within 10% of
stopPrice(trigger price), since at trigger time the mark price ≈ stopPrice.
1^(0|0\.[0-9]*[1-9][0-9]*|[1-9][0-9]*\.?[0-9]*)$"50000.5"
GTT = Good Till Time (rests until goodTilTime), IOC = Immediate or Cancel, FOK = Fill or Kill, ALO = Add Liquidity Only (post-only).
Submissions must use GTT for resting orders. Note: order reads (REST order queries and the orders WebSocket channel) currently report resting orders as GTC — the legacy name for the same bucket — for backward compatibility; see TimeInForceResponse.
GTT, IOC, FOK, ALO Good-till-time (GTT): the order's expiration as an epoch-MICROSECOND timestamp (string) — the API's user-facing timestamp resolution, matching createdAt/updatedAt. REQUIRED for all order types, including IOC and FOK: although IOC/FOK orders never rest, the field is a mandatory replay-protection timestamp (omitting it is rejected with 400 "goodTilTime is required"). Must be at least one month ahead of the current system timestamp; a nearer value is rejected. The engine cancels the order (cancel reason Expired) the first time it would fill at or after this instant.
^[0-9]+$"4102444800000000"
Set to STOP_LOSS or TAKE_PROFIT to mark this as a trigger order. Requires stopPrice. For LIMIT execution, price is also required and timeInForce must be GTT (IOC/FOK/ALO are rejected with must be GTT for TPSL LIMIT orders).
reduceOnly depends on tpslType:
STOP_LOSS— may bereduceOnly: true(a protective stop that only reduces an open position) orreduceOnly: false(a stop that opens a position in the trigger direction when it fires). BothLIMITandMARKETexecution are supported.TAKE_PROFIT— must bereduceOnly: true.
A single POST /v1/placeOrder with tpslType set places one standalone (order-level) trigger order. To bundle take-profit and stop-loss legs together, or bind them to an entry order, use POST /v1/batchPlaceOrders groupings (partialTpsl / positionTpsl / entryTpsl); every TPSL leg in a batch grouping must be reduceOnly: true.
STOP_LOSS, TAKE_PROFIT When true, mark this TPSL as a position-level close: at trigger time the engine resizes the order to the user's full open position in marketId (and forces reduceOnly). If the position is zero, the TPSL is canceled instead of executed. Requires tpslType. At most one position-level TPSL of each trigger class (TP, SL) may be active per account+market — a second placement is rejected with POSITION_TPSL_ALREADY_EXISTS. Defaults to false (sized leg / partialTpsl behavior).
Entry order id this TPSL leg is bound to (entryTpsl bundles). Set on each child TPSL placed alongside an entry order so the engine cascade-cancels every leg pointing at the entry when the entry is canceled. Requires tpslType. Omit for standalone TPSLs (partialTpsl, positionTpsl) and for non-TPSL orders.
Optional client-assigned identifier for this order.
Charset — only ASCII letters, digits, hyphens, and underscores ([A-Za-z0-9_-]) are accepted. This restricted set ensures JSON serialization is byte-identical across all SDK languages (Go, TypeScript, Python), which is required for cross-language signature compatibility. Strings containing any other character (spaces, @, Unicode, etc.) are rejected with HTTP 400 InvalidRequest.
Length — 1–36 characters.
Uniqueness — must be unique among the account's currently live orders. Reusing a clientId while the prior order is still open returns DUPLICATE_CLIENT_ID. The id is freed once the prior order reaches a terminal state (FILLED, CANCELED, REJECTED). An account may hold at most 10,000 live clientIds (TOO_MANY_CLIENT_IDS).
When set, the order can later be canceled or modified by clientId instead of orderId.
36^[A-Za-z0-9_-]+$If true, the order can only reduce an existing position. Compatible with any timeInForce value; the matching engine enforces position semantics regardless of TIF. For a STOP_LOSS trigger (tpslType: STOP_LOSS), reduceOnly: false is allowed and makes the order open a position in the trigger direction when it fires.
Per-order Ed25519 signature (128 hex). REQUIRED when this order is an element of a POST /batchPlaceOrders orders array; omitted for single POST /placeOrder (which uses X-Signature in the HTTP header instead).
Covers the ordersign typed canonical payload for this order:
- Plain orders (no
tpsl_type):op=1{"ad":"0x…","ai":N,[,"c":"…"],"ct":N,"g":N,"m":N,"op":1,"p":N,"q":N,"r":0|1,"s":N,"t":N,"v":1} - TPSL / conditional orders (with
tpsl_type):op=4(OpPlaceUntriggered) Same field set asop=1but"op":4. Using a distinct op prevents cross-replay between TPSL and plain placeOrder signatures.
In both cases ct must equal the shared X-Timestamp header value.
Response
Order processed and the gateway already has definitive state for it. status reflects that state (OPEN / FILLED / CANCELED / REJECTED). Treat this as best-effort enrichment of the 202 path; the orders WebSocket channel is still the source of truth for the full lifecycle.
Place-order response. The HTTP call is asynchronous and may return either:
202 Accepted— common case.statusisACKand the body carries no terminal state; theordersWebSocket channel delivers the order's lifecycle.200 OK— the gateway already had definitive state for the order by the time it responded.statusreflects that state (OPEN/FILLED/CANCELED/REJECTED) and enrichment fields (updatedAt,remainingSize,filledSize,rejectionReason) may be populated. Clients should treat this as best-effort and not rely on it.
In both cases the body echoes the accepted orderId and clientId for correlation. To observe the full lifecycle (fills, rejection reasons, etc.) clients must subscribe to the orders WebSocket channel (and userFills for trade-level events).
ACK on the 202 path. On the 200 path, the definitive state (OPEN / FILLED / CANCELED / REJECTED). Subscribe to the orders WebSocket channel for the full lifecycle.
PENDING, OPEN, PARTIALLY_FILLED, FILLED, CANCELED, MARGIN_CANCELED, REJECTED, UNTRIGGERED, TPSL_PLACED, TPSL_TRIGGERED, TPSL_CANCELED, LIQUIDATED, ADL, ACK, CANCEL_ACKNOWLEDGED, CANCEL_ALL_ACKNOWLEDGED, CANCEL_PENDING, ERROR "ACK"
Machine-readable reason when status is REJECTED on the 200 path. Otherwise rejection reasons are delivered via the orders WebSocket channel.
POST_ONLY_WOULD_CROSS, SELF_TRADE, UNDERCOLLATERALIZED, COULD_NOT_FILL, IOC_CANCELED, FOK_FAILED, REDUCE_ONLY_WOULD_INCREASE, TOO_MANY_CLIENT_IDS, DUPLICATE_CLIENT_ID, POSITION_TPSL_ALREADY_EXISTS, ENTRY_TPSL_CANNOT_BE_POSITION_TPSL, ORDER_WILL_TAKE_LIQUIDITY_DURING_MARKET_HALT, ORDER_NOT_FOUND_FOR_MODIFY, MODIFY_CHANGED_IMMUTABLE_FIELD, MODIFY_ZERO_SIZE, PRICE_WILL_EXCEED_MAXIMUM_OUTSIDE_RTH_TRADING_BOUND, MODIFY_WOULD_CROSS_OUTSIDE_RTH_TRADING_BOUNDARY, FILL_WILL_EXCEED_TRADING_BOUND, OPEN_INTEREST_CAP_EXCEEDED, POSITION_SIZE_CAP_EXCEEDED, MODIFY_TPSL_NOT_SUPPORTED, MODIFY_SUPERSEDED_BY_CANCEL, MODIFY_SIZE_ALREADY_FILLED, ORDER_NOT_FOUND, OPEN_ORDER_CAP_EXCEEDED, EXPIRED Was this page helpful?