Endpoint
Connection flow
1. Connect
Open a WebSocket connection. No authentication is needed at connection time.
2. Login
Send a login message within 30 seconds of connecting:
{
"type" : "login" ,
"apiKey" : "YOUR_API_KEY" ,
"channels" : []
}
An empty channels array subscribes to all available channels. To subscribe to specific channels:
{
"type" : "login" ,
"apiKey" : "YOUR_API_KEY" ,
"channels" : [ "orders" , "bets" , "settlements" ]
}
You can optionally enable reliable delivery with message acknowledgments:
{
"type" : "login" ,
"apiKey" : "YOUR_API_KEY" ,
"channels" : [ "orders" , "bets" ],
"reliableDelivery" : true
}
3. Login confirmation
On success, the server responds with:
{
"type" : "login_ok" ,
"clientName" : "your-client" ,
"channels" : [ "orders" , "bets" , "settlements" ],
"subscriptionId" : 1 ,
"access" : {
"clientFiltered" : [ "orders" , "bets" , "settlements" , "accounts" , "balance" , "betslip" ],
"global" : [ "fixtures" , "currencies" , "status" , "emergency" ]
},
"reliableDelivery" : false ,
"features" : {
"messageOrdering" : true ,
"acknowledgments" : false ,
"batchAck" : false
}
}
4. Receive updates
Data messages follow this format:
{
"type" : "data" ,
"channel" : "orders" ,
"event" : "INSERT" ,
"payload" : { ... },
"ts" : 1771183909789 ,
"seq" : 1
}
Field Description typeAlways "data" for data messages channelWhich channel this message belongs to eventEvent type: INSERT, UPDATE, DELETE, SETTLED, STATUS payloadThe full updated object (see payload schemas ) tsServer timestamp (milliseconds since epoch) seqPer-subscription monotonically increasing sequence number requireAckPresent and true only when reliable delivery is enabled
Full per-channel payload schemas are in Payload schemas below.
5. Keep alive
The server sends a ping every 30 seconds :
Respond with pong within 120 seconds or the connection is closed:
You can also send pings from the client — the server responds with pong.
Channels
Client-filtered channels
These channels only deliver data belonging to your clientName:
Channel Events Description ordersINSERT, UPDATE, DELETE Order placement, fills, status changes betsINSERT, UPDATE, DELETE Bet placement, confirmation, and removal settlementsSETTLED Settlement status updates (same payload as bets) accountsINSERT, UPDATE, DELETE Account creation, updates, and deletion balanceUPDATE Balance change notifications betslipUPDATE Real-time odds updates for active betslip subscriptions (60s window after each GET /betslip call)
Global channels
All subscribers receive these:
Channel Events Description fixturesUPDATE Fixture metadata and score changes currenciesUPDATE Currency exchange rate updates statusSTATUS System status changes emergencySTATUS Emergency mode activation/deactivation
Reliable delivery & acknowledgments
By default, messages are fire-and-forget — fast, but a message dropped during a disconnect is gone. Enable reliable delivery at login to get at-least-once delivery with acknowledgments and replay:
{ "type" : "login" , "apiKey" : "YOUR_API_KEY" , "channels" : [ "orders" , "bets" ], "reliableDelivery" : true }
When enabled, each data message carries requireAck: true, and you must acknowledge it so the server can release it from its buffer:
{ "type" : "ack" , "seq" : 42 }
Or acknowledge a range in one message (recommended for throughput):
{ "type" : "ack_batch" , "upToSeq" : 50 }
How it works:
The server buffers up to 100 unacknowledged messages per subscription and re-sends any not acked within 30 seconds .
seq is per-subscription and strictly increasing, so a gap in seq means you missed a message.
To recover missed messages after a reconnect, request a replay from the last seq you processed:
{ "type" : "replay" , "fromSeq" : 40 }
If you fall further behind than the 100-message buffer, the oldest unacked messages are dropped. Ack promptly (or use ack_batch) and treat any seq gap that a replay can’t fill as a signal to reconcile via the REST endpoints (GET /orders, GET /bets).
Changing subscriptions
Change channels without reconnecting:
{ "type" : "update_channels" , "channels" : [ "orders" , "bets" , "settlements" ] }
The server replies with channels_updated.
Betslip subscriptions
The betslip channel pushes real-time odds for selections you’re watching. There are two ways to subscribe:
Via REST — calling GET /betslip registers a 60-second sliding window ; each call resets the timer and immediately broadcasts a snapshot over the WebSocket.
Via WebSocket — send a subscribe_betslip message with an explicit ttl (10–3600s) and bookmaker list for finer control, and unsubscribe_betslip to cancel early.
A maximum of 20 active betslip subscriptions per client (REST + WS combined) is enforced. Message shapes and the subscribed_betslip confirmation are documented in Betslip subscription messages below.
Example: Python client
import asyncio
import json
import websockets
async def connect ():
uri = "wss://v2.55-tech.com/ws"
async with websockets.connect(uri) as ws:
# Login
await ws.send(json.dumps({
"type" : "login" ,
"apiKey" : "YOUR_API_KEY" ,
"channels" : [ "orders" , "bets" , "settlements" ]
}))
# Wait for login confirmation
login_resp = json.loads( await ws.recv())
print ( f "Logged in as { login_resp.get( 'clientName' ) } " )
# Listen for updates (respond to pings automatically)
async for message in ws:
data = json.loads(message)
if data[ "type" ] == "ping" :
await ws.send(json.dumps({ "type" : "pong" }))
elif data[ "type" ] == "data" :
print ( f "[ { data[ 'channel' ] } : { data[ 'event' ] } ] { data[ 'payload' ] } " )
asyncio.run(connect())
Example: JavaScript client
const WebSocket = require ( 'ws' );
const ws = new WebSocket ( 'wss://v2.55-tech.com/ws' );
ws . on ( 'open' , () => {
ws . send ( JSON . stringify ({
type: 'login' ,
apiKey: 'YOUR_API_KEY' ,
channels: [ 'orders' , 'bets' , 'settlements' ]
}));
});
ws . on ( 'message' , ( raw ) => {
const msg = JSON . parse ( raw );
if ( msg . type === 'login_ok' ) {
console . log ( `Logged in as ${ msg . clientName } ` );
}
if ( msg . type === 'ping' ) {
ws . send ( JSON . stringify ({ type: 'pong' }));
}
if ( msg . type === 'data' ) {
console . log ( `[ ${ msg . channel } : ${ msg . event } ]` , msg . payload );
}
});
Message types
Client → Server
Type Example Purpose login{"type": "login", "apiKey": "...", "channels": []}Authenticate and subscribe. Optional reliableDelivery: true. update_channels{"type": "update_channels", "channels": ["orders"]}Change channel subscriptions after login. pong{"type": "pong"}Reply to a server ping. ping{"type": "ping"}Liveness check; server replies with pong. ack{"type": "ack", "seq": 42}Acknowledge one message (reliable delivery). ack_batch{"type": "ack_batch", "upToSeq": 50}Acknowledge all messages up to and including upToSeq. replay{"type": "replay", "fromSeq": 40}Request re-send of buffered messages from fromSeq. subscribe_betslipsee below Open a betslip price subscription with a custom TTL. unsubscribe_betslipsee below Cancel a betslip subscription early.
Server → Client
Type Purpose login_okLogin succeeded; echoes channels, access scopes, and enabled features. channels_updatedConfirms an update_channels change. dataA channel event (see payload schemas ). pingServer keep-alive; reply with pong. subscribed_betslipConfirms a subscribe_betslip, with effective expiresAt. errorA problem with a client message; includes a ref to the offending request.
Betslip subscription messages
The betslip channel must be in your subscriptions (add it via login or update_channels) before subscribing.
subscribe_betslip
{
"type" : "subscribe_betslip" ,
"fixtureId" : "id1000004461512432" ,
"outcomeId" : 103 ,
"playerId" : 0 ,
"bookmakers" : [ "pinnacle" , "sharpbet" ],
"ttl" : 300
}
bookmakers must be a non-empty list.
ttl is optional (seconds), clamped to 10–3600s ; defaults to 60s if omitted.
Re-subscribing to the same selection refreshes the TTL and updates the bookmaker set (idempotent).
Server confirms:
{
"type" : "subscribed_betslip" ,
"fixtureId" : "id1000004461512432" ,
"outcomeId" : 103 ,
"playerId" : 0 ,
"bookmakers" : [ "pinnacle" , "sharpbet" ],
"expiresAt" : "2026-02-07T17:34:37+00:00"
}
Bookmakers you have no account for are dropped from the subscription and returned in a skipped array. A maximum of 20 active betslip subscriptions per client (REST + WS combined) is enforced.
unsubscribe_betslip
{
"type" : "unsubscribe_betslip" ,
"fixtureId" : "id1000004461512432" ,
"outcomeId" : 103 ,
"playerId" : 0
}
Payload schemas
Data messages wrap channel payloads in the envelope {type, channel, event, payload, ts, seq}. The orders, bets, and settlements channels deliver the full database row (row_to_json); balance, emergency, and betslip use custom shapes.
Orders
Full row from the orders table:
{
"orderId" : 327 ,
"requestUuid" : "eb45b192-317b-42d5-9f65-af497b9fa8c1" ,
"client" : "demo" ,
"clientName" : "demo" ,
"fixtureId" : "id1000004461512432" ,
"outcomeId" : 103 ,
"playerId" : 0 ,
"orderPrice" : 1.95 ,
"orderStake" : 10.0 ,
"filledStake" : 10.0 ,
"remainingStake" : 0.0 ,
"orderStatus" : "FILLED" ,
"statusReason" : null ,
"userRef" : "bettor1234" ,
"testOrder" : false ,
"acceptBetterOdds" : true ,
"acceptPartialStake" : true ,
"orderCurrency" : "USD" ,
"back" : true ,
"allowedBookmakers" : "*" ,
"oddsInfo" : null ,
"meta" : {},
"expiresAt" : "2026-02-07T17:29:37+00:00" ,
"filledAt" : "2026-02-07T17:29:32+00:00" ,
"createdAt" : "2026-02-07T17:29:32+00:00" ,
"updatedAt" : "2026-02-07T17:29:32+00:00"
}
Bets / settlements
Full row from the bets table (the settlements channel uses the same shape):
{
"betId" : 73 ,
"orderId" : 327 ,
"bookmaker" : "pinnacle" ,
"bookmakerBetId" : "3332684214" ,
"betStatus" : "CONFIRMED" ,
"settlementStatus" : "UNSETTLED" ,
"placedStake" : 10.0 ,
"placedPrice" : 1.98 ,
"placedCurrency" : "USD" ,
"account" : "pinnacle_main" ,
"requestUuid" : "eb45b192-317b-42d5-9f65-af497b9fa8c1" ,
"userRef" : "bettor1234" ,
"testBet" : false ,
"client" : "demo" ,
"clientName" : "demo" ,
"sentData" : { "stake" : 10.0 , "price" : 1.95 },
"receivedData" : { "betId" : "3332684214" , "status" : "accepted" , "price" : 1.98 },
"settlementAmount" : null ,
"settlementReason" : null ,
"settledAt" : null ,
"declineReason" : null ,
"betRequestId" : null ,
"oddsInfo" : null ,
"meta" : {},
"placedAt" : "2026-02-07T17:29:32+00:00" ,
"createdAt" : "2026-02-07T17:29:32+00:00" ,
"updatedAt" : "2026-02-07T17:29:32+00:00"
}
Subscribing to both bets and settlements delivers settlement updates twice — once on each channel. Use settlements alone if you want a dedicated settlement feed.
Balance
{
"clientName" : "demo" ,
"bookmaker" : "pinnacle" ,
"username" : "pinnacle_main" ,
"balance" : 4990.0 ,
"currency" : "USD" ,
"ts" : 1771183910123
}
Emergency
{
"active" : true ,
"reason" : "Upstream provider maintenance" ,
"ts" : 1771183910123
}
Betslip
Pushed while a betslip subscription is active. For futures the payload carries futureId and participantId instead of fixtureId.
Fixture:
{
"clientName" : "demo" ,
"fixtureId" : "id1000004461512432" ,
"outcomeId" : 103 ,
"playerId" : 0 ,
"odds" : {
"pinnacle" : {
"id1000004461512432:pinnacle:103:0" : {
"price" : 1.98 ,
"limit" : 500.0 ,
"limitMin" : 1.0 ,
"limitCurrency" : "USD" ,
"limitUsd" : 500.0 ,
"limitMinUsd" : 1.0 ,
"active" : true ,
"account" : "pinnacle_main" ,
"currencyInfo" : { "currency" : "USD" , "currencyValue" : 1 , "updatedAt" : "2026-02-07T17:29:32+00:00" }
}
}
}
}
Futures (coming soon):
{
"clientName" : "demo" ,
"futureId" : "fut_123456" ,
"outcomeId" : 0 ,
"playerId" : 0 ,
"participantId" : 5 ,
"odds" : {
"pinnacle" : {
"fut_123456:pinnacle:0:0:5" : {
"price" : 3.50 ,
"limit" : 1000.0 ,
"limitMin" : 5.0 ,
"limitCurrency" : "USD" ,
"limitUsd" : 1000.0 ,
"limitMinUsd" : 5.0 ,
"active" : true ,
"account" : "pinnacle_main" ,
"currencyInfo" : { "currency" : "USD" , "currencyValue" : 1 , "updatedAt" : "2026-02-07T17:29:32+00:00" }
}
}
}
}
Futures betslip WebSocket broadcasting is not yet enabled. The subscription infrastructure is in place and will be activated in an upcoming release.
Connection limits
Setting Value Max connections per API key 5 Auth timeout 30 seconds Server ping interval 30 seconds Pong timeout (disconnect) 120 seconds Message buffer (reliable delivery) 100 messages Output queue per client 2000 messages Max betslip subscriptions per client 20
Next steps
Currency & Limits How values are denominated and converted across currencies.
Errors Handle error responses and decline reasons.