StreamOrderStatuses - Real-time Order Status Streaming
Stream order lifecycle events from Hyperliquid L1 Gateway via gRPC. Track opens, fills, cancellations, and rejections per block in real time.
Hyperliquid RPC endpoint: endpoint URLs, plans and pricing.
Stream order status events starting from a position, providing real-time access to the lifecycle of every order on Hyperliquid: opens, fills, cancellations, and rejections.
Full Code Examples
Clone our gRPC Code Examples Repository for complete, runnable implementations in Go, Python, and Node.js.
When to Use This Method
StreamOrderStatuses is essential for:
- Order Lifecycle Tracking - Follow an order from open through fill, cancel, or rejection
- Rejection Analysis - Identify why orders are rejected using the
statusfield - Resting-Order Context - Read the full order object behind each status change
- Compliance and Auditing - Record every status transition with block alignment
Method signature
rpc StreamOrderStatuses(StreamRequest) returns (stream Record) {}V3 accepts an inclusive position.block_number or Unix-millisecond position.timestamp. Explicit zero is invalid. A positioned call replays inclusively and then tails live; an empty request tails newly written status records. Set progress to opt in to progress frames.
filter: {
fields: {
field: "users"
op: FILTER_OP_IN
values: "0x1111111111111111111111111111111111111111"
}
}Order statuses accept users, coins and dexes filters. User matching is case-insensitive, coin matching is case-sensitive and dex matching is exact on the HIP-3 dex prefix; values within a field use OR semantics and separate fields use AND semantics. Records with zero matching events are skipped. Each Record contains optional block_number and timestamp cursors plus the filtered envelope in data. A pruned position returns NOT_FOUND; malformed filters return INVALID_ARGUMENT.
grpcurl \
-import-path content/docs/hyperliquid/grpc \
-proto v3.proto \
-H "x-api-key: ${DWELLIR_API_KEY}" \
-d '{"position":{"block_number":"1058646974"},"filter":{"fields":[{"field":"coins","op":"FILTER_OP_IN","values":["BTC"]}]}}' \
"${HYPERLIQUID_GRPC_ENDPOINT}" \
hyperliquid_l1_gateway.v3.HyperliquidL1Gateway/StreamOrderStatusesResponse Stream
V3 carries the JSON-encoded node_order_statuses_by_block envelope in Record.data.
Decode the data field to access:
- Block reference (
local_time,block_time,block_number) - An
eventsarray of status records - A full order object behind each status change
Full Order Status Spec
StreamOrderStatuses emits a JSON payload matching Hyperliquid's node_order_statuses_by_block format. The envelope is the same block-envelope shape as fills, but events holds status-record objects rather than [address, fill] tuples.
Top-level keys (always present):
{
"local_time": "2026-04-20T00:00:00.040479928", // ISO-8601 timestamp when node processed the block (nanosecond precision)
"block_time": "2026-04-19T23:59:59.576040791", // ISO-8601 timestamp from block consensus
"block_number": 12345, // Block height containing these events
"events": [ // Array of status-record objects
{
"time": "2026-04-19T23:59:59.576040791", // Event timestamp (string, not integer ms)
"user": "0x1234567890abcdef1234567890abcdef12345678", // User address
"hash": "0x00...", // Transaction hash (nullable)
"builder": { "b": "0x00...", "f": 50 }, // Builder address and fee (nullable)
"status": "open", // Status value (see table below)
"order": { } // Full order object (see Order Object)
}
]
}Status event fields (events[i]):
| Field | Type | Description |
|---|---|---|
time | string | Event timestamp in the no-Z layout. Note: this is a string, not an integer millisecond value |
user | string | User address |
hash | string or null | Transaction hash. null for some statuses (for example reduceOnlyCanceled) |
builder | object or null | { "b": <address>, "f": <fee> }, the builder address and fee |
status | string | Status value. See Status Values |
order | object | The resting-order view. See Order Object |
Status Values
Observed status values (the list is not exhaustive):
| Status | Meaning |
|---|---|
open | Order accepted and resting on the book |
filled | Order filled |
canceled | Order canceled |
reduceOnlyCanceled | Reduce-only order canceled |
badAloPxRejected | Add-liquidity-only order rejected on price |
insufficientSpotBalanceRejected | Rejected for insufficient spot balance |
iocCancelRejected | Immediate-or-cancel order rejected |
minTradeNtlRejected | Rejected for failing minimum trade notional |
perpMarginRejected | Rejected for insufficient perp margin |
reduceOnlyRejected | Reduce-only order rejected |
selfTradeCanceled | Canceled to prevent a self-trade |
Order Object
The order field is the shared resting-order schema, the same object returned by GetOrderBookSnapshot.
| Field | Type | Description |
|---|---|---|
coin | string | Coin identifier |
side | string | "B" or "A" |
limitPx | string | Limit price (numeric string) |
sz | string | Current size (numeric string) |
oid | number | Order identifier. Not reliably unique across coins. See Order Identifiers |
timestamp | number | Order-creation time in Unix milliseconds |
triggerCondition | string | "N/A" for non-trigger orders |
isTrigger | boolean | Whether the order is a trigger order |
triggerPx | string | "0.0" when isTrigger is false |
children | array | Nested trigger-order schedule. Trigger orders (TP/SL) live here, not as top-level entries. Empty for non-trigger parents |
isPositionTpsl | boolean | Whether this is a position-level take-profit / stop-loss |
reduceOnly | boolean | Whether the order is reduce-only |
orderType | string | "Limit", "Trigger", etc. |
origSz | string | Original size |
tif | string | Time-in-force, for example "Alo", "Gtc", "Ioc" |
cloid | string or null | Client order ID |
Guarantees and alignment:
eventscontains all status records from the block, across all coins and users.- Messages arrive in strictly increasing
block_number, one per source block (including blocks with an emptyeventsarray). block_numberis sequential and distinct from the potentially skippingabci_block.roundconsensus value in StreamBlocks;block_timealigns withabci_block.time.
Developer tips:
- Branch on
statusto track lifecycle transitions and isolate rejections. - Handle
hashandbuilderdefensively; both can benull. - Treat
timeas a formatted string, distinct from the integer-millisecondtimeon fill events.
Order Identifiers
oid is not reliably unique across coins. Consumers that index or join per-order state must key on the (coin, oid) tuple, never on oid alone.
Outcome markets (HIP-4) demonstrably reuse oids across the two sides of a single market (for example #30 and #31) within one block. Keying on (coin, oid) is safe whether or not oids turn out to be globally unique elsewhere.
Common Use Cases
1. Rejection Monitor
REJECTIONS = {
'badAloPxRejected', 'insufficientSpotBalanceRejected', 'iocCancelRejected',
'minTradeNtlRejected', 'perpMarginRejected', 'reduceOnlyRejected',
}
def count_rejections(block):
counts = {}
for event in block.get('events', []):
status = event['status']
if status in REJECTIONS:
counts[status] = counts.get(status, 0) + 1
return counts2. Streaming Statuses in Python
Open V3 with an empty StreamRequest to tail newly written records, or set StreamRequest.position.block_number for inclusive replay. Decode each Record.data envelope before passing it to the rejection monitor above.
Progress Frames
Progress frames are an application-level heartbeat. Set StreamRequest.progress to receive one after each interval of silence. A users or coins filter can leave the stream silent for minutes. They keep it open through idle-limited proxies, which HTTP/2 keepalive pings do not, and advance your resume cursor through blocks the filter removed.
A progress frame sets Record.progress.scanned_through.block_number and leaves the data fields unset, so check progress before decoding data. Persist scanned_through as an inclusive resume cursor. See progress frames for the full contract.
Error Handling and Reconnection
Reconnect with StreamRequest.position.block_number set to the last committed V3 cursor, from a data record or a progress frame's scanned_through. Replay is inclusive, so deduplicate that record before advancing.
Best Practices
- Connection Management: Implement robust reconnection logic with exponential backoff
- Resumable State: Follow the version-specific recovery guidance above and persist the cursor required by your selected API version
- Stable Keys: Index per-order state on
(coin, oid)to stay correct across coins - Defensive Parsing: Handle nullable
hashandbuilderand the non-exhaustivestatusset - Resource Cleanup: Properly close streams and connections on shutdown
Current Limitations
- Replay History: Available replay history varies by feed and endpoint. A cursor outside retained history returns
NOT_FOUND. - Backpressure: High-volume periods may require careful handling to avoid overwhelming downstream systems
Resources
- GitHub: gRPC Code Examples - Complete working examples
- GetOrderStatuses - Point-in-time order status retrieval
- StreamRawBookDiffs - The sibling block-envelope stream for resting-book changes
- Historical Data - Historical
node_order_statuses_by_blockdownloads
Need help? Contact our support team or check the Hyperliquid gRPC documentation.
StreamMiscEvents - Real-time Miscellaneous Event Streaming
Stream non-fill balance-affecting events from Hyperliquid L1 Gateway via gRPC. Filter by user address. Monitor deposits, withdrawals, transfers, staking, and validator rewards in real-time.
StreamOrderbookSnapshots - Real-time Order Book Streaming
Stream generated order book snapshots with individual order visibility from Hyperliquid L1 Gateway via gRPC.