connected → subscribe to match events & scores → send heartbeat every 30 seconds → handle incoming messages → automatically reconnect using exponential backoff after disconnection.
Replace YOUR_API_KEY with your actual API key. Use the language selector at the top to switch between different code examples.
// org.java-websocket:Java-WebSocket:1.5.7
// com.google.code.gson:gson:2.11.0
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import java.net.URI;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
public class AnySportWsClient {
private static final String API_KEY = "YOUR_API_KEY";
private static final String WS_URL =
"wss://data.anysport.io/v1/ws/live?api_key=" + API_KEY + "&business=soccer";
private static final Gson GSON = new Gson();
private final ScheduledExecutorService scheduler =
Executors.newSingleThreadScheduledExecutor();
private final AtomicLong reconnectDelayMs = new AtomicLong(1000);
private volatile WebSocketClient client;
public void start() {
connect();
}
private void connect() {
try {
client = new WebSocketClient(URI.create(WS_URL)) {
@Override
public void onOpen(ServerHandshake handshake) {
reconnectDelayMs.set(1000);
// data 必填
sendMsg(20000, Map.of());
sendMsg(20200, Map.of());
scheduler.scheduleAtFixedRate(() -> {
if (isOpen()) {
sendMsg(20010, null);
}
}, 30, 30, TimeUnit.SECONDS);
}
@Override
public void onMessage(String message) {
JsonObject msg = GSON.fromJson(message, JsonObject.class);
if (msg.has("type")) {
String type = msg.get("type").getAsString();
if ("connected".equals(type)) {
System.out.println("connected");
return;
}
if ("situation_update".equals(type)
|| "score_update".equals(type)
|| "odds_live_update".equals(type)
|| "odds_prematch_update".equals(type)) {
System.out.println(type + " => " + msg.get("data"));
return;
}
if ("error".equals(type)) {
System.err.println("error: " + msg.get("message"));
return;
}
}
if (msg.has("code")) {
int code = msg.get("code").getAsInt();
if (code == 20001 || code == 20201) {
System.out.println("subscribe ok: " + code);
} else if (code >= 40000) {
System.err.println("biz error: " + msg);
}
}
}
@Override
public void onClose(int code, String reason, boolean remote) {
System.out.println("closed: " + reason);
scheduleReconnect();
}
@Override
public void onError(Exception ex) {
System.err.println("ws error: " + ex.getMessage());
}
};
client.connect();
} catch (Exception ex) {
scheduleReconnect();
}
}
private void sendMsg(int code, Map<String, Object> data) {
JsonObject payload = new JsonObject();
payload.addProperty("code", code);
payload.addProperty("trace", UUID.randomUUID().toString());
if (data != null) {
payload.add("data", GSON.toJsonTree(data));
}
if (client != null && client.isOpen()) {
client.send(GSON.toJson(payload));
}
}
private void scheduleReconnect() {
long delay = reconnectDelayMs.get();
scheduler.schedule(this::connect, delay, TimeUnit.MILLISECONDS);
reconnectDelayMs.set(Math.min(delay * 2, 30_000));
}
public static void main(String[] args) {
new AnySportWsClient().start();
}
}
```
# pip install websockets
import asyncio
import json
import uuid
import websockets
API_KEY = "YOUR_API_KEY"
WS_URL = f"wss://data.anysport.io/v1/ws/live?api_key={API_KEY}&business=soccer"
def build_msg(code: int, data=None) -> str:
payload = {
"code": code,
"trace": str(uuid.uuid4()),
}
if data is not None:
payload["data"] = data
return json.dumps(payload)
async def handle_messages(ws):
async for raw in ws:
msg = json.loads(raw)
msg_type = msg.get("type")
code = msg.get("code")
if msg_type == "connected":
print("connected:", msg.get("message"))
elif msg_type in (
"situation_update",
"score_update",
"odds_live_update",
"odds_prematch_update",
):
print(msg_type, msg.get("data"))
elif msg_type == "error":
print("error:", msg.get("message"))
elif code in (20001, 20201, 20101, 20301):
print("subscribe ok:", code, "trace=", msg.get("trace"))
elif code in (21010, 21210, 21110, 21310):
print("unsubscribe ok:", code)
elif isinstance(code, int) and code >= 40000:
print("biz error:", msg)
async def heartbeat(ws):
while True:
await asyncio.sleep(30)
await ws.send(build_msg(20010))
async def run_once():
async with websockets.connect(WS_URL, ping_interval=20) as ws:
await ws.send(build_msg(20000, {}))
await ws.send(build_msg(20200, {}))
# await ws.send(build_msg(20000, {"match_id": "1234567"}))
hb = asyncio.create_task(heartbeat(ws))
try:
await handle_messages(ws)
finally:
hb.cancel()
async def main():
delay = 1.0
while True:
try:
await run_once()
delay = 1.0
except Exception as ex:
print(f"disconnected: {ex}, reconnect in {delay:.0f}s")
await asyncio.sleep(delay)
delay = min(delay * 2, 30.0)
if __name__ == "__main__":
asyncio.run(main())
// go get github.com/gorilla/websocket github.com/google/uuid
package main
import (
"encoding/json"
"fmt"
"log"
"math"
"net/url"
"time"
"github.com/google/uuid"
"github.com/gorilla/websocket"
)
const apiKey = "YOUR_API_KEY"
type requestMsg struct {
Code int `json:"code"`
Trace string `json:"trace"`
Data map[string]interface{} `json:"data,omitempty"`
}
func send(conn *websocket.Conn, code int, data map[string]interface{}) error {
msg := requestMsg{
Code: code,
Trace: uuid.NewString(),
Data: data,
}
return conn.WriteJSON(msg)
}
func main() {
delay := time.Second
for {
err := runOnce()
if err != nil {
log.Printf("disconnected: %v, reconnect in %s", err, delay)
time.Sleep(delay)
delay = time.Duration(math.Min(float64(delay*2), float64(30*time.Second)))
continue
}
delay = time.Second
}
}
func runOnce() error {
u := url.URL{
Scheme: "wss",
Host: "data.anysport.io",
Path: "/v1/ws/live",
RawQuery: "api_key=" + apiKey + "&business=soccer",
}
conn, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
if err != nil {
return err
}
defer conn.Close()
if err := send(conn, 20000, map[string]interface{}{}); err != nil {
return err
}
if err := send(conn, 20200, map[string]interface{}{}); err != nil {
return err
}
done := make(chan struct{})
go func() {
ticker := time.NewTicker(30 * time.Second)
defer ticker.Stop()
for {
select {
case <-done:
return
case <-ticker.C:
_ = send(conn, 20010, nil)
}
}
}()
defer close(done)
for {
_, raw, err := conn.ReadMessage()
if err != nil {
return err
}
var msg map[string]interface{}
if err := json.Unmarshal(raw, &msg); err != nil {
continue
}
if t, ok := msg["type"].(string); ok {
switch t {
case "connected":
fmt.Println("connected")
case "situation_update", "score_update", "odds_live_update", "odds_prematch_update":
fmt.Println(t, msg["data"])
case "error":
fmt.Println("error:", msg["message"])
}
continue
}
if code, ok := msg["code"].(float64); ok {
c := int(code)
if c == 20001 || c == 20201 || c == 20101 || c == 20301 {
fmt.Println("subscribe ok:", c)
} else if c >= 40000 {
fmt.Println("biz error:", msg)
}
}
}
}
<?php
// composer require textalk/websocket
use WebSocket\Client;
const API_KEY = 'YOUR_API_KEY';
const WS_URL = 'wss://data.anysport.io/v1/ws/live?api_key=' . API_KEY . '&business=soccer';
function buildMsg(int $code, ?array $data = null): string
{
$payload = [
'code' => $code,
'trace' => bin2hex(random_bytes(16)),
];
if ($data !== null) {
$payload['data'] = $data;
}
return json_encode($payload, JSON_UNESCAPED_UNICODE);
}
function runOnce(): void
{
$client = new Client(WS_URL);
$lastHeartbeat = time();
$client->send(buildMsg(20000, new stdClass()));
$client->send(buildMsg(20200, new stdClass()));
while (true) {
if (time() - $lastHeartbeat >= 30) {
$client->send(buildMsg(20010));
$lastHeartbeat = time();
}
$raw = $client->receive();
if ($raw === null) {
continue;
}
$msg = json_decode($raw, true);
if (!is_array($msg)) {
continue;
}
$type = $msg['type'] ?? null;
$code = $msg['code'] ?? null;
if ($type === 'connected') {
echo "connected\n";
} elseif (in_array($type, [
'situation_update',
'score_update',
'odds_live_update',
'odds_prematch_update',
], true)) {
echo $type . ' => ' . json_encode($msg['data'], JSON_UNESCAPED_UNICODE) . "\n";
} elseif ($type === 'error') {
echo 'error: ' . ($msg['message'] ?? '') . "\n";
} elseif (in_array($code, [20001, 20201, 20101, 20301], true)) {
echo "subscribe ok: {$code}\n";
} elseif (is_int($code) && $code >= 40000) {
echo 'biz error: ' . json_encode($msg, JSON_UNESCAPED_UNICODE) . "\n";
}
}
}
$delay = 1;
while (true) {
try {
runOnce();
$delay = 1;
} catch (Throwable $e) {
echo "disconnected: {$e->getMessage()}, reconnect in {$delay}s\n";
sleep($delay);
$delay = min($delay * 2, 30);
}
}
// Node.js: const WebSocket = require('ws');
const API_KEY = 'YOUR_API_KEY';
const WS_URL = `wss://data.anysport.io/v1/ws/live?api_key=${API_KEY}&business=soccer`;
let ws = null;
let heartTimer = null;
let reconnectDelay = 1000;
function uuid() {
return crypto.randomUUID();
}
function send(code, data) {
const payload = { code, trace: uuid() };
if (data !== undefined) {
payload.data = data;
}
if (ws && ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify(payload));
}
}
function connect() {
ws = new WebSocket(WS_URL);
ws.onopen = () => {
reconnectDelay = 1000;
send(20000, {});
send(20200, {});
// send(20000, { match_id: '1234567' });
heartTimer = setInterval(() => send(20010), 30_000);
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.type === 'connected') {
console.log('connected');
return;
}
if ([20001, 20201, 20101, 20301].includes(msg.code)) {
console.log('subscribe ok', msg.code, msg.trace);
return;
}
if (
msg.type === 'situation_update' ||
msg.type === 'score_update' ||
msg.type === 'odds_live_update' ||
msg.type === 'odds_prematch_update'
) {
console.log(msg.type, msg.data);
return;
}
if (msg.code >= 40000 || msg.type === 'error') {
console.error('ws error', msg);
}
};
ws.onclose = () => {
clearInterval(heartTimer);
setTimeout(connect, reconnectDelay);
reconnectDelay = Math.min(reconnectDelay * 2, 30_000);
};
ws.onerror = () => ws.close();
}
connect();