Partner API

Viewership API

Access tournament viewership data programmatically — concurrent viewers, daily stats, channel breakdowns.

Overview

Base URL

https://app.escharts.com/api/viewership

All endpoints return JSON. Dates use Y-m-d format. Timestamps are UTC.

Authentication

Pass your API token as a Bearer token in every request:

Authorization: Bearer <your_token>

Rate Limiting

120 requests per minute per token. Exceeding the limit returns 429 Too Many Requests.

Errors

{
  "error": "game_id is not in your allowed games list.",
  "status": 403
}
CodeMeaning
401 Missing or invalid token
403 Requested data is outside your partner access scope
422 Validation error — check required parameters
429 Rate limit exceeded

Field Glossary

Canonical fields returned across viewership endpoints.

FieldDescription
channel_name Display name of the channel
platform Streaming platform (Twitch, YouTube, etc.)
category "Official" or "Co-stream"
language Human-readable language name (e.g. "English")
tournament Tournament display name
day Tournament day number (1-based, from tournament start date)
phase Stage / phase name (VERIFIED only)
label Match label, e.g. "Faze Clan vs Falcons" (channel-minute VERIFIED only)
team_a, team_b Names of the two teams playing the match (channel-minute VERIFIED only)
timestamp Slot timestamp (UTC). RAW = 1-minute granularity; VERIFIED = 5-minute granularity
start_timestamp Min start datetime across official channels (UTC)
end_timestamp Max end datetime across official channels (UTC)
airtime Total broadcast hours
hours_watched Total hours watched (viewers × time)
average_viewers Average concurrent viewers
peak_viewers Maximum concurrent viewers
concurrent_viewers Concurrent viewers in the slot. RAW slots are 1 minute wide; VERIFIED slots are 5 minutes wide
views Total view count
unique_viewers Estimated unique viewers (broadcast-tournament only)
media_value_eur Estimated ad-equivalent media value in EUR (broadcast-tournament only)
GET /tournaments

List Tournaments

Paginated list of tournaments with aggregated viewership stats. Results are limited to tournaments in your partner access scope.

Query Parameters

ParameterTypeRequiredDescription
game_id int Filter by game ID
organizer_id int Filter by organizer ID
event_id int Filter by event series ID
date_from Y-m-d Tournaments that ended on or after this date
date_to Y-m-d Tournaments that started on or before this date
search string Partial match on tournament name (max 100 chars)
sort_by string name · hours_watched · peak_viewers · avg_viewers · air_time · starts_at · ends_at · prize_pool · matches_count · match_days
sort_order string ASC or DESC (default DESC)
page int Page number (default 1)
per_page int Results per page, max 200 (default 50)

Response

{
  "data": [
    {
      "tournament_id": 1234,
      "name": "Six Invitational 2025",
      "slug": "six-invitational-2025",
      "game_name": "Rainbow Six Siege",
      "game_id": 11,
      "event_name": "Six Invitational",
      "event_id": 42,
      "starts_at": "2025-02-10 00:00:00",
      "ends_at": "2025-02-23 00:00:00",
      "hours_watched": 2540000.0,
      "peak_viewers": 312000,
      "avg_viewers": 85000.0,
      "air_time_minutes": 5400,
      "prize_pool": 3000000,
      "is_offline": 1,
      "organizer_names": "Ubisoft",
      "venue_names": "Montreal",
      "matches_count": 42,
      "match_days": 12
    }
  ],
  "meta": {
    "page": 1,
    "per_page": 50,
    "total": 1,
    "sort_by": "ends_at",
    "sort_order": "DESC"
  }
}
GET /tournament-channels

Tournament Channels

Full channel breakdown for a tournament — one row per channel with aggregated stats for the entire event. Use the returned channel_id values with the channel-level endpoints.

Query Parameters

ParameterTypeRequiredDescription
tournament_id int Tournament ID
official_only bool Return only official/main broadcast channels (default false)
sort_by string hours_watched · peak_viewers · avg_viewers · air_time · channel_name (default hours_watched)
sort_order string ASC or DESC (default DESC)

Response

{
  "data": [
    {
      "channel_id": 5678,
      "stream_entity_id": 0,
      "channel_name": "Rainbow6",
      "channel_slug": "rainbow6",
      "platform": "Twitch",
      "platform_slug": "twitch.tv",
      "category": "Official",
      "language": "English",
      "other_languages": [],
      "hours_watched": 920000.0,
      "peak_viewers": 180000,
      "avg_viewers": 95000.0,
      "airtime": 54.0,
      "views": 4200000
    }
  ],
  "meta": {
    "tournament_id": 1234,
    "official_only": false,
    "sort_by": "hours_watched",
    "sort_order": "DESC",
    "count": 18
  }
}
GET /tournament-matches

Tournament Matches

Full match schedule for a tournament with aggregated viewership stats. All parallel matches (Stream A / Stream B) are returned as separate rows. Useful for attributing viewership to specific matches.

Query Parameters

ParameterTypeRequiredDescription
tournament_id int Tournament ID
date Y-m-d Filter to matches played on a specific day. Omit to get all matches for the tournament

Response

{
  "data": [
    {
      "match_id": 101,
      "match_name": "Falcons VS EP",
      "stage_name": "Group Stage",
      "starts_at": "2025-11-15 14:00:00",
      "ends_at": "2025-11-15 15:28:00",
      "team_a": "Falcons",
      "team_b": "EP",
      "hours_watched": 12500.0,
      "peak_viewers": 45000,
      "avg_viewers": 38200.0,
      "air_time_minutes": 88
    },
    {
      "match_id": 102,
      "match_name": "Wildcard VS LOS",
      "stage_name": "Group Stage",
      "starts_at": "2025-11-15 14:00:00",
      "ends_at": "2025-11-15 15:15:00",
      "team_a": "Wildcard",
      "team_b": "LOS",
      "hours_watched": 3200.0,
      "peak_viewers": 9800,
      "avg_viewers": 7500.0,
      "air_time_minutes": 75
    }
  ],
  "meta": {
    "tournament_id": 1234,
    "date": "2025-11-15",
    "count": 2
  }
}
GET /channel-minute

Channel Minute

Concurrent viewers per minute for a given day. Pass channel_id or stream_entity_id for a single channel, channel_ids[]/stream_entity_ids[] for a subset, or omit all to get every channel.

RAW — true 1-min granularity from raw scans, ≤5 min delay VERIFIED — 5-min granularity with match context, available 24–120 h after stream end

Query Parameters

ParameterTypeRequiredDescription
tournament_id int Tournament ID
status string RAW or VERIFIED
date Y-m-d ✓* Date to query. Required unless match_id is provided (date is derived from the match automatically)
match_id int Filter to a single match window. Shorthand for match_ids[]=X. When provided, date can be omitted
match_ids[] int[] Filter to one or more matches — e.g. match_ids[]=101&match_ids[]=102. Minutes within any of the match windows are returned. date can be omitted. Works with both RAW and VERIFIED
channel_id int Single channel ID (when channel_id != 0 in /tournament-channels). Mutually exclusive with channel_ids[]
stream_entity_id int Single stream entity ID (when channel_id == 0 in /tournament-channels). Mutually exclusive with stream_entity_ids[]
channel_ids[] int[] Filter multiple channels by ID — e.g. channel_ids[]=1&channel_ids[]=2. Only applied when channel_id/stream_entity_id are omitted
stream_entity_ids[] int[] Filter multiple stream entities by ID. Only applied when channel_id/stream_entity_id are omitted. Can be combined with channel_ids[]
page int Page number (default: 1)
per_page int Rows per page (default: 10000, max: 10000)

Response — status=RAW, with channel_id

{
  "data": [
    {
      "channel_name": "Rainbow6",
      "platform": "Twitch",
      "category": "Official",
      "language": "English",
      "tournament": "SLC Major 2026",
      "timestamp": "2026-05-15 15:33:00",
      "concurrent_viewers": 12345
    }
  ],
  "status": "RAW",
  "meta": {
    "tournament_id": 1234,
    "tournament_name": "SLC Major 2026",
    "channel_id": 5678,
    "date": "2026-05-15",
    "day": 6,
    "scope": "channel"
  }
}

Response — status=VERIFIED, with channel_id

{
  "data": [
    {
      "channel_name": "Rainbow6",
      "platform": "Twitch",
      "category": "Official",
      "language": "English",
      "tournament": "SLC Major 2026",
      "day": 6,
      "phase": "Playoffs",
      "label": "Faze Clan vs Falcons",
      "team_a": "Faze Clan",
      "team_b": "Falcons",
      "timestamp": "2026-05-15 15:33:00",
      "concurrent_viewers": 12345
    }
  ],
  "status": "VERIFIED",
  "meta": {
    "tournament_id": 1234,
    "tournament_name": "Six Invitational 2025",
    "channel_id": 5678,
    "date": "2025-02-10",
    "day": 1,
    "scope": "channel"
  }
}

day, phase, label, team_a, team_b are only present in VERIFIED responses. Values are null for slots outside any match window.

Response — status=RAW, without channel_id

One row per channel per minute, ordered by timestamp ASC, concurrent_viewers DESC.

{
  "data": [
    {
      "channel_name": "Rainbow6",
      "platform": "Twitch",
      "category": "Official",
      "language": "English",
      "tournament": "SLC Major 2026",
      "timestamp": "2026-05-15 15:33:00",
      "concurrent_viewers": 12345
    }
  ],
  "status": "RAW",
  "meta": {
    "tournament_id": 1234,
    "tournament_name": "SLC Major 2026",
    "channel_id": null,
    "date": "2026-05-15",
    "day": 6,
    "scope": "all_channels"
  }
}

Response — status=VERIFIED, without channel_id

One row per channel per 5-minute slot (VERIFIED source granularity), with match context attached.

{
  "data": [
    {
      "channel_name": "Rainbow6",
      "platform": "Twitch",
      "category": "Official",
      "language": "English",
      "tournament": "SLC Major 2026",
      "day": 6,
      "phase": "Playoffs",
      "label": "Faze Clan vs Falcons",
      "team_a": "Faze Clan",
      "team_b": "Falcons",
      "timestamp": "2026-05-15 15:33:00",
      "concurrent_viewers": 12345
    }
  ],
  "status": "VERIFIED",
  "meta": {
    "tournament_id": 1234,
    "tournament_name": "SLC Major 2026",
    "channel_id": null,
    "date": "2026-05-15",
    "day": 6,
    "scope": "all_channels"
  }
}
GET /channel-day

Channel Day

Aggregated daily stats. With channel_id — one summary row for that channel. Without — one row per channel ordered by hours watched.

RAW — near real-time, ≤5 min delay VERIFIED — post-processed, available 24–120 h after stream end

Query Parameters

ParameterTypeRequiredDescription
tournament_id int Tournament ID
date Y-m-d Date to query
status string RAW or VERIFIED
channel_id int Channel ID (channel_id != 0 in /tournament-channels). Omit for one row per channel
stream_entity_id int Stream entity ID (channel_id == 0 in /tournament-channels). Mutually exclusive with channel_id

Response — status=RAW

{
  "data": [
    {
      "channel_name": "Rainbow6",
      "platform": "Twitch",
      "category": "Official",
      "language": "English",
      "tournament": "SLC Major 2026",
      "day": 6,
      "start_timestamp": "2026-05-15 12:00:00",
      "end_timestamp": "2026-05-15 20:30:00",
      "airtime": 8.5,
      "hours_watched": 104932.5,
      "average_viewers": 12345,
      "peak_viewers": 12345,
      "views": 4321
    }
  ],
  "status": "RAW",
  "meta": {
    "tournament_id": 1234,
    "tournament_name": "SLC Major 2026",
    "channel_id": null,
    "date": "2026-05-15",
    "day": 6,
    "scope": "all_channels"
  }
}

Response — status=VERIFIED (adds phase)

{
  "data": [
    {
      "channel_name": "Rainbow6",
      "platform": "Twitch",
      "category": "Official",
      "language": "English",
      "tournament": "SLC Major 2026",
      "day": 6,
      "phase": "Playoffs",
      "start_timestamp": "2026-05-15 12:00:00",
      "end_timestamp": "2026-05-15 20:30:00",
      "airtime": 8.5,
      "hours_watched": 104932.5,
      "average_viewers": 12345,
      "peak_viewers": 12345,
      "views": 4321
    }
  ],
  "status": "VERIFIED",
  "meta": {
    "tournament_id": 1234,
    "tournament_name": "SLC Major 2026",
    "channel_id": null,
    "date": "2026-05-15",
    "day": 6,
    "scope": "all_channels"
  }
}
GET /broadcast-day

Broadcast Day

Daily totals across all official channels. Concurrent viewers are summed per 5-minute slot before aggregation.

RAW — ≤30 min delay VERIFIED — post-processed, available 24–120 h after stream end

Query Parameters

ParameterTypeRequiredDescription
tournament_id int Tournament ID
date Y-m-d Date to query
status string RAW or VERIFIED

Response

{
  "data": [
    {
      "tournament": "SLC Major 2026",
      "day": 6,
      "start_timestamp": "2026-05-15 12:00:00",
      "end_timestamp": "2026-05-15 20:30:00",
      "airtime": 8.5,
      "hours_watched": 104932.5,
      "average_viewers": 12345,
      "peak_viewers": 12345,
      "views": 4321
    }
  ],
  "status": "RAW",
  "meta": {
    "tournament_id": 1234,
    "tournament_name": "SLC Major 2026",
    "date": "2026-05-15",
    "day": 6
  }
}

Response — status=VERIFIED (adds phase)

{
  "data": [
    {
      "tournament": "SLC Major 2026",
      "day": 6,
      "phase": "Playoffs",
      "start_timestamp": "2026-05-15 12:00:00",
      "end_timestamp": "2026-05-15 20:30:00",
      "airtime": 8.5,
      "hours_watched": 104932.5,
      "average_viewers": 12345,
      "peak_viewers": 12345,
      "views": 4321
    }
  ],
  "status": "VERIFIED",
  "meta": {
    "tournament_id": 1234,
    "tournament_name": "SLC Major 2026",
    "date": "2026-05-15",
    "day": 6
  }
}
GET /broadcast-tournament

Broadcast Tournament

Single-row tournament-level totals across all official channels. Same shape for RAW and VERIFIED — RAW has shorter cache.

RAW — ≤30 min cache VERIFIED — post-processed totals

Query Parameters

ParameterTypeRequiredDescription
tournament_id int Tournament ID
status string RAW or VERIFIED

Response

start_timestamp / end_timestamp are min/max across all official channels.

{
  "data": {
    "tournament": "SLC Major 2026",
    "start_timestamp": "2026-05-08 10:05:00",
    "end_timestamp": "2026-05-17 18:45:00",
    "airtime": 120.75,
    "hours_watched": 1490659.75,
    "average_viewers": 12345,
    "peak_viewers": 12345,
    "views": 36199618,
    "unique_viewers": 543210,
    "media_value_eur": 1454581
  },
  "status": "VERIFIED",
  "meta": {
    "tournament_id": 1234
  }
}

unique_viewers may be null if post-verification has not yet completed. media_value_eur is estimated using CPM rates by language and game area.

Typical Workflow

  1. 1
    /tournaments

    Discover available tournaments and their IDs. Filter by game, date range, or event series.

  2. 2
    /tournament-channels

    Get all channels for a tournament. Each entry has a channel_id for the next steps.

  3. 3
    /channel-minute or /channel-day

    Fetch channel-level viewership. Pass channel_id for one channel, or omit it for aggregated totals.

  4. 4
    /broadcast-day or /broadcast-tournament

    Get official broadcast totals — peak concurrent and hours watched across main streams.