连接流程
1. 连接
打开WebSocket连接。连接时无需身份验证。
2. 登录
在连接后 30秒 内发送登录消息:
{
"type": "login",
"apiKey": "YOUR_API_KEY",
"channels": []
}
空的 channels 数组订阅所有可用频道。要订阅特定频道:
{
"type": "login",
"apiKey": "YOUR_API_KEY",
"channels": ["orders", "bets", "settlements"]
}
可选启用可靠传递和消息确认:
{
"type": "login",
"apiKey": "YOUR_API_KEY",
"channels": ["orders", "bets"],
"reliableDelivery": true
}
3. 登录确认
成功后,服务器响应:
{
"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. 接收更新
数据消息格式如下:
{
"type": "data",
"channel": "orders",
"event": "INSERT",
"payload": { ... },
"ts": 1771183909789,
"seq": 1
}
| 字段 | 描述 |
|---|
type | 数据消息始终为 "data" |
channel | 此消息所属频道 |
event | 事件类型:INSERT、UPDATE、DELETE、SETTLED、STATUS |
payload | 完整的更新对象(见负载结构) |
ts | 服务器时间戳(自纪元以来的毫秒数) |
seq | 每订阅的单调递增序列号 |
requireAck | 仅在启用可靠传递时存在且为 true |
各频道完整的负载结构见下文负载结构。
5. 保持活跃
服务器每 30秒 发送一次 ping:
在 120秒 内回复 pong,否则连接将被关闭:
您也可以从客户端发送 ping — 服务器会回复 pong。
客户端过滤频道
这些频道仅传递属于您 clientName 的数据:
| 频道 | 事件 | 描述 |
|---|
orders | INSERT, UPDATE, DELETE | 订单下达、成交、状态变更 |
bets | INSERT, UPDATE, DELETE | 投注下达、确认和移除 |
settlements | SETTLED | 结算状态更新(负载与 bets 相同) |
accounts | INSERT, UPDATE, DELETE | 账户创建、更新和删除 |
balance | UPDATE | 余额变动通知 |
betslip | UPDATE | 活跃投注单订阅的实时赔率更新(每次 GET /betslip 调用后 60 秒窗口) |
全局频道
所有订阅者都会收到:
| 频道 | 事件 | 描述 |
|---|
fixtures | UPDATE | 赛事元数据和比分变更 |
currencies | UPDATE | 货币汇率更新 |
status | STATUS | 系统状态变更 |
emergency | STATUS | 紧急模式激活/停用 |
可靠投递与确认
默认情况下,消息是「发后即忘」的——快速,但断连期间丢失的消息就此消失。在登录时启用可靠投递,即可获得带确认与重放的至少一次投递:
{ "type": "login", "apiKey": "YOUR_API_KEY", "channels": ["orders", "bets"], "reliableDelivery": true }
启用后,每条 data 消息都携带 requireAck: true,你必须确认它,服务端才能将其从缓冲区释放:
{ "type": "ack", "seq": 42 }
或在一条消息中确认一个范围(推荐,利于吞吐):
{ "type": "ack_batch", "upToSeq": 50 }
工作原理:
- 服务端为每个订阅缓冲最多 100 条未确认消息,并重发任何 30 秒内未被确认的消息。
seq 按订阅且严格递增,因此 seq 出现间隙意味着你漏掉了消息。
- 要在重连后恢复漏掉的消息,从你处理的最后一个
seq 请求重放:
{ "type": "replay", "fromSeq": 40 }
若你落后超过 100 条消息的缓冲,最旧的未确认消息会被丢弃。请及时确认(或使用 ack_batch),并将任何 replay 无法填补的 seq 间隙视为通过 REST 端点(GET /orders、GET /bets)对账的信号。
变更订阅
无需重连即可变更频道:
{ "type": "update_channels", "channels": ["orders", "bets", "settlements"] }
服务端以 channels_updated 回复。
赔率单订阅
betslip 频道为你关注的选项推送实时赔率。有两种订阅方式:
- 通过 REST——调用
GET /betslip 会注册一个 60 秒滑动窗口;每次调用重置计时器并立即通过 WebSocket 广播一份快照。
- 通过 WebSocket——发送
subscribe_betslip 消息并附显式 ttl(10–3600 秒)与博彩商列表以获得更精细的控制,用 unsubscribe_betslip 提前取消。
每客户端最多 20 个活跃赔率单订阅(REST + WS 合计)。消息结构与 subscribed_betslip 确认见下文赔率单订阅消息。
示例:Python 客户端
import asyncio
import json
import websockets
async def connect():
uri = "wss://v2.55-tech.com/ws"
async with websockets.connect(uri) as ws:
# 登录
await ws.send(json.dumps({
"type": "login",
"apiKey": "YOUR_API_KEY",
"channels": ["orders", "bets", "settlements"]
}))
# 等待登录确认
login_resp = json.loads(await ws.recv())
print(f"已登录为 {login_resp.get('clientName')}")
# 监听更新(自动回复 ping)
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())
示例:JavaScript 客户端
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(`已登录为 ${msg.clientName}`);
}
if (msg.type === 'ping') {
ws.send(JSON.stringify({ type: 'pong' }));
}
if (msg.type === 'data') {
console.log(`[${msg.channel}:${msg.event}]`, msg.payload);
}
});
消息类型
客户端 → 服务端
| 类型 | 示例 | 用途 |
|---|
login | {"type": "login", "apiKey": "...", "channels": []} | 鉴权并订阅。可选 reliableDelivery: true。 |
update_channels | {"type": "update_channels", "channels": ["orders"]} | 登录后变更频道订阅。 |
pong | {"type": "pong"} | 回复服务端的 ping。 |
ping | {"type": "ping"} | 存活检查;服务端以 pong 回复。 |
ack | {"type": "ack", "seq": 42} | 确认单条消息(可靠投递)。 |
ack_batch | {"type": "ack_batch", "upToSeq": 50} | 确认直到并包含 upToSeq 的所有消息。 |
replay | {"type": "replay", "fromSeq": 40} | 请求从 fromSeq 起重发缓冲消息。 |
subscribe_betslip | 见下文 | 以自定义 TTL 开启赔率单价格订阅。 |
unsubscribe_betslip | 见下文 | 提前取消赔率单订阅。 |
服务端 → 客户端
| 类型 | 用途 |
|---|
login_ok | 登录成功;回显频道、访问范围与已启用功能。 |
channels_updated | 确认一次 update_channels 变更。 |
data | 一个频道事件(见负载结构)。 |
ping | 服务端保活;以 pong 回复。 |
subscribed_betslip | 确认一次 subscribe_betslip,附有效 expiresAt。 |
error | 客户端消息出错;含指向相关请求的 ref。 |
赔率单订阅消息
在订阅前,betslip 频道必须在你的订阅中(通过 login 或 update_channels 添加)。
subscribe_betslip
{
"type": "subscribe_betslip",
"fixtureId": "id1000004461512432",
"outcomeId": 103,
"playerId": 0,
"bookmakers": ["pinnacle", "sharpbet"],
"ttl": 300
}
bookmakers 必须为非空列表。
ttl 可选(秒),限制在 10–3600 秒;省略时默认 60 秒。
- 对同一选项重新订阅会刷新 TTL 并更新博彩商集合(幂等)。
服务端确认:
{
"type": "subscribed_betslip",
"fixtureId": "id1000004461512432",
"outcomeId": 103,
"playerId": 0,
"bookmakers": ["pinnacle", "sharpbet"],
"expiresAt": "2026-02-07T17:34:37+00:00"
}
你没有账户的博彩商会从订阅中剔除,并在 skipped 数组中返回。每客户端最多 20 个活跃赔率单订阅(REST + WS 合计)。
unsubscribe_betslip
{
"type": "unsubscribe_betslip",
"fixtureId": "id1000004461512432",
"outcomeId": 103,
"playerId": 0
}
负载结构
数据消息将频道负载包裹在信封 {type, channel, event, payload, ts, seq} 中。orders、bets 与 settlements 频道投递完整数据库行(row_to_json);balance、emergency 与 betslip 使用自定义结构。
Orders
orders 表的完整行:
{
"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
bets 表的完整行(settlements 频道使用相同结构):
{
"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"
}
同时订阅 bets 与 settlements 会使结算更新被投递两次——每个频道各一次。若想要专门的结算流,请单独使用 settlements。
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
在赔率单订阅活跃期间推送。对于期货,负载携带 futureId 与 participantId 而非 fixtureId。
赛事:
{
"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" }
}
}
}
}
期货(即将推出):
{
"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" }
}
}
}
}
期货赔率单的 WebSocket 广播尚未启用。订阅基础设施已就位,将在后续版本中激活。
连接限制
| 设置 | 取值 |
|---|
| 每个 API key 最大连接数 | 5 |
| 鉴权超时 | 30 秒 |
| 服务端 ping 间隔 | 30 秒 |
| Pong 超时(断开) | 120 秒 |
| 消息缓冲(可靠投递) | 100 条消息 |
| 每客户端输出队列 | 2000 条消息 |
| 每客户端最大赔率单订阅数 | 20 |
后续步骤