Overview
The SDK provides three WebSocket-based event streaming methods:
listen - Subscribe to user-specific events (orders, positions, deposits, withdrawals)
listenToKalshiEvent - Subscribe to market ticker updates for a specific Kalshi event
listenToOrderbook - Subscribe to real-time orderbook snapshots and deltas for a specific market
All methods support automatic reconnection with exponential backoff.
User Events
Subscribe to events for a specific user address.
listen
listen(
userAddress: string,
onEvent: (event: BisonEvent) => void,
options?: {
onError?: (error: Error) => void;
onConnect?: () => void;
onDisconnect?: () => void;
reconnect?: boolean;
}
): () => void
Parameters
User’s Ethereum address to listen for events
Callback function that receives events as they occur
Optional callback for handling WebSocket errors
Optional callback invoked when WebSocket connection is established
Optional callback invoked when WebSocket connection closes
Enable automatic reconnection (default: true). Uses exponential backoff with max 5 attempts.
Returns
A disconnect function to stop listening and close the WebSocket connection.
Event Types
The callback receives one of the following event types:
Order Events:
order_placed - New order submitted
order_filled - Order matched and executed
order_cancelled - Order cancelled
Position Events:
position_minted - New position tokens created
position_burned - Position tokens destroyed
USDC Events:
usdc_deposited - USDC deposited to vault
usdc_withdrawn - USDC withdrawn from vault
Market Events:
market_opened - Market opened for trading
market_closed - Market closed for trading
market_settled - Market outcome determined
Example
import { createBisonClient } from 'bison-sdk-ts';
const client = createBisonClient({
baseUrl: 'https://api.bison.markets'
});
const disconnect = client.listen(
'0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
(event) => {
switch (event.type) {
case 'order_placed':
console.log(`Order placed: ${event.orderId}`, {
market: event.marketId,
action: event.action,
side: event.side,
quantity: event.number,
price: event.priceUusdc / 1_000_000,
});
break;
case 'order_filled':
console.log(`Order filled: ${event.orderId}`);
break;
case 'usdc_deposited':
const usdcAmount = event.uusdcAmount / 1_000_000;
console.log(`Deposited ${usdcAmount} USDC`);
break;
case 'position_minted':
console.log(`Minted ${event.number} ${event.side} tokens for ${event.marketId}`);
break;
case 'market_settled':
console.log(`Market ${event.marketId} settled:`, event.result);
break;
default:
console.log('Received event:', event);
}
},
{
onConnect: () => console.log('Connected to event stream'),
onDisconnect: () => console.log('Disconnected from event stream'),
onError: (error) => console.error('WebSocket error:', error),
reconnect: true,
}
);
// Later, when you want to stop listening:
// disconnect();
Market Ticker Updates
Subscribe to real-time price and volume updates for a specific Kalshi event.
listenToKalshiEvent
listenToKalshiEvent(
eventTicker: string,
onTicker: (update: KalshiTickerUpdate) => void,
options?: {
onError?: (error: Error) => void;
onConnect?: () => void;
onDisconnect?: () => void;
reconnect?: boolean;
}
): () => void
Parameters
Kalshi event ticker (e.g., "KXFEDDECISION-26JAN")
Callback function that receives ticker updates for markets in the event
Optional callback for handling WebSocket errors
Optional callback invoked when WebSocket connection is established
Optional callback invoked when WebSocket connection closes
Enable automatic reconnection (default: true). Uses exponential backoff with max 5 attempts.
Returns
A disconnect function to stop listening and close the WebSocket connection.
Ticker Update Fields
Current best bid price for YES side in µUSDC
Current best ask price for YES side in µUSDC
Current best bid price for NO side in µUSDC
Current best ask price for NO side in µUSDC
Last traded price in µUSDC
Current open interest (outstanding contracts)
Example
const disconnect = client.listenToKalshiEvent(
'KXFEDDECISION-26JAN',
(update) => {
console.log(`Market: ${update.market_ticker}`);
if (update.yes_bid_uusdc && update.yes_ask_uusdc) {
const yesBid = update.yes_bid_uusdc / 1_000_000;
const yesAsk = update.yes_ask_uusdc / 1_000_000;
console.log(`YES: $${yesBid} bid / $${yesAsk} ask`);
}
if (update.no_bid_uusdc && update.no_ask_uusdc) {
const noBid = update.no_bid_uusdc / 1_000_000;
const noAsk = update.no_ask_uusdc / 1_000_000;
console.log(`NO: $${noBid} bid / $${noAsk} ask`);
}
if (update.last_price_uusdc) {
console.log(`Last: $${update.last_price_uusdc / 1_000_000}`);
}
if (update.volume !== undefined) {
console.log(`Volume: ${update.volume}`);
}
if (update.open_interest !== undefined) {
console.log(`Open Interest: ${update.open_interest}`);
}
},
{
onConnect: () => console.log('Connected to Kalshi event stream'),
reconnect: true,
}
);
// Stop listening when done
// disconnect();
Orderbook Updates
Subscribe to real-time orderbook data for a specific market, including initial snapshots and incremental updates.
listenToOrderbook
listenToOrderbook(
marketTicker: string,
onUpdate: (update: OrderbookUpdate) => void,
options?: {
onError?: (error: Error) => void;
onConnect?: () => void;
onDisconnect?: () => void;
reconnect?: boolean;
}
): () => void
Parameters
Kalshi market ticker (e.g., "KXBTC-100K-DEC31")
Callback function that receives orderbook updates (snapshots and deltas)
Optional callback for handling WebSocket errors
Optional callback invoked when WebSocket connection is established
Optional callback invoked when WebSocket connection closes
Enable automatic reconnection (default: true). Uses exponential backoff with max 5 attempts.
Returns
A disconnect function to stop listening and close the WebSocket connection.
Update Types
The callback receives one of two update types:
Snapshot Update (OrderbookSnapshot):
- Sent immediately upon connection
- Contains the complete current orderbook state
- Fields:
type, market_ticker, yes, no
Delta Update (OrderbookDelta):
- Sent for each orderbook change
- Contains incremental updates to specific price levels
- Fields:
type, market_ticker, side, price_uusdc, delta
Example
import { createBisonClient } from 'bison-sdk-ts';
const client = createBisonClient({
baseUrl: 'https://api.bison.markets'
});
// Track orderbook state
const orderbook = {
yes: new Map<number, number>(), // price -> quantity
no: new Map<number, number>() // price -> quantity
};
const disconnect = client.listenToOrderbook(
'KXBTC-100K-DEC31',
(update) => {
if (update.type === 'orderbook_snapshot') {
// Initialize orderbook with full snapshot
orderbook.yes.clear();
orderbook.no.clear();
update.yes?.forEach(level => {
orderbook.yes.set(level.price_uusdc, level.quantity);
});
update.no?.forEach(level => {
orderbook.no.set(level.price_uusdc, level.quantity);
});
console.log('Orderbook initialized');
console.log(`YES levels: ${orderbook.yes.size}`);
console.log(`NO levels: ${orderbook.no.size}`);
} else if (update.type === 'orderbook_delta') {
// Apply incremental update
const book = update.side === 'yes' ? orderbook.yes : orderbook.no;
const currentQty = book.get(update.price_uusdc) || 0;
const newQty = currentQty + update.delta;
if (newQty <= 0) {
book.delete(update.price_uusdc);
} else {
book.set(update.price_uusdc, newQty);
}
const priceUSDC = (update.price_uusdc / 1_000_000).toFixed(2);
console.log(`${update.side.toUpperCase()} @ $${priceUSDC}: ${newQty} contracts`);
}
},
{
onConnect: () => console.log('Connected to orderbook'),
onError: (error) => console.error('Orderbook error:', error),
reconnect: true,
}
);
// Helper function to get best bid/ask
function getBestPrices() {
const yesPrices = Array.from(orderbook.yes.keys());
const noPrices = Array.from(orderbook.no.keys());
return {
yesBid: yesPrices.length > 0 ? Math.max(...yesPrices) : null,
yesAsk: yesPrices.length > 0 ? Math.min(...yesPrices) : null,
noBid: noPrices.length > 0 ? Math.max(...noPrices) : null,
noAsk: noPrices.length > 0 ? Math.min(...noPrices) : null,
};
}
// Use after receiving updates
setTimeout(() => {
const prices = getBestPrices();
console.log('Best prices:', {
yes: prices.yesBid && prices.yesAsk
? `${prices.yesBid / 1_000_000} / ${prices.yesAsk / 1_000_000}`
: 'N/A',
no: prices.noBid && prices.noAsk
? `${prices.noBid / 1_000_000} / ${prices.noAsk / 1_000_000}`
: 'N/A',
});
}, 1000);
// Stop listening when done
// disconnect();
Connection Management
All three methods return a disconnect function that should be called to properly clean up the WebSocket connection:
const disconnectUser = client.listen(userAddress, onEvent);
const disconnectEvent = client.listenToKalshiEvent(eventTicker, onTicker);
const disconnectOrderbook = client.listenToOrderbook(marketTicker, onUpdate);
// Later, when component unmounts or user logs out:
disconnectUser();
disconnectEvent();
disconnectOrderbook();
Automatic Reconnection
The SDK automatically handles connection failures with exponential backoff:
- Initial reconnect delay: 1 second
- Maximum reconnect delay: 30 seconds
- Maximum reconnect attempts: 5
- Heartbeat interval: 30 seconds
When the maximum number of reconnect attempts is reached, the connection will stop trying to reconnect. You can manually reconnect by calling the listen method again.
Error Handling
const disconnect = client.listen(
userAddress,
(event) => {
console.log('Event:', event);
},
{
onError: (error) => {
// Handle WebSocket errors
console.error('Connection error:', error.message);
// Optionally notify user or trigger fallback behavior
showErrorNotification('Lost connection to event stream');
},
onDisconnect: () => {
// Connection closed
console.log('Disconnected. Will attempt to reconnect...');
}
}
);
Important Notes
- WebSocket connections are automatically kept alive with periodic heartbeat messages
- Events are delivered in real-time as they occur on the blockchain or Kalshi platform
- Multiple subscriptions can be active simultaneously (user events, market tickers, orderbooks)
- Reconnection is enabled by default but can be disabled by setting
reconnect: false
- Always call the disconnect function to avoid memory leaks when cleaning up
- For orderbook subscriptions, always process the initial snapshot before applying deltas
- Orderbook delta updates are cumulative - add them to existing quantities, don’t replace