# Getting started

This guide explains how to establish and maintain a WebSocket connection to the Soccer Football API real-time service.

## Connection URL

There is two connection urls:

`wss://ws-eu.soccerfootball.info/?token=YOUR_WEBSOCKET_TOKEN`

`wss://ws-as.soccerfootball.info/?token=YOUR_WEBSOCKET_TOKEN`

You must use the connection URL in response of [/v1/ws/new call.](/v1/ws.md)

## Connection flow

1. GET [/v1/ws/new](/v1/ws/new.md) → Obtain WebSocket token
2. Connect to WSS → Establish WebSocket connection
3. Subscribe to channels → Start receiving events
4. Handle events → Process incoming messages
5. Renew token → Before expiration (every \~25 minutes)

***

## Step-by-step guide

### Step 1 — Obtain a WebSocket token

Call the [/v1/ws/new](/v1/ws/new.md) endpoint to generate a new WebSocket token.

```bash
curl --request GET \
    --url 'https://api.soccerfootball.info/v1/ws/new/?t=YOUR_API_TOKEN'
```

The response contains everything you need to connect:

```json
{
  "status": 200,
  "errors": [],
  "pagination": [],
  "result": [
    {
      "is_new": true,
      "token": "abc123xyz789...",
      "server": "wss://ws-eu.soccerfootball.info/?token=abc123xyz789...",
      "max_connections": 2,
      "max_subscribe_per_connection": 2,
      "allowed_channels": ["MAIN"],
      "expires_at": "2024-01-15 14:30:00"
    }
  ]
}
```

Save the **`token`** and use the **`server`** URL to connect. Note the **`expires_at`** timestamp — you will need to renew the token before this time.

### Step 2 — Connect to WebSocket

Use the `server` URL from the previous response to establish a WebSocket connection:

```javascript
const ws = new WebSocket("wss://ws-eu.soccerfootball.info/?token=abc123xyz789...");

ws.onopen = () => {
  console.log("Connected!");
};
```

### Step 3 — Subscribe to a channel

Once connected, subscribe to the channels you need. For example, to receive all match events on the **MAIN** channel:

```javascript
ws.send(JSON.stringify({
  "action": "subscribe",
  "channel": "MAIN",
  "scope": "all"
}));
```

You can also subscribe to a specific match or league:

```javascript
// Subscribe to a specific match
ws.send(JSON.stringify({
  "action": "subscribe",
  "channel": "MAIN",
  "scope": "match",
  "id": "b01d28ac92221034"
}));

// Subscribe to a specific league
ws.send(JSON.stringify({
  "action": "subscribe",
  "channel": "MAIN",
  "scope": "league",
  "id": "f2b16fa54cb525d"
}));
```

The server confirms each subscription:

```json
{
  "type": "subscribed",
  "channel": "MAIN",
  "scope": "all",
  "id": null,
  "topicKey": "MAIN:all",
  "message": "Successfully subscribed"
}
```

### Step 4 — Handle events

Process incoming messages based on their `type`:

```javascript
ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);

  switch (msg.type) {
    case 'match_start':
      console.log(`Match started: ${msg.data.teamA.name} vs ${msg.data.teamB.name}`);
      break;
    case 'goal':
      console.log(`GOAL! Score: ${msg.data.score} at ${msg.data.timer}'`);
      break;
    case 'halftime':
      console.log(`Halftime: ${msg.data.score}`);
      break;
    case 'match_end':
      console.log(`Full time: ${msg.data.finalScore}`);
      break;
    case 'pong':
      // Keep-alive response
      break;
    case 'subscribed':
      console.log(`Subscribed to: ${msg.topicKey}`);
      break;
    case 'error':
      console.error(`Error: ${msg.message}`);
      break;
  }
};
```

### Step 5 — Renew token before expiration

WebSocket tokens expire after approximately 25 minutes. You must call the [/v1/ws/renew](/v1/ws/renew.md) endpoint **before** the token expires to keep your connection alive.

Best practice: set a timer to renew **5 minutes before** the `expires_at` timestamp.

```javascript
// Renew the token via REST API
async function renewToken(apiToken, wsToken) {
  const response = await fetch(
    `https://api.soccerfootball.info/v1/ws/renew/?t=${apiToken}&wid=${wsToken}`
  );
  const data = await response.json();

  if (data.result[0].renewed) {
    console.log("Token renewed, new expiration:", data.result[0].expires_at);
  }
}

// Schedule renewal 5 minutes before expiration
const expiresAt = new Date("2024-01-15T14:30:00Z");
const renewAt = expiresAt.getTime() - (5 * 60 * 1000); // 5 minutes before
const delay = renewAt - Date.now();

setTimeout(() => {
  renewToken("YOUR_API_TOKEN", "abc123xyz789...");
}, delay);
```

***

## Complete example

A full working example combining all steps: obtain token, connect, subscribe, handle events, keep-alive ping, and token renewal.

```javascript
const API_TOKEN = "YOUR_API_TOKEN";

// Step 1 — Obtain token
async function start() {
  const res = await fetch(`https://api.soccerfootball.info/v1/ws/new/?t=${API_TOKEN}`);
  const json = await res.json();
  const { token, server, expires_at } = json.result[0];

  // Step 2 — Connect
  const ws = new WebSocket(server);

  ws.onopen = () => {
    console.log("Connected!");

    // Step 3 — Subscribe to MAIN channel
    ws.send(JSON.stringify({ action: "subscribe", channel: "MAIN", scope: "all" }));
  };

  // Step 4 — Handle events
  ws.onmessage = (event) => {
    const msg = JSON.parse(event.data);
    console.log(`[${msg.type}]`, msg.channel || "", msg.data || msg.message || "");
  };

  ws.onerror = (err) => console.error("WebSocket error:", err);

  ws.onclose = (event) => {
    console.log(`Connection closed: ${event.code} - ${event.reason}`);
    // Implement reconnection logic here if needed
  };

  // Keep-alive ping every 30 seconds
  const pingInterval = setInterval(() => {
    if (ws.readyState === WebSocket.OPEN) {
      ws.send(JSON.stringify({ action: "ping" }));
    }
  }, 30000);

  // Step 5 — Schedule token renewal 5 minutes before expiration
  const expiresAtMs = new Date(expires_at).getTime();
  const renewDelay = expiresAtMs - Date.now() - (5 * 60 * 1000);

  if (renewDelay > 0) {
    setTimeout(async () => {
      const renewRes = await fetch(
        `https://api.soccerfootball.info/v1/ws/renew/?t=${API_TOKEN}&wid=${token}`
      );
      const renewJson = await renewRes.json();
      console.log("Token renewed:", renewJson.result[0].expires_at);
    }, renewDelay);
  }
}

start();
```

***

{% hint style="info" %}
**MAIN\_REALTIME channel (MEGA plan 🟩 only)**

If you subscribe to the **MAIN\_REALTIME** channel, the messages contain IDs that are specific to the realtime data source and differ from the standard REST API IDs. To map these realtime IDs to the corresponding REST IDs, use the following endpoints:

* [/v1/live/ws](/v1/live/live-ws.md) — live matches with ID mapping
* [/v1/championships/ws](/v1/championships/ws.md) — championships with ID mapping
* [/v1/teams/ws](/v1/teams/ws.md) — teams with ID mapping

All other channels (MAIN, STATS, ODDS, STATS\_REALTIME, ODDS\_REALTIME) already use REST IDs — no mapping is needed.
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://info.soccerfootball.info/websocket/getting-started.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
