Skip to content

Cancel Orders (WebSocket)

Cancel one or more existing orders through the WebSocket connection for fastest order management.

Action Result Notifications

This method executes cancellations immediately. Cancellation events are automatically sent via SubAccount Updates Subscription if subscribed.

Endpoint

ws.send() wss://api.synthetix.io/v1/ws/trade

Request

Request Format

{
  "id": "cancel-1",
  "method": "post",
  "params": {
    "action": "cancelOrders",
    "subAccountId": "1867542890123456789",
    "orderIds": ["1948058938469519360", "1948058938469519361"],
    "source": "direct",
    "nonce": 1704067200000,
    "expiresAfter": 1704067300,
    "signature": {
      "v": 28,
      "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 "cancelOrders"
subAccountIdstringYesSubaccount ID to cancel orders from
orderIdsarrayYesArray of order IDs to cancel (strings)
sourcestringNoRequest source identifier for tracking and rebates (max 100 characters). Use "direct" for generic integrations
nonceintegerYesPositive integer, incrementing nonce
expiresAfterintegerNoOptional expiration Unix timestamp in seconds (0 = no expiration)
signatureobjectYesEIP-712 signature with v, r, s components

EIP-712 Type Definition

const CancelOrdersTypes = {
  CancelOrders: [
    { name: "subAccountId", type: "uint256" },
    { name: "orderIds", type: "uint256[]" },
    { name: "nonce", type: "uint256" },
    { name: "expiresAfter", type: "uint256" }
  ]
}

Note: orderIds is uint256[] in EIP-712, but sent as string[] in the JSON request body.

Response Format

Success Response

{
  "id": "cancel-1",
  "status": 200,
  "result": {
    "status": "success",
    "response": {
      "statuses": [
        {
          "order": {
            "venueId": "1948058938469519360",
            "clientId": "cli-1948058938469519360"
          },
          "orderId": "1948058938469519360",
          "message": "Canceled"
        },
        {
          "order": {
            "venueId": "1948058938469519361",
            "clientId": "cli-1948058938469519361"
          },
          "orderId": "1948058938469519361",
          "message": "Canceled"
        }
      ]
    }
  }
}

Partial Success Response

If some orders fail to cancel, individual order statuses will contain error messages:

{
  "id": "cancel-1",
  "status": 200,
  "result": {
    "status": "success",
    "response": {
      "statuses": [
        {
          "order": {
            "venueId": "1948058938469519360",
            "clientId": "cli-1948058938469519360"
          },
          "orderId": "1948058938469519360",
          "message": "Canceled"
        },
        {
          "order": {
            "venueId": "0",
            "clientId": ""
          },
          "orderId": "1948058938469519361",
          "message": "Order not found",
          "errorCode": "ORDER_NOT_FOUND"
        }
      ]
    }
  }
}

Migration Note: Use order.venueId as canonical in status items. orderId remains deprecated compatibility output.

Error Response

{
  "id": "cancel-1",
  "status": 400,
  "result": null,
  "error": {
    "code": 400,
    "message": "Invalid request parameters"
  }
}

Implementation Example

// Cancel single order
const subAccountId = "1867542890123456789";
const nonce = Date.now();
const expiresAfter = Math.floor(Date.now() / 1000) + 30; // 30 seconds from now
 
// Create EIP-712 signature (see EIP-712 Signing section below)
const signature = await signCancelOrders({
  subAccountId,
  orderIds: ["1948058938469519360"],
  nonce,
  expiresAfter
});
 
const cancelRequest = {
  id: "cancel-1",
  method: "post",
  params: {
    action: "cancelOrders",
    subAccountId,
    orderIds: ["1948058938469519360"],
    nonce,
    expiresAfter,
    signature
  }
};
 
ws.send(JSON.stringify(cancelRequest));
 
// Cancel multiple orders
const cancelMultiple = {
  id: "cancel-2",
  method: "post",
  params: {
    action: "cancelOrders",
    subAccountId,
    orderIds: ["1948058938469519360", "1948058938469519361", "1948058938469519362"],
    nonce: Date.now(),
    expiresAfter: Math.floor(Date.now() / 1000) + 30,
    signature: await signCancelOrders({
      subAccountId,
      orderIds: ["1948058938469519360", "1948058938469519361", "1948058938469519362"],
      nonce: Date.now(),
      expiresAfter: Math.floor(Date.now() / 1000) + 30
    })
  }
};
 
ws.send(JSON.stringify(cancelMultiple));
 
// Handle response
ws.onmessage = (event) => {
  const response = JSON.parse(event.data);
 
  if (response.id === "cancel-1") {
    if (response.result?.status === "success") {
      response.result.response.statuses.forEach(status => {
        const orderId = status.order?.venueId || status.orderId;
        console.log(`Order ${orderId}: ${status.message}`);
      });
    } else if (response.error) {
      console.error(`Error: ${response.error.message}`);
    }
  }
};

Implementation Notes

  • Cancellation requests must include at least one order ID
  • Order IDs must belong to the authenticated subaccount
  • Authentication timestamps must be strictly increasing per subaccount
  • EIP-712 domain separator must use "Synthetix" for WebSocket endpoints

Cancellation Behavior

  • Only OPEN and PARTIALLY_FILLED orders can be cancelled
  • Filled portions of partially filled orders remain executed
  • Cancellation is immediate upon validation
  • Freed margin becomes available instantly

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

Next Steps