Skip to main content

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

FieldTypeDescription
idstring (UUID)Order identifier. Matches GET /spot/orders.
symbolstringMarket, e.g. DFUSDT.
sidestringbuy or sell. See Enums — Order Side.
typestringlimit or market. See Enums — Order Type.
tifstringgtc, ioc, or post_only. See Enums — Time-In-Force.
pricestring (decimal) or nullLimit price. null for market orders.
quantitystring (decimal) or nullBase quantity (DF). null for market-buy orders that used quote_quantity.
quote_quantitystring (decimal) or nullQuote quantity (USDT) for market-buy orders; null otherwise.
filled_qtystring (decimal)Cumulative base quantity filled so far.
avg_fill_pricestring (decimal)Volume-weighted average fill price. "0" if no fills yet.
statusstringCurrent order status. See Enums — Order Status.
reject_reasonstring or nullError code if status == "rejected", e.g. POST_ONLY_REJECT. null otherwise.
updated_atintegerWhen this event occurred — unix seconds.
last_fillobject or absentPresent only when the push was caused by a fill. Omitted on plain place, cancel, and reject.

last_fill fields

FieldTypeDescription
trade_idstring (UUID)Fill identifier (matches GET /spot/trades/me).
pricestring (decimal)Execution price of this fill.
quantitystring (decimal)Base quantity of this fill.
feestring (decimal)Fee amount charged for this fill.
fee_tokenstringToken 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

EventWhen
Order placedImmediately on engine acceptance
Partial fillImmediately per fill (one push per fill per user)
Full fillImmediately on the final fill
Order canceledImmediately on cancellation (user request, IOC remainder, or market delisting)
Order rejectedImmediately 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 + ')' : ''}`);
}
}
};