# Counter-Strike 2 webhooks

Signed POST requests to your URL when Counter-Strike 2 events happen. Signing, retries, pauses and catch-up are the same for every sport: https://citoapi.com/docs/webhooks.md

Live catalog for this sport, with current status and volume: https://api.citoapi.com/api/v1/webhooks/events?game=cs2
Human docs: https://citoapi.com/docs/api/cs2/webhooks/
Status below was measured at 2026-11-08T20:30:57.835Z. Trust the live catalog over this file.

## Which events to subscribe to

- Live scoreboard: cs2.match.live_started, cs2.score.updated, cs2.round.ended, cs2.map.completed, cs2.match.completed. Tells you when a match goes live, then every score change and round result, and closes with the map and match results.
- Settle bets: cs2.match.completed, cs2.map.completed. Final map score and winner, plus each map for per-map markets. cs2.match.live_ended is left out: it is not the official result.
- Results only: cs2.match.completed. One event per finished match.
- Alerts: cs2.match.started, cs2.match.completed. “Match starting” and “final score”. Few enough to post to a channel.

## Filters

- `league`: Only this league. On CS2 events the league is always cs2, so it does not narrow them.
- `matchId`: Only this match. Take the id from the schedule or live routes.

## Events

### cs2.match.started

A CS2 match has started, with event name and team names.

- When: When a match goes live. Once per match.
- Status: Active. Sent during the last 7 days.
- Frequency: about 25 per day across all matches
- Plan: Pro and Scale
- Filters: league, matchId
- Use it to: Flip a match to live and post a “match starting” alert with the event and teams.

| Field | Type | Meaning |
|---|---|---|
| `data` | object | The change itself, on score events. |
| `event` | null or string | The tournament or event name inside data on CS2 events, the event name on the envelope. |
| `event_type` | string | The event name. |
| `league` | string | League name, or the sport id on CS2 events. |
| `match_id` | string | The match id. Works on the match routes for this sport. |
| `matchId` | string | The match id. Works on the match routes for this sport. |
| `previous_state` | null or object | The state before the change, when the event has one. |
| `teams` | array | The teams in this match. |
| `timestamp` | string | When this event happened, ISO 8601 UTC. |

```json
{
  "event": "cs2.match.started",
  "id": "a1b2c3d4-0000-4000-8000-000000000000",
  "timestamp": "2026-11-08T14:09:05.649Z",
  "event_type": "cs2.match.started",
  "match_id": "cs2-match-2400316",
  "previous_state": {
    "status": "upcoming"
  },
  "data": {
    "data": {
      "event": "ESL Challenger League Season 52 Europe Cup 11",
      "teams": [
        "Balkan Outlaws",
        "The Last Resort"
      ]
    },
    "event": "ESL Challenger League Season 52 Europe Cup 11",
    "teams": [
      "Balkan Outlaws",
      "The Last Resort"
    ],
    "league": "cs2",
    "matchId": "cs2-match-2400316",
    "match_id": "cs2-match-2400316",
    "timestamp": "2026-11-08T14:09:05.633Z",
    "event_type": "cs2.match.started",
    "previous_state": {
      "status": "upcoming"
    }
  }
}
```

### cs2.match.live_started

Live round-by-round tracking began for a CS2 match.

- When: When live tracking of a match begins. About once per match.
- Status: Active. Sent during the last 7 days.
- Frequency: about 25 per day across all matches
- Plan: Pro and Scale (real time)
- Filters: league, matchId
- Use it to: Start listening to the round events for this match, or open your live view.

| Field | Type | Meaning |
|---|---|---|
| `data` | object | The change itself, on score events. |
| `event_type` | string | The event name. |
| `league` | string | League name, or the sport id on CS2 events. |
| `match_id` | string | The match id. Works on the match routes for this sport. |
| `matchId` | string | The match id. Works on the match routes for this sport. |
| `previous_state` | null | The state before the change, when the event has one. |
| `timestamp` | string | When this event happened, ISO 8601 UTC. |

```json
{
  "event": "cs2.match.live_started",
  "id": "a1b2c3d4-0000-4000-8000-000000000000",
  "timestamp": "2026-11-08T16:25:22.572Z",
  "event_type": "cs2.match.live_started",
  "match_id": "cs2-match-2400093",
  "previous_state": null,
  "data": {
    "data": {
      "score": {
        "team1": null,
        "team2": null
      },
      "teams": {
        "team1_id": "cs2-team-13029",
        "team2_id": "cs2-team-13026",
        "team1_name": "RED Canids Academy",
        "team2_name": "BESTIA Academy"
      },
      "status": "live",
      "match_id": "cs2-match-2400093",
      "started_at": "2026-11-08T16:25:22.451Z"
    },
    "league": "cs2",
    "matchId": "cs2-match-2400093",
    "match_id": "cs2-match-2400093",
    "timestamp": "2026-11-08T16:25:22.451Z",
    "event_type": "cs2.match.live_started",
    "previous_state": null
  }
}
```

### cs2.match.live_ended

Live tracking ended for a CS2 match, with the last known state of the map and players in data.final_state.

- When: When a match stops being live. Use cs2.match.completed for the official result.
- Status: Active. Sent during the last 7 days.
- Frequency: about 25 per day across all matches
- Plan: Pro and Scale (real time)
- Filters: league, matchId
- Use it to: Stop your live view. Do not settle on this event: wait for cs2.match.completed.
- Notes: data.reason says why tracking stopped. The score in data.score counts maps; data.final_state.score counts rounds on the last map.

| Field | Type | Meaning |
|---|---|---|
| `data` | object | The change itself, on score events. |
| `event_type` | string | The event name. |
| `league` | string | League name, or the sport id on CS2 events. |
| `match_id` | string | The match id. Works on the match routes for this sport. |
| `matchId` | string | The match id. Works on the match routes for this sport. |
| `previous_state` | object | The state before the change, when the event has one. |
| `timestamp` | string | When this event happened, ISO 8601 UTC. |

```json
{
  "event": "cs2.match.live_ended",
  "id": "a1b2c3d4-0000-4000-8000-000000000000",
  "timestamp": "2026-11-08T14:10:55.655Z",
  "event_type": "cs2.match.live_ended",
  "match_id": "cs2-match-2400384",
  "previous_state": {
    "score": {
      "team1": 5,
      "team2": 12
    },
    "teams": {
      "team1_name": "benched gods",
      "team2_name": "PCIFIC",
      "terrorist_team_name": "PCIFIC",
      "counter_terrorist_team_name": "benched gods"
    },
    "status": "live",
    "players": [
      {
        "hp": 100,
        "adr": 120.83333333333333,
        "name": "jresy",
        "nick": "jresy",
        "side": "T",
        "alive": true,
        "kills": 19,
        "money": 3100,
        "deaths": 11,
        "helmet": true,
        "kevlar": true,
        "weapon": "ak47",
        "assists": 6,
        "player_id": "cs2-player-21250",
        "has_defuse_kit": false
      },
      {
        "hp": 100,
        "adr": 74.5,
        "name": "scolleN",
        "nick": "scolleN",
        "side": "T",
        "alive": true,
        "kills": 15,
        "money": 6350,
        "deaths": 11,
        "helmet": true,
        "kevlar": true,
        "weapon": "ak47",
        "assists": 5,
        "player_id": "cs2-player-22504",
        "has_defuse_kit": false
      },
      {
        "hp": 100,
        "adr": 73.61111111111111,
        "name": "lugseN",
        "nick": "lugseN",
        "side": "T",
        "alive": true,
        "kills": 15,
        "money": 8300,
        "deaths": 7,
        "helmet": true,
        "kevlar": true,
        "weapon": "awp",
        "assists": 4,
        "player_id": "cs2-player-23274",
        "has_defuse_kit": false
      },
      {
        "hp": 100,
        "adr": 85.38888888888889,
        "name": "mini",
        "nick": "mini",
        "side": "T",
        "alive": true,
        "kills": 14,
        "money": 2550,
        "deaths": 8,
        "helmet": true,
        "kevlar": true,
        "weapon": "ak47",
        "assists": 5,
        "player_id": "cs2-player-9352",
        "has_defuse_kit": false
      },
      {
        "hp": 100,
        "adr": 59.27777777777778,
        "name": "oyesil",
        "nick": "oyesil",
        "side": "T",
        "alive": true,
        "kills": 10,
        "money": 3050,
        "deaths": 8,
        "helmet": true,
        "kevlar": true,
        "weapon": "ak47",
        "assists": 5,
        "player_id": "cs2-player-25890",
        "has_defuse_kit": false
      },
      {
        "hp": 100,
        "adr": 69.77777777777777,
        "name": "facer",
        "nick": "facer",
        "side": "CT",
        "alive": true,
        "kills": 10,
        "money": 100,
        "deaths": 16,
        "helmet": false,
        "kevlar": true,
        "weapon": "m4a1_silencer",
        "assists": 4,
        "player_id": "cs2-player-24885",
        "has_defuse_kit": false
      },
      {
        "hp": 100,
        "adr": 72.94444444444444,
        "name": "f1chper",
        "nick": "f1chper",
        "side": "CT",
        "alive": true,
        "kills": 10,
        "money": 300,
        "deaths": 13,
        "helmet": false,
        "kevlar": true,
        "weapon": "m4a1_silencer",
        "assists": 1,
        "player_id": "cs2-player-26074",
        "has_defuse_kit": false
      },
      {
        "hp": 100,
        "adr": 41.388888888888886,
        "name": "yoyoS2",
        "nick": "yoyoS2",
        "side": "CT",
        "alive": true,
        "kills": 9,
        "money": 0,
        "deaths": 14,
        "helmet": true,
        "kevlar": true,
        "weapon": "awp",
        "assists": 2,
        "player_id": "cs2-player-26646",
        "has_defuse_kit": false
      },
      {
        "hp": 95,
        "adr": 56.55555555555556,
        "name": "wign",
        "nick": "Wign",
        "side": "CT",
        "alive": true,
        "kills": 8,
        "money": 0,
        "deaths": 14,
        "helmet": true,
        "kevlar": true,
        "weapon": "m4a1_silencer",
        "assists": 3,
        "player_id": "cs2-player-23773",
        "has_defuse_kit": false
      },
      {
        "hp": 100,
        "adr": 48.833333333333336,
        "name": "K014NZ",
        "nick": "K014NZ",
        "side": "CT",
        "alive": true,
        "kills": 8,
        "money": 0,
        "deaths": 16,
        "helmet": true,
        "kevlar": true,
        "weapon": "m4a1_silencer",
        "assists": 2,
        "player_id": "cs2-player-24840",
        "has_defuse_kit": true
      }
    ],
    "match_id": "cs2-match-2400384",
    "current_map": "de_anubis",
    "bomb_planted": false,
    "current_round": 18,
    "round_time_seconds": null
  },
  "data": {
    "data": {
      "score": {
        "team1": 1,
        "team2": 1
      },
      "teams": {
        "team1_id": "cs2-team-13599",
        "team2_id": "cs2-team-13054",
        "team1_name": "benched gods",
        "team2_name": "PCIFIC"
      },
      "reason": "not_live",
      "status": "ended",
      "ended_at": "2026-11-08T14:10:55.632Z",
      "match_id": "cs2-match-2400384",
      "final_state": {
        "score": {
          "team1": 5,
          "team2": 12
        },
        "teams": {
          "team1_name": "benched gods",
          "team2_name": "PCIFIC",
          "terrorist_team_name": "PCIFIC",
          "counter_terrorist_team_name": "benched gods"
        },
        "status": "live",
        "players": [
          {
            "hp": 100,
            "adr": 120.83333333333333,
            "name": "jresy",
            "nick": "jresy",
            "side": "T",
            "alive": true,
            "kills": 19,
            "money": 3100,
            "deaths": 11,
            "helmet": true,
            "kevlar": true,
            "weapon": "ak47",
            "assists": 6,
            "player_id": "cs2-player-21250",
            "has_defuse_kit": false
          },
          {
            "hp": 100,
            "adr": 74.5,
            "name": "scolleN",
            "nick": "scolleN",
            "side": "T",
            "alive": true,
            "kills": 15,
            "money": 6350,
            "deaths": 11,
            "helmet": true,
            "kevlar": true,
            "weapon": "ak47",
            "assists": 5,
            "player_id": "cs2-player-22504",
            "has_defuse_kit": false
          },
          {
            "hp": 100,
            "adr": 73.61111111111111,
            "name": "lugseN",
            "nick": "lugseN",
            "side": "T",
            "alive": true,
            "kills": 15,
            "money": 8300,
            "deaths": 7,
            "helmet": true,
            "kevlar": true,
            "weapon": "awp",
            "assists": 4,
            "player_id": "cs2-player-23274",
            "has_defuse_kit": false
          },
          {
            "hp": 100,
            "adr": 85.38888888888889,
            "name": "mini",
            "nick": "mini",
            "side": "T",
            "alive": true,
            "kills": 14,
            "money": 2550,
            "deaths": 8,
            "helmet": true,
            "kevlar": true,
            "weapon": "ak47",
            "assists": 5,
            "player_id": "cs2-player-9352",
            "has_defuse_kit": false
          },
          {
            "hp": 100,
            "adr": 59.27777777777778,
            "name": "oyesil",
            "nick": "oyesil",
            "side": "T",
            "alive": true,
            "kills": 10,
            "money": 3050,
            "deaths": 8,
            "helmet": true,
            "kevlar": true,
            "weapon": "ak47",
            "assists": 5,
            "player_id": "cs2-player-25890",
            "has_defuse_kit": false
          },
          {
            "hp": 100,
            "adr": 69.77777777777777,
            "name": "facer",
            "nick": "facer",
            "side": "CT",
            "alive": true,
            "kills": 10,
            "money": 100,
            "deaths": 16,
            "helmet": false,
            "kevlar": true,
            "weapon": "m4a1_silencer",
            "assists": 4,
            "player_id": "cs2-player-24885",
            "has_defuse_kit": false
          },
          {
            "hp": 100,
            "adr": 72.94444444444444,
            "name": "f1chper",
            "nick": "f1chper",
            "side": "CT",
            "alive": true,
            "kills": 10,
            "money": 300,
            "deaths": 13,
            "helmet": false,
            "kevlar": true,
            "weapon": "m4a1_silencer",
            "assists": 1,
            "player_id": "cs2-player-26074",
            "has_defuse_kit": false
          },
          {
            "hp": 100,
            "adr": 41.388888888888886,
            "name": "yoyoS2",
            "nick": "yoyoS2",
            "side": "CT",
            "alive": true,
            "kills": 9,
            "money": 0,
            "deaths": 14,
            "helmet": true,
            "kevlar": true,
            "weapon": "awp",
            "assists": 2,
            "player_id": "cs2-player-26646",
            "has_defuse_kit": false
          },
          {
            "hp": 95,
            "adr": 56.55555555555556,
            "name": "wign",
            "nick": "Wign",
            "side": "CT",
            "alive": true,
            "kills": 8,
            "money": 0,
            "deaths": 14,
            "helmet": true,
            "kevlar": true,
            "weapon": "m4a1_silencer",
            "assists": 3,
            "player_id": "cs2-player-23773",
            "has_defuse_kit": false
          },
          {
            "hp": 100,
            "adr": 48.833333333333336,
            "name": "K014NZ",
            "nick": "K014NZ",
            "side": "CT",
            "alive": true,
            "kills": 8,
            "money": 0,
            "deaths": 16,
            "helmet": true,
            "kevlar": true,
            "weapon": "m4a1_silencer",
            "assists": 2,
            "player_id": "cs2-player-24840",
            "has_defuse_kit": true
          }
        ],
        "match_id": "cs2-match-2400384",
        "current_map": "de_anubis",
        "bomb_planted": false,
        "current_round": 18,
        "round_time_seconds": null
      }
    },
    "league": "cs2",
    "matchId": "cs2-match-2400384",
    "match_id": "cs2-match-2400384",
    "timestamp": "2026-11-08T14:10:55.632Z",
    "event_type": "cs2.match.live_ended",
    "previous_state": {
      "score": {
        "team1": 5,
        "team2": 12
      },
      "teams": {
        "team1_name": "benched gods",
        "team2_name": "PCIFIC",
        "terrorist_team_name": "PCIFIC",
        "counter_terrorist_team_name": "benched gods"
      },
      "status": "live",
      "players": [
        {
          "hp": 100,
          "adr": 120.83333333333333,
          "name": "jresy",
          "nick": "jresy",
          "side": "T",
          "alive": true,
          "kills": 19,
          "money": 3100,
          "deaths": 11,
          "helmet": true,
          "kevlar": true,
          "weapon": "ak47",
          "assists": 6,
          "player_id": "cs2-player-21250",
          "has_defuse_kit": false
        },
        {
          "hp": 100,
          "adr": 74.5,
          "name": "scolleN",
          "nick": "scolleN",
          "side": "T",
          "alive": true,
          "kills": 15,
          "money": 6350,
          "deaths": 11,
          "helmet": true,
          "kevlar": true,
          "weapon": "ak47",
          "assists": 5,
          "player_id": "cs2-player-22504",
          "has_defuse_kit": false
        },
        {
          "hp": 100,
          "adr": 73.61111111111111,
          "name": "lugseN",
          "nick": "lugseN",
          "side": "T",
          "alive": true,
          "kills": 15,
          "money": 8300,
          "deaths": 7,
          "helmet": true,
          "kevlar": true,
          "weapon": "awp",
          "assists": 4,
          "player_id": "cs2-player-23274",
          "has_defuse_kit": false
        },
        {
          "hp": 100,
          "adr": 85.38888888888889,
          "name": "mini",
          "nick": "mini",
          "side": "T",
          "alive": true,
          "kills": 14,
          "money": 2550,
          "deaths": 8,
          "helmet": true,
          "kevlar": true,
          "weapon": "ak47",
          "assists": 5,
          "player_id": "cs2-player-9352",
          "has_defuse_kit": false
        },
        {
          "hp": 100,
          "adr": 59.27777777777778,
          "name": "oyesil",
          "nick": "oyesil",
          "side": "T",
          "alive": true,
          "kills": 10,
          "money": 3050,
          "deaths": 8,
          "helmet": true,
          "kevlar": true,
          "weapon": "ak47",
          "assists": 5,
          "player_id": "cs2-player-25890",
          "has_defuse_kit": false
        },
        {
          "hp": 100,
          "adr": 69.77777777777777,
          "name": "facer",
          "nick": "facer",
          "side": "CT",
          "alive": true,
          "kills": 10,
          "money": 100,
          "deaths": 16,
          "helmet": false,
          "kevlar": true,
          "weapon": "m4a1_silencer",
          "assists": 4,
          "player_id": "cs2-player-24885",
          "has_defuse_kit": false
        },
        {
          "hp": 100,
          "adr": 72.94444444444444,
          "name": "f1chper",
          "nick": "f1chper",
          "side": "CT",
          "alive": true,
          "kills": 10,
          "money": 300,
          "deaths": 13,
          "helmet": false,
          "kevlar": true,
          "weapon": "m4a1_silencer",
          "assists": 1,
          "player_id": "cs2-player-26074",
          "has_defuse_kit": false
        },
        {
          "hp": 100,
          "adr": 41.388888888888886,
          "name": "yoyoS2",
          "nick": "yoyoS2",
          "side": "CT",
          "alive": true,
          "kills": 9,
          "money": 0,
          "deaths": 14,
          "helmet": true,
          "kevlar": true,
          "weapon": "awp",
          "assists": 2,
          "player_id": "cs2-player-26646",
          "has_defuse_kit": false
        },
        {
          "hp": 95,
          "adr": 56.55555555555556,
          "name": "wign",
          "nick": "Wign",
          "side": "CT",
          "alive": true,
          "kills": 8,
          "money": 0,
          "deaths": 14,
          "helmet": true,
          "kevlar": true,
          "weapon": "m4a1_silencer",
          "assists": 3,
          "player_id": "cs2-player-23773",
          "has_defuse_kit": false
        },
        {
          "hp": 100,
          "adr": 48.833333333333336,
          "name": "K014NZ",
          "nick": "K014NZ",
          "side": "CT",
          "alive": true,
          "kills": 8,
          "money": 0,
          "deaths": 16,
          "helmet": true,
          "kevlar": true,
          "weapon": "m4a1_silencer",
          "assists": 2,
          "player_id": "cs2-player-24840",
          "has_defuse_kit": true
        }
      ],
      "match_id": "cs2-match-2400384",
      "current_map": "de_anubis",
      "bomb_planted": false,
      "current_round": 18,
      "round_time_seconds": null
    }
  }
}
```

### cs2.match.completed

A CS2 match has finished, with the final map score and winner.

- When: When a match result is final.
- Status: Active. Sent during the last 7 days.
- Frequency: about 29 per day across all matches
- Plan: Pro and Scale
- Filters: league, matchId
- Use it to: Settle on the final map score and winner, then fetch player stats with /cs2/matches/{matchId}/player-stats.
- Notes: On this event matchId, mapId and winnerTeamId can use a different id prefix from other CS2 events. The trailing number is the same one as in cs2-match-{number}, so compare on that number.

| Field | Type | Meaning |
|---|---|---|
| `endsAt` | string | When the match ended, ISO 8601 UTC. |
| `event` | null or string | The tournament or event name inside data on CS2 events, the event name on the envelope. |
| `league` | string | League name, or the sport id on CS2 events. |
| `matchId` | string | The match id. Works on the match routes for this sport. |
| `team1Score` | number | Maps won by team 1 on match events, rounds on map events. Null while a map is being set up. |
| `team2Score` | number | Maps won by team 2 on match events, rounds on map events. Null while a map is being set up. |
| `teams` | array | The teams in this match. |
| `winnerTeamId` | string | The winning team id. Works on /cs2/teams/{id}. |

```json
{
  "event": "cs2.match.completed",
  "id": "a1b2c3d4-0000-4000-8000-000000000000",
  "timestamp": "2026-11-08T15:24:03.312Z",
  "event_type": "cs2.match.completed",
  "match_id": "cs2-match-2400316",
  "previous_state": null,
  "data": {
    "event": "ESL Challenger League Season 52 Europe Cup 11",
    "teams": [
      "Balkan Outlaws",
      "The Last Resort"
    ],
    "endsAt": "2026-11-08T15:24:03.241Z",
    "league": "cs2",
    "matchId": "cs2-match-2400316",
    "team1Score": 2,
    "team2Score": 0,
    "winnerTeamId": "cs2-team-14130"
  }
}
```

### cs2.map.started

A map of a CS2 series is known or has started.

- When: When a map record of a live series opens.
- Status: Active. Sent during the last 7 days.
- Frequency: about 343 per day across all matches (about 25 per match)
- Plan: Pro and Scale
- Filters: league, matchId
- Use it to: Show which map is in play. Be ready for repeats of the same map.
- Notes: data.mapName can be "TBA" and scores null until the map is picked and played, and this event can repeat for one map. On this event matchId, mapId and winnerTeamId can use a different id prefix from other CS2 events. The trailing number is the same one as in cs2-match-{number}, so compare on that number.

| Field | Type | Meaning |
|---|---|---|
| `league` | string | League name, or the sport id on CS2 events. |
| `mapId` | string | Map id. Works on /cs2/maps/{mapId}/economy. |
| `mapName` | string | Map name, or TBA until it is known. |
| `mapNumber` | number | Which map of the series, from 1. |
| `matchId` | string | The match id. Works on the match routes for this sport. |
| `team1Score` | null | Maps won by team 1 on match events, rounds on map events. Null while a map is being set up. |
| `team2Score` | null | Maps won by team 2 on match events, rounds on map events. Null while a map is being set up. |

```json
{
  "event": "cs2.map.started",
  "id": "a1b2c3d4-0000-4000-8000-000000000000",
  "timestamp": "2026-11-08T20:25:38.311Z",
  "event_type": "cs2.map.started",
  "match_id": "cs2-match-2400439",
  "previous_state": null,
  "data": {
    "mapId": "cs2-match-2400439-map-1",
    "league": "cs2",
    "mapName": "Default",
    "matchId": "cs2-match-2400439",
    "mapNumber": 1,
    "team1Score": null,
    "team2Score": null
  }
}
```

### cs2.map.completed

A map of a CS2 series finished, with the round score and winner.

- When: When a map ends.
- Status: Active. Sent during the last 7 days.
- Frequency: about 21 per day across all matches (about 2 per match)
- Plan: Pro and Scale
- Filters: league, matchId
- Use it to: Record the map winner and round score; settle per-map markets.
- Notes: On this event matchId, mapId and winnerTeamId can use a different id prefix from other CS2 events. The trailing number is the same one as in cs2-match-{number}, so compare on that number.

| Field | Type | Meaning |
|---|---|---|
| `league` | string | League name, or the sport id on CS2 events. |
| `mapId` | string | Map id. Works on /cs2/maps/{mapId}/economy. |
| `mapName` | string | Map name, or TBA until it is known. |
| `mapNumber` | number | Which map of the series, from 1. |
| `matchId` | string | The match id. Works on the match routes for this sport. |
| `team1Score` | number | Maps won by team 1 on match events, rounds on map events. Null while a map is being set up. |
| `team2Score` | number | Maps won by team 2 on match events, rounds on map events. Null while a map is being set up. |
| `winnerTeamId` | string | The winning team id. Works on /cs2/teams/{id}. |

```json
{
  "event": "cs2.map.completed",
  "id": "a1b2c3d4-0000-4000-8000-000000000000",
  "timestamp": "2026-11-06T18:31:57.023Z",
  "event_type": "cs2.map.completed",
  "match_id": "cs2-match-2400085",
  "previous_state": null,
  "data": {
    "mapId": "cs2-match-2400085-map-2",
    "league": "cs2",
    "mapName": "Ancient",
    "matchId": "cs2-match-2400085",
    "mapNumber": 2,
    "team1Score": 10,
    "team2Score": 13,
    "winnerTeamId": "cs2-team-14126"
  }
}
```

### cs2.round.started

A round started, with teams and sides.

- When: At the start of each round of a live match.
- Status: Active. Sent during the last 7 days.
- Frequency: about 1,184 per day across all matches (about 47 per match)
- Plan: Pro and Scale (real time)
- Filters: league, matchId
- Use it to: Reset round-level state: round timer, bomb state, sides.

| Field | Type | Meaning |
|---|---|---|
| `data` | object | The change itself, on score events. |
| `event_type` | string | The event name. |
| `league` | string | League name, or the sport id on CS2 events. |
| `match_id` | string | The match id. Works on the match routes for this sport. |
| `matchId` | string | The match id. Works on the match routes for this sport. |
| `previous_state` | null or object | The state before the change, when the event has one. |
| `timestamp` | string | When this event happened, ISO 8601 UTC. |

```json
{
  "event": "cs2.round.started",
  "id": "a1b2c3d4-0000-4000-8000-000000000000",
  "timestamp": "2026-11-08T20:29:35.329Z",
  "event_type": "cs2.round.started",
  "match_id": "cs2-match-2400320",
  "previous_state": {
    "score": {
      "team1": 4,
      "team2": 8
    },
    "round_number": 12
  },
  "data": {
    "data": {
      "map": "de_anubis",
      "score": {
        "team1": 8,
        "team2": 4
      },
      "teams": {
        "team1_name": "aimclub",
        "team2_name": "Balkan Outlaws",
        "terrorist_team_name": "Balkan Outlaws",
        "counter_terrorist_team_name": "aimclub"
      },
      "round_number": 13
    },
    "league": "cs2",
    "matchId": "cs2-match-2400320",
    "match_id": "cs2-match-2400320",
    "timestamp": "2026-11-08T20:29:35.312Z",
    "event_type": "cs2.round.started",
    "previous_state": {
      "score": {
        "team1": 4,
        "team2": 8
      },
      "round_number": 12
    }
  }
}
```

### cs2.round.ended

A round ended, with winner side and reason.

- When: At the end of each round of a live match.
- Status: Active. Sent during the last 7 days.
- Frequency: about 1,222 per day across all matches (about 51 per match)
- Plan: Pro and Scale (real time)
- Filters: league, matchId
- Use it to: Update round history with the winner side and reason.

| Field | Type | Meaning |
|---|---|---|
| `data` | object | The change itself, on score events. |
| `event_type` | string | The event name. |
| `league` | string | League name, or the sport id on CS2 events. |
| `match_id` | string | The match id. Works on the match routes for this sport. |
| `matchId` | string | The match id. Works on the match routes for this sport. |
| `previous_state` | object | The state before the change, when the event has one. |
| `timestamp` | string | When this event happened, ISO 8601 UTC. |

```json
{
  "event": "cs2.round.ended",
  "id": "a1b2c3d4-0000-4000-8000-000000000000",
  "timestamp": "2026-11-08T20:15:22.416Z",
  "event_type": "cs2.round.ended",
  "match_id": "cs2-match-2400228",
  "previous_state": {
    "score": {
      "team1": 13,
      "team2": 13
    },
    "round_number": 27
  },
  "data": {
    "data": {
      "map": "de_ancient",
      "score": {
        "team1": 13,
        "team2": 13
      },
      "reason": "Terrorists_Win",
      "winner": "TERRORIST",
      "event_id": "ef9cb4d9d46a3126439ff1a6d8745d31",
      "timestamp": "2026-11-08T20:15:21.644Z",
      "round_number": 27
    },
    "league": "cs2",
    "matchId": "cs2-match-2400228",
    "match_id": "cs2-match-2400228",
    "timestamp": "2026-11-08T20:15:22.400Z",
    "event_type": "cs2.round.ended",
    "previous_state": {
      "score": {
        "team1": 13,
        "team2": 13
      },
      "round_number": 27
    }
  }
}
```

### cs2.bomb.planted

The bomb was planted: site, player and players alive per side.

- When: On each plant in a live match.
- Status: Active. Sent during the last 7 days.
- Frequency: about 660 per day across all matches (about 28 per match)
- Plan: Pro and Scale (real time)
- Filters: league, matchId
- Use it to: Show the bomb site and start a bomb timer.

| Field | Type | Meaning |
|---|---|---|
| `data` | object | The change itself, on score events. |
| `event_type` | string | The event name. |
| `league` | string | League name, or the sport id on CS2 events. |
| `match_id` | string | The match id. Works on the match routes for this sport. |
| `matchId` | string | The match id. Works on the match routes for this sport. |
| `previous_state` | null | The state before the change, when the event has one. |
| `timestamp` | string | When this event happened, ISO 8601 UTC. |

```json
{
  "event": "cs2.bomb.planted",
  "id": "a1b2c3d4-0000-4000-8000-000000000000",
  "timestamp": "2026-11-08T19:42:56.992Z",
  "event_type": "cs2.bomb.planted",
  "match_id": "cs2-match-2400320",
  "previous_state": null,
  "data": {
    "data": {
      "map": "de_dust2",
      "site": "A",
      "event_id": "0a7e3923f3a1b55cf4898789ec303f12",
      "t_players": 1,
      "timestamp": "2026-11-08T19:42:56.294Z",
      "ct_players": 1,
      "player_name": "starplajerz",
      "player_nick": "starplajerz",
      "round_number": 19
    },
    "league": "cs2",
    "matchId": "cs2-match-2400320",
    "match_id": "cs2-match-2400320",
    "timestamp": "2026-11-08T19:42:56.948Z",
    "event_type": "cs2.bomb.planted",
    "previous_state": null
  }
}
```

### cs2.bomb.defused

The bomb was defused.

- When: On each defuse in a live match.
- Status: Active. Sent during the last 7 days.
- Frequency: about 1 per day across all matches
- Plan: Pro and Scale (real time)
- Filters: none
- Use it to: Stop the bomb timer and mark the defuse.

### cs2.bomb.exploded

The bomb exploded.

- When: On each explosion in a live match.
- Status: Active. Sent during the last 7 days.
- Frequency: about 1 per day across all matches
- Plan: Pro and Scale (real time)
- Filters: none
- Use it to: Stop the bomb timer and mark the explosion.

### cs2.score.updated

The live score changed.

- When: When the map or round score of a live match changes.
- Status: Active. Sent during the last 7 days.
- Frequency: about 2,225 per day across all matches (about 90 per match)
- Plan: Pro and Scale (real time)
- Filters: league, matchId
- Use it to: Update the on-screen score. previous_state.score holds the score before the change.
- Notes: previous_state.score holds the score before the change. A score can be null while a map is being set up. Round-level detail (data.map, data.round_number) is on most events, not all.

| Field | Type | Meaning |
|---|---|---|
| `data` | object | The change itself, on score events. |
| `event_type` | string | The event name. |
| `league` | string | League name, or the sport id on CS2 events. |
| `match_id` | string | The match id. Works on the match routes for this sport. |
| `matchId` | string | The match id. Works on the match routes for this sport. |
| `previous_state` | object | The state before the change, when the event has one. |
| `team1Score` | null | Maps won by team 1 on match events, rounds on map events. Null while a map is being set up. |
| `team2Score` | null | Maps won by team 2 on match events, rounds on map events. Null while a map is being set up. |
| `timestamp` | string | When this event happened, ISO 8601 UTC. |

```json
{
  "event": "cs2.score.updated",
  "id": "a1b2c3d4-0000-4000-8000-000000000000",
  "timestamp": "2026-11-08T20:29:56.291Z",
  "event_type": "cs2.score.updated",
  "match_id": "cs2-match-2400228",
  "previous_state": {
    "score": {
      "team1": 1,
      "team2": 1
    }
  },
  "data": {
    "data": {
      "score": {
        "team1": null,
        "team2": null
      }
    },
    "league": "cs2",
    "matchId": "cs2-match-2400228",
    "match_id": "cs2-match-2400228",
    "timestamp": "2026-11-08T20:29:56.266Z",
    "event_type": "cs2.score.updated",
    "team1Score": null,
    "team2Score": null,
    "previous_state": {
      "score": {
        "team1": 1,
        "team2": 1
      }
    }
  }
}
```

### cs2.player.state_changed

A player changed: health, money, weapon, armor, kills or similar. data.changes lists what changed.

- When: Many times per round for every player in a live match. This is by far the highest-volume event: subscribe only if you need it, and answer quickly.
- Status: Active. Sent during the last 7 days.
- Frequency: about 58,003 per day across all matches (about 2,417 per match)
- Plan: Pro and Scale (real time)
- Filters: league, matchId
- Use it to: Drive a full live player panel. Very high volume: only subscribe if you draw that panel, and answer fast.

| Field | Type | Meaning |
|---|---|---|
| `data` | object | The change itself, on score events. |
| `event_type` | string | The event name. |
| `league` | string | League name, or the sport id on CS2 events. |
| `match_id` | string | The match id. Works on the match routes for this sport. |
| `matchId` | string | The match id. Works on the match routes for this sport. |
| `previous_state` | object | The state before the change, when the event has one. |
| `timestamp` | string | When this event happened, ISO 8601 UTC. |

```json
{
  "event": "cs2.player.state_changed",
  "id": "a1b2c3d4-0000-4000-8000-000000000000",
  "timestamp": "2026-11-08T20:29:47.086Z",
  "event_type": "cs2.player.state_changed",
  "match_id": "cs2-match-2400094",
  "previous_state": {
    "score": {
      "team1": 1,
      "team2": 3
    },
    "player": {
      "hp": 100,
      "adr": 67.4,
      "name": "Lucaozy",
      "nick": "Lucaozy",
      "side": "CT",
      "alive": true,
      "kills": 4,
      "money": 4850,
      "deaths": 2,
      "helmet": true,
      "kevlar": true,
      "weapon": "ak47",
      "assists": 3,
      "player_id": "cs2-player-18717",
      "has_defuse_kit": true
    },
    "round_number": 5
  },
  "data": {
    "data": {
      "map": "de_nuke",
      "score": {
        "team1": 1,
        "team2": 3
      },
      "player": {
        "hp": 100,
        "adr": 67.4,
        "name": "Lucaozy",
        "nick": "Lucaozy",
        "side": "CT",
        "alive": true,
        "kills": 5,
        "money": 5150,
        "deaths": 2,
        "helmet": true,
        "kevlar": true,
        "weapon": "ak47",
        "assists": 3,
        "player_id": "cs2-player-18717",
        "has_defuse_kit": true
      },
      "changes": [
        "kill",
        "money_threshold_crossed"
      ],
      "round_number": 5
    },
    "league": "cs2",
    "matchId": "cs2-match-2400094",
    "match_id": "cs2-match-2400094",
    "timestamp": "2026-11-08T20:29:47.071Z",
    "event_type": "cs2.player.state_changed",
    "previous_state": {
      "score": {
        "team1": 1,
        "team2": 3
      },
      "player": {
        "hp": 100,
        "adr": 67.4,
        "name": "Lucaozy",
        "nick": "Lucaozy",
        "side": "CT",
        "alive": true,
        "kills": 4,
        "money": 4850,
        "deaths": 2,
        "helmet": true,
        "kevlar": true,
        "weapon": "ak47",
        "assists": 3,
        "player_id": "cs2-player-18717",
        "has_defuse_kit": true
      },
      "round_number": 5
    }
  }
}
```

### cs2.live.state

A snapshot of a live match: status, score and current map.

- When: Repeatedly during a live match.
- Status: Active. Sent during the last 7 days.
- Frequency: about 5,582 per day across all matches (about 221 per match)
- Plan: Pro and Scale (real time)
- Filters: league, matchId
- Use it to: Resync a live scoreboard when you may have missed a tick.

| Field | Type | Meaning |
|---|---|---|
| `currentMap` | null | The map in play. |
| `data` | object | The change itself, on score events. |
| `event_type` | string | The event name. |
| `league` | string | League name, or the sport id on CS2 events. |
| `match_id` | string | The match id. Works on the match routes for this sport. |
| `matchId` | string | The match id. Works on the match routes for this sport. |
| `previous_state` | object | The state before the change, when the event has one. |
| `status` | string | Current status of the match. |
| `team1Score` | null or number | Maps won by team 1 on match events, rounds on map events. Null while a map is being set up. |
| `team2Score` | null or number | Maps won by team 2 on match events, rounds on map events. Null while a map is being set up. |
| `timestamp` | string | When this event happened, ISO 8601 UTC. |

```json
{
  "event": "cs2.live.state",
  "id": "a1b2c3d4-0000-4000-8000-000000000000",
  "timestamp": "2026-11-08T20:29:17.981Z",
  "event_type": "cs2.live.state",
  "match_id": "cs2-match-2400094",
  "previous_state": {
    "score": {
      "team1": 0,
      "team2": 1
    },
    "status": "live"
  },
  "data": {
    "data": {
      "score": {
        "team1": 0,
        "team2": 1
      },
      "status": "live",
      "current_map": null
    },
    "league": "cs2",
    "status": "live",
    "matchId": "cs2-match-2400094",
    "match_id": "cs2-match-2400094",
    "timestamp": "2026-11-08T20:29:17.966Z",
    "currentMap": null,
    "event_type": "cs2.live.state",
    "team1Score": 0,
    "team2Score": 1,
    "previous_state": {
      "score": {
        "team1": 0,
        "team2": 1
      },
      "status": "live"
    }
  }
}
```

### cs2.live.player_stats_updated

Live player stats were refreshed. A count only: data.playerStatRows says how many rows changed.

- When: During a live match.
- Status: Active. Sent during the last 7 days.
- Frequency: about 565 per day across all matches (about 57 per match)
- Plan: Pro and Scale (real time)
- Filters: league, matchId
- Use it to: Re-read /cs2/live/{matchId} for fresh player lines.
- Notes: Treat it as a signal to re-read /cs2/live/{matchId}. It carries no player stats.

| Field | Type | Meaning |
|---|---|---|
| `data` | object | The change itself, on score events. |
| `event_type` | string | The event name. |
| `league` | string | League name, or the sport id on CS2 events. |
| `match_id` | string | The match id. Works on the match routes for this sport. |
| `matchId` | string | The match id. Works on the match routes for this sport. |
| `playerStatRows` | number | How many player rows changed. Read /cs2/live/{matchId} for the rows. |
| `previous_state` | null | The state before the change, when the event has one. |
| `timestamp` | string | When this event happened, ISO 8601 UTC. |

```json
{
  "event": "cs2.live.player_stats_updated",
  "id": "a1b2c3d4-0000-4000-8000-000000000000",
  "timestamp": "2026-11-08T19:12:51.400Z",
  "event_type": "cs2.live.player_stats_updated",
  "match_id": "cs2-match-2400319",
  "previous_state": null,
  "data": {
    "data": {
      "player_stat_rows": 10
    },
    "league": "cs2",
    "matchId": "cs2-match-2400319",
    "match_id": "cs2-match-2400319",
    "timestamp": "2026-11-08T19:12:51.385Z",
    "event_type": "cs2.live.player_stats_updated",
    "playerStatRows": 10,
    "previous_state": null
  }
}
```

### cs2.ranking.updated

A CS2 team ranking update.

- When: When rankings change.
- Status: None recorded yet. You can subscribe, but none has been recorded. Do not rely on it.
- Frequency: none recorded so far
- Plan: Pro and Scale
- Filters: none
- Use it to: Refresh a rankings table.
