Skip to content

WebSocket Order Updates API

Real-time order updates with automatic reconnection for monitoring order status, executions, and rejections.

Overview

The WebSocket Order Updates API provides instant notifications for all order-related events including placements, modifications, cancellations, executions, and rejections. This is a push-only connection — after authenticating, the server streams every order event for the connected user. There are no subscribe/unsubscribe messages.

Executions (fills) arrive as ORDER_UPDATE messages with reportType: "Fill"; there is no separate trade socket. Position updates are not delivered on this stream — use the Positions API to poll positions.

Python SDK

The Python SDK wraps this WebSocket in ArrowStreams.connect_order_stream(). See the WebSocket Streaming guide for SDK-level usage, event handlers, and examples.

Key Features

  • Real-Time Order Updates: Instant notifications for all order state changes
  • Push-Only Protocol: No subscription messages required; all order events are delivered automatically
  • Automatic Reconnection: Built-in exponential backoff retry mechanism
  • Heartbeat Monitoring: Active connection health checks with configurable client-side intervals
  • Session-Based Authentication: Secure connection using session tokens
  • Text-Based Protocol: JSON messages for easy parsing and debugging

Connection Setup

WebSocket Endpoint

wss://order-updates.arrow.trade?appID=<APP_ID>&token=<TOKEN>

Authentication Parameters

Parameter Type Required Description
appID string Your application identifier
token string User authentication token

Connection Examples

websocat "wss://order-updates.arrow.trade?appID=<YOUR_APP_ID>&token=<YOUR_TOKEN>"
const APP_ID = "<YOUR_APP_ID>";
const TOKEN = "<YOUR_TOKEN>";
const wsUrl = `wss://order-updates.arrow.trade?appID=${APP_ID}&token=${TOKEN}`;
const ws = new WebSocket(wsUrl);

ws.onopen = () => console.log('Connected to order updates');

ws.onmessage = (event) => {
    const update = JSON.parse(event.data);
    if (update.id) {
        console.log(`Order ${update.id}: ${update.orderStatus} (${update.reportType})`);
    }
};

ws.onerror = (err) => console.error('WebSocket error:', err);
ws.onclose = () => console.log('Disconnected');
import json
import websocket

APP_ID = "<YOUR_APP_ID>"
TOKEN = "<YOUR_TOKEN>"
ws_url = f"wss://order-updates.arrow.trade?appID={APP_ID}&token={TOKEN}"

def on_message(ws, message):
    update = json.loads(message)
    if update.get("id"):
        print(f"Order {update['id']}: {update['orderStatus']} ({update['reportType']})")

def on_open(ws):
    print("Connected to order updates")

ws = websocket.WebSocketApp(ws_url, on_message=on_message, on_open=on_open)
ws.run_forever()

Connection Management

Heartbeat Protocol

The connection maintains health through a client-side heartbeat mechanism. Custom clients should send a plain-text PONG message (not JSON) at a regular interval and treat prolonged read silence as a stale connection.

The Python SDK (ConnectionConfig) uses these defaults for all WebSocket streams (order, data, and HFT):

  • Client Ping: Sends plain-text PONG every 3 seconds (ping_interval)
  • Read Timeout: 5 seconds without an incoming message closes the connection and triggers reconnection (read_timeout)
  • Automatic Recovery: Reconnects on timeout or connection loss when enable_reconnect is true

Reconnection Strategy

Built-in exponential backoff with configurable parameters. Python SDK defaults (ConnectionConfig):

Parameter Default Description
enable_reconnect true Enable automatic reconnection
max_reconnect_attempts 300 Maximum reconnection attempts
immediate_reconnect_attempts 3 First N attempts with no delay
max_reconnect_delay 5 seconds Maximum delay between attempts
ping_interval 3 seconds Interval for client PONG messages
read_timeout 5 seconds Idle read timeout before reconnect

Backoff schedule (Python SDK):

  • Attempts 1–3: immediate (0 second delay)
  • Attempt 4: 2 seconds (2^1, capped at 5)
  • Attempt 5: 4 seconds (2^2, capped at 5)
  • Attempt 6+: 5 seconds (capped at max_reconnect_delay)

Reconcile on reconnect

After reconnecting, fetch the full order book via GET /user/orders to catch any updates missed during the disconnection window.

Order Update Messages

Message Format

All order updates are JSON text frames with the following structure:

{
  "updateType": "ORDER_UPDATE",
  "userID": "AJ0001",
  "accountID": "AJ0001",
  "exchange": "NFO",
  "symbol": "NIFTY27JAN26C25300",
  "id": "26012301000023",
  "price": "0.05",
  "quantity": "65",
  "product": "M",
  "orderStatus": "PENDING",
  "reportType": "PendingNew",
  "transactionType": "B",
  "order": "LMT",
  "cumulativeFillQty": "0",
  "fillShares": "0",
  "averagePrice": "0",
  "exchangeOrderID": "0",
  "cancelQuantity": "0",
  "orderTriggerPrice": "0",
  "validity": "DAY",
  "pricePrecision": "2",
  "tickSize": "0.05",
  "lotSize": "65",
  "token": "58695",
  "orderTime": "2026-01-23T13:40:53",
  "orderSource": "WEB",
  "leavesQuantity": "65"
}

Additional Examples

Exchange Ack (Order Open)

{
  "updateType": "ORDER_UPDATE",
  "userID": "AJ0001",
  "accountID": "AJ0001",
  "exchange": "NFO",
  "symbol": "NIFTY02DEC25C26100",
  "id": "25120202000010",
  "price": "34",
  "quantity": "75",
  "product": "M",
  "orderStatus": "OPEN",
  "reportType": "NewAck",
  "transactionType": "B",
  "order": "MKT",
  "cumulativeFillQty": "0",
  "fillShares": "0",
  "averagePrice": "0",
  "exchangeOrderID": "1400000055208129",
  "cancelQuantity": "0",
  "orderTriggerPrice": "0",
  "validity": "DAY",
  "pricePrecision": "2",
  "tickSize": "0.05",
  "lotSize": "75",
  "token": "46799",
  "orderTime": "2025-12-02T10:16:16",
  "exchangeUpdateTime": "2025-12-02T10:16:16",
  "exchangeTime": "2025-12-02T10:16:16",
  "orderSource": "WEB",
  "isAck": true,
  "leavesQuantity": "75"
}

Fill (Order Complete)

{
  "updateType": "ORDER_UPDATE",
  "userID": "AJ0001",
  "accountID": "AJ0001",
  "exchange": "NFO",
  "symbol": "NIFTY02DEC25C26100",
  "id": "25120202000010",
  "price": "34",
  "quantity": "75",
  "product": "M",
  "orderStatus": "COMPLETE",
  "reportType": "Fill",
  "transactionType": "B",
  "order": "MKT",
  "cumulativeFillQty": "75",
  "fillShares": "75",
  "averagePrice": "34",
  "exchangeOrderID": "1400000055208129",
  "cancelQuantity": "0",
  "orderTriggerPrice": "0",
  "validity": "DAY",
  "pricePrecision": "2",
  "tickSize": "0.05",
  "lotSize": "75",
  "token": "46799",
  "orderTime": "2025-12-02T10:16:16",
  "exchangeUpdateTime": "2025-12-02T10:16:16",
  "exchangeTime": "2025-12-02T10:16:16",
  "orderSource": "WEB",
  "isAck": true,
  "leavesQuantity": "0"
}

Partial vs full fill

Both partial and full fills use reportType: "Fill". Distinguish them by checking orderStatus (OPEN or PARTIALLY_FILLED for partial, COMPLETE for full) and leavesQuantity (remaining unfilled quantity).

Rejection

{
  "updateType": "ORDER_UPDATE",
  "userID": "AJ0001",
  "accountID": "AJ0001",
  "exchange": "NSE",
  "symbol": "IDEA-EQ",
  "id": "25120202000012",
  "rejectReason": "The price lies outside the DPR range",
  "price": "7.5",
  "quantity": "2",
  "product": "I",
  "orderStatus": "REJECTED",
  "reportType": "Rejected",
  "transactionType": "B",
  "order": "LMT",
  "cumulativeFillQty": "0",
  "fillShares": "0",
  "averagePrice": "0",
  "exchangeOrderID": "0",
  "cancelQuantity": "0",
  "remarks": "234",
  "validity": "DAY",
  "pricePrecision": "2",
  "tickSize": "0.01",
  "lotSize": "1",
  "token": "14366",
  "orderTime": "2025-12-02T11:32:31",
  "exchangeUpdateTime": "2025-12-02T11:32:31",
  "exchangeTime": "2025-12-02T11:32:31",
  "orderSource": "WEB",
  "isAck": true,
  "leavesQuantity": "0"
}

Cancellation

{
  "updateType": "ORDER_UPDATE",
  "userID": "AJ0001",
  "accountID": "AJ0001",
  "exchange": "NSE",
  "symbol": "IDEA-EQ",
  "id": "25120202000013",
  "price": "10",
  "quantity": "10",
  "product": "I",
  "orderStatus": "CANCELLED",
  "reportType": "Canceled",
  "transactionType": "B",
  "order": "LMT",
  "cumulativeFillQty": "0",
  "fillShares": "0",
  "averagePrice": "0",
  "exchangeOrderID": "1100000029104706",
  "cancelQuantity": "10",
  "remarks": "234",
  "validity": "DAY",
  "pricePrecision": "2",
  "tickSize": "0.01",
  "lotSize": "1",
  "token": "14366",
  "orderTime": "2025-12-02T11:33:07",
  "exchangeUpdateTime": "2025-12-02T11:33:07",
  "exchangeTime": "2025-12-02T11:33:07",
  "orderSource": "WEB",
  "isAck": true,
  "leavesQuantity": "0"
}

Field Reference

Field Type Description Example
updateType string Message type (always "ORDER_UPDATE") "ORDER_UPDATE"
userID string User identifier "AJ0001"
accountID string Trading account identifier "AJ0001"
exchange string Exchange code "NFO", "NSE", "BSE", "BFO", "MCXFO"
symbol string Trading symbol "NIFTY27JAN26C25300"
id string Unique order identifier "26012301000023"
price string Order price "0.05"
quantity string Order quantity "65"
product string Product type "I" (Intraday), "C" (Delivery), "M" (Normal/F&O)
orderStatus string Current order status See Order Status table
reportType string Type of update report See Report Types table
transactionType string Buy or Sell "B" (Buy), "S" (Sell)
order string Order type "LMT", "MKT", "SL-LMT", "SL-MKT"
cumulativeFillQty string Total filled quantity across all fills "0"
fillShares string Shares filled in this update "0"
averagePrice string Average execution price "0"
exchangeOrderID string Exchange-assigned order ID "0"
cancelQuantity string Cancelled quantity "0"
orderTriggerPrice string Trigger price for stop orders "0"
validity string Order validity "DAY", "IOC"
pricePrecision string Decimal precision for price "2"
tickSize string Minimum price increment "0.05"
lotSize string Trading lot size "65"
token string Instrument token "58695"
orderTime string Order timestamp (ISO format) "2026-01-23T13:40:53"
orderSource string Order entry source "WEB", "API", "MOBILE"
leavesQuantity string Remaining unfilled quantity "65"
rejectReason string Rejection reason (present when orderStatus is REJECTED) "The price lies outside the DPR range"
remarks string Custom order tag set via place/modify (max 16 characters) "strategy_1"
exchangeUpdateTime string Last update timestamp from the exchange (ISO format, present on acked orders) "2025-12-02T10:16:16"
exchangeTime string Exchange system timestamp (ISO format) "2025-12-02T10:16:16"
isAck boolean Whether the order has been acknowledged by the exchange true
disclosedQuantity string Disclosed quantity for iceberg orders "0"
fillPrice string Fill price for this execution (present on fill updates) "34"
marketProtection string Market protection percentage applied to the order "0"

triggerPrice vs orderTriggerPrice

When placing or modifying an order, the request field is triggerPrice. In order update messages (and GET /user/orders responses), the same value appears as orderTriggerPrice.

Report Types

The reportType field indicates the type of order update:

Report Type Description Example Scenario
PendingNew Order submitted, awaiting exchange acknowledgement New order placed
NewAck Order accepted and acknowledged by exchange Order becomes active (OPEN)
Fill Execution occurred (partial or full) Quantity filled; check orderStatus and leavesQuantity to distinguish partial from complete
Replaced Order modified successfully Price or quantity changed
Canceled Order cancelled User or system cancellation
Rejected Order rejected by exchange or RMS Insufficient margin, price outside DPR, etc.
Expired Order expired End of trading session
Triggered Stop order triggered Trigger price reached

Order Status Values

Status Description Terminal State
PENDING Order submitted, awaiting exchange No
OPEN Active order in market No
PARTIALLY_FILLED Partially executed, remaining quantity still open No
COMPLETE Fully executed Yes
CANCELLED Cancelled by user/system Yes
REJECTED Rejected by exchange or RMS Yes
TRIGGER_PENDING Stop order waiting for trigger price No
AFTER_MARKET_ORDER_REQ_RECEIVED AMO order queued for next session No

Order Type Codes

Code Full Name Description
LMT Limit Order at specified price or better
MKT Market Plain MKT is disabled by default on the place-order API — use mpp: true for market-style routing (Upper Limit / DPR by instrument)
SL-LMT Stop Loss Limit Stop order with limit price
SL-MKT Stop Loss Market Stop order at market price

Transaction Type Codes

Code Full Name
B Buy
S Sell

Product Type Codes

Code Full Name Description
I Intraday Same-day position closure (auto-squared off near session end)
C Cash / Delivery Equity delivery orders (T+1 settlement)
M Normal / Margin F&O orders including MCXFO (standard margin)

Exchange Codes

Code Description
NSE National Stock Exchange — Equity
NFO NSE Futures & Options
BSE Bombay Stock Exchange — Equity
BFO BSE Futures & Options
MCXFO MCX Futures & Options

Troubleshooting

Issue Cause Solution
Connection Fails Invalid appID/token Verify credentials are current and valid
Frequent Disconnects Network instability Check network quality, increase timeout
Missing Updates Connection dropped Fetch order status via GET /user/orders on reconnect
Duplicate Updates Network retry Deduplicate using order id + orderTime
High CPU Usage Too many handlers Optimize callback functions, batch updates
Memory Leaks Handlers not cleaned Remove handlers when components unmount
Wrong Field Names Using old documentation Use id instead of orderId, symbol instead of tradingSymbol
String vs Number Field type mismatch Parse string fields to numbers: parseInt(), parseFloat()