User Orders
Channel Name
spot:user:orders
Authentication: required. See Authentication.
Description
Streams order lifecycle events for the authenticated user across all spot markets. The server filters pushes by wallet address — only events belonging to the authenticated user are forwarded. Subscribe once and receive events for every symbol.
Subscribe
Authenticate first, then subscribe:
{ "type": "auth_token", "token": "eyJhbGciOiJIUzI1..." }
{ "type": "subscribe", "channel": "spot:user:orders" }
Response:
{ "type": "subscribed", "channel": "spot:user:orders" }
No snapshot is sent. Call GET /spot/orders after subscribing to seed your local order state, then apply incoming spot_user_order pushes to keep it current.
Push Format
spot_user_order
Pushed on every order lifecycle event: place, fill (once per fill per side), cancel, and reject.
Example — order placed (no fill yet):
{
"type": "spot_user_order",
"channel": "spot:user:orders",
"data": {
"id": "8b3d1a2c-4e5f-6789-abcd-ef0123456789",
"symbol": "DFUSDT",
"side": "buy",
"type": "limit",
"tif": "gtc",
"price": "0.5000",
"quantity": "100",
"quote_quantity": null,
"filled_qty": "0",
"avg_fill_price": "0",
"status": "open",
"reject_reason": null,
"updated_at": 1778400000
}
}
Example — partial fill (last_fill present):
{
"type": "spot_user_order",
"channel": "spot:user:orders",
"data": {
"id": "8b3d1a2c-4e5f-6789-abcd-ef0123456789",
"symbol": "DFUSDT",
"side": "buy",
"type": "limit",
"tif": "gtc",
"price": "0.5000",
"quantity": "100",
"quote_quantity": null,
"filled_qty": "30",
"avg_fill_price": "0.5000",
"status": "partially_filled",
"reject_reason": null,
"updated_at": 1778400010,
"last_fill": {
"trade_id": "9f2a1b3c-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
"price": "0.5000",
"quantity": "30",
"fee": "0.015",
"fee_token": "DF"
}
}
}
Example — order canceled:
{
"type": "spot_user_order",
"channel": "spot:user:orders",
"data": {
"id": "8b3d1a2c-4e5f-6789-abcd-ef0123456789",
"symbol": "DFUSDT",
"side": "buy",
"type": "limit",
"tif": "gtc",
"price": "0.5000",
"quantity": "100",
"quote_quantity": null,
"filled_qty": "30",
"avg_fill_price": "0.5000",
"status": "canceled",
"reject_reason": null,
"updated_at": 1778400020
}
}
Example — order rejected:
{
"type": "spot_user_order",
"channel": "spot:user:orders",
"data": {
"id": "7c4e2b1d-5f6a-7890-bcde-f01234567890",
"symbol": "DFUSDT",
"side": "buy",
"type": "limit",
"tif": "post_only",
"price": "0.5001",
"quantity": "50",
"quote_quantity": null,
"filled_qty": "0",
"avg_fill_price": "0",
"status": "rejected",
"reject_reason": "POST_ONLY_REJECT",
"updated_at": 1778400030
}
}
Fields
| Field | Type | Description |
|---|---|---|
id | string (UUID) | Order identifier. Matches GET /spot/orders. |
symbol | string | Market, e.g. DFUSDT. |
side | string | buy or sell. See Enums — Order Side. |
type | string | limit or market. See Enums — Order Type. |
tif | string | gtc, ioc, or post_only. See Enums — Time-In-Force. |
price | string (decimal) or null | Limit price. null for market orders. |
quantity | string (decimal) or null | Base quantity (DF). null for market-buy orders that used quote_quantity. |
quote_quantity | string (decimal) or null | Quote quantity (USDT) for market-buy orders; null otherwise. |
filled_qty | string (decimal) | Cumulative base quantity filled so far. |
avg_fill_price | string (decimal) | Volume-weighted average fill price. "0" if no fills yet. |
status | string | Current order status. See Enums — Order Status. |
reject_reason | string or null | Error code if status == "rejected", e.g. POST_ONLY_REJECT. null otherwise. |
updated_at | integer | When this event occurred — unix seconds. |
last_fill | object or absent | Present only when the push was caused by a fill. Omitted on plain place, cancel, and reject. |
last_fill fields
| Field | Type | Description |
|---|---|---|
trade_id | string (UUID) | Fill identifier (matches GET /spot/trades/me). |
price | string (decimal) | Execution price of this fill. |
quantity | string (decimal) | Base quantity of this fill. |
fee | string (decimal) | Fee amount charged for this fill. |
fee_token | string | Token in which the fee was charged — DF if you received DF (buy side or maker-on-sell), USDT if you received USDT (sell side or maker-on-buy). Hard-coded for the DFUSDT MVP; future markets may differ. |
Update Cadence
| Event | When |
|---|---|
| Order placed | Immediately on engine acceptance |
| Partial fill | Immediately per fill (one push per fill per user) |
| Full fill | Immediately on the final fill |
| Order canceled | Immediately on cancellation (user request, IOC remainder, or market delisting) |
| Order rejected | Immediately on rejection |
Code Example
const ws = new WebSocket('wss://api-sepolia.p99.world/ws');
// Local order map: id -> order data
const orders = new Map();
ws.onopen = () => {
// 1. Authenticate
ws.send(JSON.stringify({ type: 'auth_token', token: '<JWT>' }));
setInterval(() => ws.send(JSON.stringify({ type: 'ping' })), 30000);
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.type === 'auth_result' && msg.success) {
// 2. Seed local state from REST
fetch('https://api-sepolia.p99.world/api/v1/spot/orders', {
headers: { Authorization: 'Bearer <JWT>' },
})
.then((r) => r.json())
.then((list) => list.forEach((o) => orders.set(o.id, o)));
// 3. Subscribe
ws.send(JSON.stringify({ type: 'subscribe', channel: 'spot:user:orders' }));
}
if (msg.type === 'spot_user_order') {
const o = msg.data;
orders.set(o.id, o);
if (o.last_fill) {
console.log(`Fill on order ${o.id}: qty=${o.last_fill.quantity} @ ${o.last_fill.price} fee=${o.last_fill.fee} ${o.last_fill.fee_token}`);
} else {
console.log(`Order ${o.id} → status=${o.status}${o.reject_reason ? ' (' + o.reject_reason + ')' : ''}`);
}
}
};