Documentation Index Fetch the complete documentation index at: https://docs.agg.market/llms.txt
Use this file to discover all available pages before exploring further.
See WebSocket Protocol for the full auth upgrade flow, heartbeat behavior, and
close-code reference. This page focuses on user-specific events.
Authenticated users automatically receive order and balance notifications over the WebSocket. No
separate subscription action is required once the connection has user-level auth.
Connect and authenticate
let accessToken = initialAccessToken ;
const ws = new WebSocket ( `wss://ws.agg.market/ws?appId= ${ appId } &token= ${ accessToken } ` );
You will receive a connection acknowledgement:
{ "type" : "connected" , "appId" : "your-app-id" , "userId" : "user-123" }
If the user signs in after the socket is already open, upgrade the connection in-place:
ws . send ( JSON . stringify ({ action: "authenticate" , token: accessToken }));
// Response: { "type": "authenticated", "userId": "user-123" }
No initial state is sent on authentication. Use GET /execution/balances,
GET /execution/positions, and GET /execution/orders for the current user state, then use the
WebSocket to keep the UI fresh.
Events
Order submitted
Sent after a trade is accepted for execution:
{
"type" : "order_submitted" ,
"venue" : "kalshi" ,
"orderId" : "order-abc-123" ,
"side" : "buy" ,
"price" : 0.55 ,
"size" : 10 ,
"outcomeId" : "vmo_123" ,
"timestamp" : 1710705123456
}
Balance update
Sent when a trade changes the user’s venue balance:
{
"type" : "balance_update" ,
"venue" : "kalshi" ,
"tradingBalanceCents" : 50000 ,
"walletBalanceCents" : 100000 ,
"timestamp" : 1710705123456
}
Order event
Venue-agnostic stream of DAG lifecycle and terminal order status. Discriminate on the inner event field. Common shapes:
// Step lifecycle (drives progress UI)
{
"type" : "order_event" ,
"event" : "step_started" ,
"userId" : "user-123" ,
"orderId" : "order-abc-123" ,
"dagRunId" : "dag_xyz" ,
"stepId" : "execute-..." ,
"stepType" : "submit-order" ,
"sequence" : 3 , // 1-based step index within the DAG
"totalSteps" : 7 , // total step count
"venue" : "polymarket" ,
"timestamp" : 1710705123456
}
// Terminal fill (triggers success toast + position refresh)
{
"type" : "order_event" ,
"event" : "filled" , // or "partial_fill"
"userId" : "user-123" ,
"orderId" : "order-abc-123" ,
"venue" : "polymarket" ,
"filledAmountRaw" : "1000000" ,
"remainingAmountRaw" : "0" ,
"timestamp" : 1710705123456
}
// Failure (triggers error toast)
{
"type" : "order_event" ,
"event" : "failed" ,
"userId" : "user-123" ,
"orderId" : "order-abc-123" ,
"venue" : "polymarket" ,
"errorReason" : "Polymarket CLOB error (400): ..." ,
"timestamp" : 1710705123456
}
event values: dag_started, dag_completed, dag_failed, dag_cancelled, step_started, step_completed, step_waiting, step_failed, step_retrying, filled, partial_fill, failed. The gateway broadcasts every event verbatim — switch on event and ignore types your UI doesn’t care about.
Handle messages
ws . onmessage = ( event ) => {
const msg = JSON . parse ( event . data );
switch ( msg . type ) {
case "order_submitted" :
// Legacy direct-trade event
addOrder ({
id: msg . orderId ,
venue: msg . venue ,
side: msg . side ,
price: msg . price ,
size: msg . size ,
});
break ;
case "balance_update" :
updateBalance ( msg . venue , {
trading: msg . tradingBalanceCents / 100 ,
wallet:
msg . walletBalanceCents != null ? msg . walletBalanceCents / 100 : null ,
});
break ;
case "order_event" :
// Venue-agnostic DAG + order lifecycle
switch ( msg . event ) {
case "step_started" :
case "step_completed" :
case "step_waiting" :
// msg.sequence + msg.totalSteps available for "Step 3 of 7" UI
updateOrderProgress (
msg . orderId ,
msg . event ,
msg . stepType ,
msg . sequence ,
msg . totalSteps ,
);
break ;
case "filled" :
case "partial_fill" :
markOrderTerminal ( msg . orderId , msg . event , msg . filledAmountRaw );
refreshPosition ( msg . venue );
break ;
case "failed" :
case "dag_failed" :
case "step_failed" :
markOrderFailed ( msg . orderId , msg . errorReason ?? msg . error );
break ;
}
break ;
case "error" :
console . error ( msg . message );
break ;
}
};
Refresh-aware reconnect
If the socket closes and your access token may have expired, refresh it before reconnecting:
function connect () {
const ws = new WebSocket ( `wss://ws.agg.market/ws?appId= ${ appId } &token= ${ accessToken } ` );
ws . onclose = async () => {
try {
accessToken = await client . refreshAccessToken ();
} catch {
await client . signOut ();
return ;
}
setTimeout ( connect , 1000 );
};
ws . onmessage = handleMessage ;
}
WebSocket Protocol Full auth upgrade, heartbeat, error, and reconnect reference.
Real-Time Orderbook Outcome-level orderbook subscriptions on the same socket connection.
Real-Time Charts Build live charts from orderbook and trade events.
Token Refresh Session renewal patterns for REST and WebSocket clients.