Modify Order (WebSocket)
Modify existing orders by changing their price and/or quantity through the WebSocket connection. This is essentially a cancel-and-replace operation that maintains the order's position in the queue while updating its parameters.
Action Result Notifications
This method executes modifications immediately. Modification events are automatically sent via SubAccount Updates Subscription if subscribed.
Endpoint
ws.send() wss://api.synthetix.io/v1/ws/tradeRequest
Request Format
{
"id": "modify-1",
"method": "post",
"params": {
"action": "modifyOrder",
"orderId": "2026771048053084160",
"price": "45000.50",
"quantity": "2.5",
"source": "direct",
"subAccountId": "1",
"nonce": 1703123456789,
"expiresAfter": 1703123486,
"signature": {
"v": 27,
"r": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"s": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
}
}
}Parameters
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Client-generated unique request identifier |
method | string | Yes | Must be "post" |
params | object | Yes | Contains all parameters for the request |
Params Object
| Parameter | Type | Required | Description |
|---|---|---|---|
action | string | Yes | Must be "modifyOrder" |
orderId | string | Yes | Order ID to modify (string for JS BigInt compatibility) |
price | string | No* | New price as decimal string |
quantity | string | No* | New quantity as decimal string |
triggerPrice | string | No | New trigger price for trigger orders (empty string if not modified) |
source | string | No | Request source identifier for tracking and rebates (max 100 characters). Use "direct" for generic integrations |
subAccountId | string | Yes | Subaccount ID that owns the order |
nonce | integer | Yes | Positive integer, incrementing nonce |
expiresAfter | integer | No | Optional expiration timestamp in seconds (0 = no expiration) |
signature | object | Yes | EIP-712 signature components |
signature.v | integer | Yes | Recovery ID (27 or 28) |
signature.r | string | Yes | R component of signature |
signature.s | string | Yes | S component of signature |
*At least one of price, quantity, or triggerPrice must be provided for the modification to be valid.
Response Format
Success Response
{
"id": "modify-1",
"status": 200,
"result": {
"order": {
"venueId": "2026771048053084160",
"clientId": "cli-12345"
},
"orderId": "2026771048053084160",
"status": "open",
"timestamp": 1704067200000,
"price": "45000.50",
"quantity": "2.5",
"triggerPrice": "46000.00",
"cumQty": "0.5",
"avgPrice": "45000.00"
}
}Response Fields
| Field | Type | Description |
|---|---|---|
order | object | Canonical modified order identifier object |
order.venueId | string | Canonical venue-generated order ID |
order.clientId | string | Optional client-provided order ID |
orderId | string | Deprecated legacy modified order ID |
status | string | Current order status (e.g., "open", "partiallyFilled") |
timestamp | integer | Modification timestamp in milliseconds |
price | string | New order price (if modified) |
quantity | string | New order quantity (if modified) |
triggerPrice | string | New trigger price (if modified, for trigger orders) |
cumQty | string | Cumulative filled quantity (if partially filled) |
avgPrice | string | Average fill price (if partially filled) |
order(canonical),orderId(deprecated),status, andtimestampare always returnedprice,quantity,triggerPrice,cumQty, andavgPriceare optional and only included when relevant
Migration Note: Use order.venueId as canonical. orderId is deprecated compatibility output.
Rejection Response
Trading rejections return status 200 with status: "rejected" on the result:
{
"id": "modify-1",
"status": 200,
"result": {
"order": { "venueId": "2026771048053084160", "clientId": "cli-12345" },
"orderId": "2026771048053084160",
"status": "rejected",
"error": "order 2026771048053084160 not found",
"errorCode": "ORDER_NOT_FOUND",
"timestamp": 1704067200000
}
}Error Response
Request-level errors return a non-200 status:
{
"id": "modify-1",
"status": 400,
"error": {
"code": 400,
"message": "Order not found or does not belong to this subaccount"
}
}Implementation Example
import { ethers } from 'ethers';
async function modifyOrder(ws, signer, subAccountId, orderId, price, quantity) {
const nonce = Date.now();
const expiresAfter = Math.floor(Date.now() / 1000) + 30;
// EIP-712 signature
const domain = {
name: "Synthetix",
version: "1",
chainId: 1,
verifyingContract: "0x0000000000000000000000000000000000000000"
};
const types = {
ModifyOrder: [
{ name: "subAccountId", type: "uint256" },
{ name: "orderId", type: "uint256" },
{ name: "price", type: "string" },
{ name: "quantity", type: "string" },
{ name: "triggerPrice", type: "string" },
{ name: "nonce", type: "uint256" },
{ name: "expiresAfter", type: "uint256" }
]
};
const message = {
subAccountId,
orderId,
price: price || "",
quantity: quantity || "",
triggerPrice: "",
nonce,
expiresAfter
};
const sig = await signer.signTypedData(domain, types, message);
const signature = ethers.Signature.from(sig);
// Send request
ws.send(JSON.stringify({
id: `modify-${Date.now()}`,
method: "post",
params: {
action: "modifyOrder",
orderId,
subAccountId,
...(price && { price }),
...(quantity && { quantity }),
nonce,
expiresAfter,
signature: { v: signature.v, r: signature.r, s: signature.s }
}
}));
}
// Usage
await modifyOrder(ws, signer, "1867542890123456789", "12345", "45000.50", null);Validation Rules
Request Validation
- Action Type: Must be exactly
"modifyOrder" - Order ID: Must be a valid positive integer string
- Modification Fields: At least one of
price,quantity, ortriggerPricemust be provided - Price Format: If provided, must be a valid decimal string
- Quantity Format: If provided, must be a valid decimal string
- Trigger Price Format: If provided, must be a valid decimal string
- Order Existence: The order must exist and belong to the specified subaccount
- Signature Verification: EIP-712 signature must be valid for the request parameters
Business Logic Validation
- Order must be in an open/active state
- Cannot modify orders that are already filled or cancelled
- Price/quantity changes must comply with market rules
- Account must have sufficient margin for the modification
Implementation Notes
- Queue Position: The operation preserves the order's position in the queue when possible
- Atomic Operation: The modify operation is atomic - either the entire modification succeeds or fails
- Partial Modification: If only one field (price, quantity, or triggerPrice) is provided, the other fields retain their current values
- Precision: All monetary values use string representation to avoid floating-point precision issues
- Authentication: EIP-712 domain separator must use "Synthetix" for WebSocket endpoints
- Timestamps: Authentication timestamps must be strictly increasing per subaccount
Comparison with Cancel+Replace
| Feature | Modify Order | Cancel+Replace |
|---|---|---|
| Queue Priority | Can maintain | Loses priority |
| Latency | Single round-trip | Two round-trips |
| Risk Window | Minimal | Exposed during gap |
| Complexity | Simple | Complex coordination |
| Failure Modes | Single point | Multiple points |
Signing
All trading methods are signed using EIP-712. Each successful trading request will contain:
- A piece of structured data that includes the sender address
- A signature of the hash of that structured data, signed by the sender
For detailed information on EIP-712 signing, see EIP-712 Signing.
Nonce Management
The nonce system prevents replay attacks and ensures order uniqueness:
- Use any positive integer as nonce
- Each nonce must be greater than the previous one (incrementing)
Date.now()is a convenient option, not a requirement- If nonce conflicts occur, increment by 1 and retry
:::note SubAccountAction Exception
SubAccountAction endpoints (getPositions, getOpenOrders, getOrdersHistory, getTrades, getFundingPayments, getSubAccount, getSubAccounts, getDelegatedSigners, getBalanceUpdates) do not require a nonce. Only the signature and optional expiresAfter parameters are needed.
:::
Error Handling
Common error scenarios:
| Error Code | Description | Retryable |
|---|---|---|
UNAUTHORIZED | EIP-712 signature validation failed | No |
VALIDATION_ERROR | Request validation failed | No |
MISSING_REQUIRED_FIELD | Required field is missing | No |
INVALID_FORMAT | Field format is invalid | No |
INVALID_VALUE | Invalid parameter value | No |
RATE_LIMIT_EXCEEDED | Too many requests in time window | Yes |
INSUFFICIENT_MARGIN | Not enough margin for trade | No |
ORDER_NOT_FOUND | Order does not exist | No |
OPERATION_TIMEOUT | Operation timed out | Yes |
| Error Code | Description |
|---|---|
VALIDATION_ERROR | Request validation failed (invalid format, missing fields, etc.) |
INVALID_FORMAT | Request body is not valid JSON |
INTERNAL_ERROR | Server-side processing error |
UNAUTHORIZED | Authentication failed |
FORBIDDEN | Wallet does not own the specified subaccount |
| Invalid signature | EIP-712 signature verification failed |
| Signature address mismatch | Signature address does not match wallet address |
| Nonce already used | Nonce has been used in a previous request (replay protection) |
| Request expired | expiresAfter timestamp has passed |
| Order not found | Order ID does not exist or not owned by user |
| Order not modifiable | Order is filled, cancelled, or not a limit order |
| Invalid order parameters | New order parameters are invalid |
Next Steps
- Cancel Orders - Order cancellation via WebSocket
- Place Orders - Order placement via WebSocket
- REST Alternative - REST API comparison