Skip to content

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/trade

Request

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

ParameterTypeRequiredDescription
idstringYesClient-generated unique request identifier
methodstringYesMust be "post"
paramsobjectYesContains all parameters for the request

Params Object

ParameterTypeRequiredDescription
actionstringYesMust be "modifyOrder"
orderIdstringYesOrder ID to modify (string for JS BigInt compatibility)
pricestringNo*New price as decimal string
quantitystringNo*New quantity as decimal string
triggerPricestringNoNew trigger price for trigger orders (empty string if not modified)
sourcestringNoRequest source identifier for tracking and rebates (max 100 characters). Use "direct" for generic integrations
subAccountIdstringYesSubaccount ID that owns the order
nonceintegerYesPositive integer, incrementing nonce
expiresAfterintegerNoOptional expiration timestamp in seconds (0 = no expiration)
signatureobjectYesEIP-712 signature components
signature.vintegerYesRecovery ID (27 or 28)
signature.rstringYesR component of signature
signature.sstringYesS 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

FieldTypeDescription
orderobjectCanonical modified order identifier object
order.venueIdstringCanonical venue-generated order ID
order.clientIdstringOptional client-provided order ID
orderIdstringDeprecated legacy modified order ID
statusstringCurrent order status (e.g., "open", "partiallyFilled")
timestampintegerModification timestamp in milliseconds
pricestringNew order price (if modified)
quantitystringNew order quantity (if modified)
triggerPricestringNew trigger price (if modified, for trigger orders)
cumQtystringCumulative filled quantity (if partially filled)
avgPricestringAverage fill price (if partially filled)
Notes:
  • order (canonical), orderId (deprecated), status, and timestamp are always returned
  • price, quantity, triggerPrice, cumQty, and avgPrice are 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

  1. Action Type: Must be exactly "modifyOrder"
  2. Order ID: Must be a valid positive integer string
  3. Modification Fields: At least one of price, quantity, or triggerPrice must be provided
  4. Price Format: If provided, must be a valid decimal string
  5. Quantity Format: If provided, must be a valid decimal string
  6. Trigger Price Format: If provided, must be a valid decimal string
  7. Order Existence: The order must exist and belong to the specified subaccount
  8. 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

FeatureModify OrderCancel+Replace
Queue PriorityCan maintainLoses priority
LatencySingle round-tripTwo round-trips
Risk WindowMinimalExposed during gap
ComplexitySimpleComplex coordination
Failure ModesSingle pointMultiple 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 CodeDescriptionRetryable
UNAUTHORIZEDEIP-712 signature validation failedNo
VALIDATION_ERRORRequest validation failedNo
MISSING_REQUIRED_FIELDRequired field is missingNo
INVALID_FORMATField format is invalidNo
INVALID_VALUEInvalid parameter valueNo
RATE_LIMIT_EXCEEDEDToo many requests in time windowYes
INSUFFICIENT_MARGINNot enough margin for tradeNo
ORDER_NOT_FOUNDOrder does not existNo
OPERATION_TIMEOUTOperation timed outYes
Error CodeDescription
VALIDATION_ERRORRequest validation failed (invalid format, missing fields, etc.)
INVALID_FORMATRequest body is not valid JSON
INTERNAL_ERRORServer-side processing error
UNAUTHORIZEDAuthentication failed
FORBIDDENWallet does not own the specified subaccount
Invalid signatureEIP-712 signature verification failed
Signature address mismatchSignature address does not match wallet address
Nonce already usedNonce has been used in a previous request (replay protection)
Request expiredexpiresAfter timestamp has passed
Order not foundOrder ID does not exist or not owned by user
Order not modifiableOrder is filled, cancelled, or not a limit order
Invalid order parametersNew order parameters are invalid

Next Steps