Place Orders
Place one or more orders on Synthetix's orderbook. This endpoint always accepts an array of orders for consistency, even when placing a single order.
Endpoint
POST https://papi.synthetix.io/v1/tradeRequest
Request Format
{
"params": {
"action": "placeOrders",
"subAccountId": "1867542890123456789",
"orders": [
{
"symbol": "BTC-USDT",
"side": "buy",
"orderType": "limitGtc",
"price": "50000.00",
"triggerPrice": "",
"quantity": "0.1",
"reduceOnly": false,
"postOnly": false,
"isTriggerMarket": false,
"closePosition": false,
"clientOrderId": "0x1234567890abcdef1234567890abcdef"
}
],
"grouping": "na",
"source": "direct"
},
"nonce": 1704067200000,
"signature": {
"v": 28,
"r": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"s": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
},
"expiresAfter": 1704067300
}Request Parameters
Action Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
params | object | Yes | Parameters object containing method details |
params.action | string | Yes | Must be "placeOrders" |
params.subAccountId | string | Yes | Subaccount identifier |
params.orders | array | Yes | Array of order objects (minimum 1 order) |
params.grouping | string | No | Order grouping: "na", "normalTpsl", "positionTpsl" |
params.source | string | No | Request source identifier for tracking and rebates (max 100 characters). Use "direct" for generic integrations |
Common Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
nonce | integer | Yes | Positive integer, incrementing nonce |
signature | object | Yes | EIP-712 signature object |
expiresAfter | integer | No | Expiration timestamp (5x rate limit on stale cancels) |
Order Object
| Parameter | Type | Required | Description |
|---|---|---|---|
symbol | string | Yes | Market symbol (e.g., "BTC-USDT", "ETH-USDT") |
side | string | Yes | "buy" or "sell" |
orderType | string | Yes | One of: limitGtc, limitIoc, limitAlo, market, triggerSl, triggerTp |
price | string | Yes | Price as string. Use empty string when not applicable (market orders and trigger market) |
quantity | string | Yes | Order size as string |
reduceOnly | boolean | Yes | Only reduce existing position |
postOnly | boolean | Conditional | Whether order must be maker (no immediate match). Only used for limitGtc orders. Must be false for all other order types |
triggerPrice | string | Yes | Trigger price as string. Required for triggerSl and triggerTp; empty string otherwise |
isTriggerMarket | boolean | Yes | Execution type for trigger orders. true for market-on-trigger, false for limit-on-trigger. Must be false for non-trigger types |
closePosition | boolean | Yes | Close entire position when triggered (TP/SL orders only). Must be false for non-trigger types |
clientOrderId | string | No | 128-bit hex string (0x + 32 hex chars) |
Note on postOnly: The postOnly field is a request parameter but is not included in the EIP-712 signed Order type. It is processed server-side after signature verification. The EIP-712 Order type contains: symbol, side, quantity, orderType, price, triggerPrice, reduceOnly, isTriggerMarket, clientOrderId, closePosition.
Order Type Enum and Rules
limitGtc: price required;isTriggerMarket=false;triggerPrice=""limitIoc: price required;isTriggerMarket=false;triggerPrice=""limitAlo: price required;isTriggerMarket=false;triggerPrice=""market: price="";isTriggerMarket=false;triggerPrice=""triggerSl:triggerPricerequired;isTriggerMarketdetermines execution; iftruethenprice="", iffalsethenpricerequiredtriggerTp: same rules astriggerSl
Examples
Limit GTC
{
"orderType": "limitGtc",
"price": "50000.00",
"triggerPrice": "",
"isTriggerMarket": false,
"postOnly": false,
"closePosition": false
}Limit GTC (Post-Only)
{
"orderType": "limitGtc",
"price": "50000.00",
"triggerPrice": "",
"isTriggerMarket": false,
"postOnly": true,
"closePosition": false
}Market
{
"orderType": "market",
"price": "",
"triggerPrice": "",
"isTriggerMarket": false,
"closePosition": false
}Trigger SL (Market)
{
"orderType": "triggerSl",
"price": "",
"triggerPrice": "50000",
"isTriggerMarket": true,
"closePosition": true
}Trigger TP (Limit)
{
"orderType": "triggerTp",
"price": "49950.00",
"triggerPrice": "50000.00",
"isTriggerMarket": false,
"closePosition": true
}Time in Force (TIF) Options
| Value | Name | Description |
|---|---|---|
gtc | Good Till Canceled | Order remains active until filled or canceled |
ioc | Immediate or Cancel | Fill immediately available quantity, cancel remainder |
alo | Add Liquidity Only | Post-only order, rejected if it would take liquidity |
Response
Response Structure
| Field | Type | Description |
|---|---|---|
status | string | "ok" for processed requests or "error" for request-level failures |
response | object | Contains operation results (omitted when status is "error") |
response.statuses | array | Array of status objects, one per order submitted (check each for success/error) |
error | object | Error details (only present when status is "error") |
requestId | string | Request tracking identifier |
traceId | string | Trace ID for debugging |
timestamp | integer | Unix milliseconds timestamp |
Order Status Types
Each order in the request receives one status response:
| Status Type | Description | Fields |
|---|---|---|
resting | Order placed in orderbook | order (canonical), id (deprecated) |
filled | Order completely filled | order (canonical), id (deprecated), avgPrice, totalSize |
canceled | Order was canceled | order (canonical), id (deprecated) |
error | Order rejected | error (message string), errorCode (machine-readable code) |
Success Response Examples
Single Order - Resting
{
"status": "ok",
"response": {
"statuses": [
{
"resting": {
"order": {
"venueId": "1948058938469519360",
"clientId": "cli-1948058938469519360"
},
"id": "1948058938469519360"
}
}
]
},
"requestId": "5ccf215d37e3ae6d"
}Single Order - Filled
{
"status": "ok",
"response": {
"statuses": [
{
"filled": {
"order": {
"venueId": "1948058938469519361",
"clientId": "cli-1948058938469519361"
},
"id": "1948058938469519361",
"avgPrice": "50001.25",
"totalSize": "0.1"
}
}
]
},
"requestId": "5ccf215d37e3ae6d"
}Single Order - Canceled
{
"status": "ok",
"response": {
"statuses": [
{
"canceled": {
"order": {
"venueId": "1948058938469519362",
"clientId": "cli-1948058938469519362"
},
"id": "1948058938469519362"
}
}
]
},
"requestId": "5ccf215d37e3ae6d"
}Multiple Orders - Mixed Results (Partial Success)
Batch requests can have mixed results where some orders succeed and others fail. The response still has status: "ok" because the request was processed successfully—check each item in the statuses array:
{
"status": "ok",
"response": {
"statuses": [
{
"resting": {
"order": {
"venueId": "1948058938469519360",
"clientId": "cli-1948058938469519360"
},
"id": "1948058938469519360"
}
},
{
"filled": {
"order": {
"venueId": "1948058938469519361",
"clientId": "cli-1948058938469519361"
},
"id": "1948058938469519361",
"avgPrice": "2999.50",
"totalSize": "1.0"
}
},
{
"error": "insufficient margin: additional needed 500.00, available 100.12",
"errorCode": "INSUFFICIENT_MARGIN",
"order": { "venueId": "0", "clientId": "cli-1948058938469519362" }
}
]
},
"requestId": "5ccf215d37e3ae6d",
"traceId": "abc123def456",
"timestamp": 1704067200000
}See Batch Request Error Handling for details on handling partial success scenarios.
Migration Note: Use *.order.venueId as canonical in each status payload. Legacy id remains for compatibility.
Error Response
Request-level errors return an error status. For per-item errors in batch requests, see Batch Request Error Handling.
{
"status": "error",
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid signature",
"category": "AUTH",
"retryable": false
},
"requestId": "5ccf215d37e3ae6d",
"traceId": "abc123def456",
"timestamp": 1704067200000
}Examples
Place Single Limit Order (GTC)
{
"params": {
"action": "placeOrders",
"subAccountId": "1867542890123456789",
"orders": [
{
"symbol": "BTC-USDT",
"side": "buy",
"orderType": "limitGtc",
"price": "50000.00",
"triggerPrice": "",
"quantity": "0.1",
"reduceOnly": false,
"postOnly": false,
"isTriggerMarket": false,
"closePosition": false
}
]
},
"nonce": 1704067200000,
"signature": {
"v": 28,
"r": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"s": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
}
}Place Multiple Orders (Batch) — Mixed types
{
"params": {
"action": "placeOrders",
"subAccountId": "1867542890123456789",
"orders": [
{
"symbol": "BTC-USDT",
"side": "buy",
"orderType": "limitGtc",
"price": "49000.00",
"triggerPrice": "",
"quantity": "0.05",
"reduceOnly": false,
"postOnly": false,
"isTriggerMarket": false,
"closePosition": false
},
{
"symbol": "BTC-USDT",
"side": "buy",
"orderType": "limitGtc",
"price": "48000.00",
"triggerPrice": "",
"quantity": "0.1",
"reduceOnly": false,
"postOnly": false,
"isTriggerMarket": false,
"closePosition": false
},
{
"symbol": "BTC-USDT",
"side": "sell",
"quantity": "0.15",
"reduceOnly": true,
"orderType": "triggerSl",
"price": "",
"triggerPrice": "45000",
"isTriggerMarket": true,
"closePosition": false
}
],
"grouping": "na"
},
"nonce": 1704067200000,
"signature": {
"v": 28,
"r": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"s": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
}
}:::info Rate Limiting This batch contains 3 orders, so it consumes 3 orders from your per-subaccount rate limit (100 orders/second). See Rate Limits for details. :::
Implementation Notes
- Order nonces must be positive integers, incrementing and unique per request
- Client order IDs enable request tracking with 128-bit hex format (0x prefix + 32 hex characters)
- Limit orders require price specification, trigger orders require trigger price
- Batch operations process orders independently with individual status responses
- Order grouping types:
"na"(none),"normalTpsl"(stop-loss/take-profit),"positionTpsl"(position-based) - All price and quantity values must be provided as strings for precision preservation
Error Handling
Common Errors
| Error Code | Description | Solution |
|---|---|---|
INSUFFICIENT_MARGIN | Account lacks required margin | Add collateral or reduce order size |
REQUEST_EXPIRED | expiresAfter timestamp has passed | Use longer expiration or remove |
INVALID_VALUE | Market symbol not recognized | Check supported markets |
QUANTITY_TOO_SMALL | Below minimum order size | Check market minimums |
POST_ONLY_WOULD_TRADE | Post-only order would take liquidity | Adjust price or use different TIF |
MAX_ORDERS_EXCEEDED | Maximum order limit reached | Cancel existing orders first |
REDUCE_ONLY_NO_POSITION | No position for reduce-only order | Remove reduce-only flag |
MARKET_CLOSED | Market is not open for trading | Wait for market to open |
Batch Order Errors
For batch orders, each order is validated and processed independently:
- Request-level errors (invalid signature, rate limit) fail the entire batch with an error response
- Per-item errors (insufficient margin, invalid price) return HTTP 200 with individual error statuses
- The
statusesarray preserves the order of your request—index 0 corresponds to your first order - Successfully processed orders are not rolled back if other orders fail
See Batch Request Error Handling for complete details and code examples.
Implementation Notes
- Batch operations support multiple orders in a single request
- Client order IDs enable tracking across WebSocket sessions
- Expiration timestamps prevent stale order execution (5x rate limit on stale cancels)
- Partial success responses indicate individual order status in batch operations
Rate Limiting
- Each order in the batch counts separately - A request with 5 orders consumes 5 from your rate limit
- Default limit: 100 orders per second per subaccount
- Failed orders due to validation errors still count against rate limits
- See Rate Limits for complete details
Next Steps
- Authentication - Set up request signing
- WebSocket Trading - Real-time alternative
- Error Handling - Handle errors properly