How to reduce API consumption when monitoring 50+ matches simultaneously?

How to reduce API consumption when monitoring 50+ sports matches simultaneously

When the system is tracking 50 or more matches in different sports simultaneously, the main enemy is excessive requests. Each unnecessary call to the sports API increases tariff consumption, delays, and load on your backend. A proper data handling strategy allows you to reduce the number of API calls significantly without losing service quality: update speeds for scores, statistics, or bookmaker odds.

The platform Sports events and odds API api-sport.ru Initially designed for high loads: one request can retrieve up to 100 matches, use filtering by tournaments, categories, and status, as well as receive all key parameters in the response — from the current score and minute of the match to live events. liveEvents, detailed statistics matchStatistics and bookmaker lines oddsBase. Thanks to this, there is no need to hit dozens of different endpoints to solve a simple monitoring task.

The basic approach to optimizing consumption with 50+ matches looks like this:

  • combine matches into one request via a parameter ids (up to 100 identifiers at a time);
  • separate «light» monitoring (score, status, minute, key odds) and «heavy» requests (full lineups, advanced statistics, event history) and call them only on event;
  • use cache and local storage to avoid requesting the same data (teams, tournaments, players) multiple times;
  • switch to streaming and WebSocket whenever possible (as soon as it becomes available in api-sport.ru), leaving REST only for initialization and background updates.

Below is an example of how to get a list of 50+ football matches in one request to the API:

const API_BASE = 'https://api.api-sport.ru/v2/football';
const API_KEY = 'YOUR_API_KEY'; // получите ключ в личном кабинете
const matchIds = [
  14570728, 14586240, 14590001, 14590002,
  // ... до 100 ID матчей
];
async function loadMatches() {
  const url = `${API_BASE}/matches?ids=${matchIds.join(',')}`;
  const response = await fetch(url, {
    headers: { 'Authorization': API_KEY }
  });
  const data = await response.json();
  console.log('Всего матчей:', data.totalMatches);
  // используйте data.matches для вывода счета, минут и коэффициентов
}
loadMatches();

With this approach, instead of 50+ separate HTTP requests, you only make one, which is especially important under high loads when football, basketball, tennis, table tennis, esports, and other disciplines are tracked simultaneously.

Limitations and quotas of sports APIs: how to calculate request consumption

Any sports API operates with limits: the number of requests per unit of time and/or the total daily/monthly volume is restricted. Specific values depend on the chosen plan and are described in the service terms, but the principle of calculating consumption is always the same — it is important to understand how many requests your monitoring cycle generates with the current update frequency settings and the number of matches being tracked.

In the sports events API api-sport.ru, the key factor is the number of HTTP requests. One request can contain up to 100 matches in the parameter ids, so for monitoring 50+ events, it is important not to query each match separately, but to use grouping effectively. Everything boils down to a simple formula:

  • Nrequests per minute = 60 / update_interval_in_seconds;
  • Nrequests per day = Nrequests per minute × 60 × 24;
  • if all 50+ matches are requested in each request by ids, the number of matches in the formula is no longer involved.

For example, if you update data for 50 matches every 10 seconds with one batch request to /v2/{sportSlug}/matches, the calculation looks like this: 60 / 10 = 6 requests per minute, 6 × 60 × 24 = 8640 requests per day. This figure already allows you to understand whether you are within the tariff limit and whether it makes sense to request «heavy» data like extended statistics less frequently.

Below is a small utility example that will help estimate the request consumption for any update interval:

function calcDailyRequests(intervalSec) {
  const pollsPerMinute = 60 / intervalSec;
  return pollsPerMinute * 60 * 24;
}
console.log('10 секунд:', calcDailyRequests(10)); // 8640
console.log('15 секунд:', calcDailyRequests(15)); // 5760
console.log('30 секунд:', calcDailyRequests(30)); // 2880

Using such an estimate, you can choose a safe polling interval for live monitoring, and then fine-tune the consumption: separating requests by sports, tournaments, match statuses, and data types (for example, pulling bookmaker odds separately through the field oddsBase only where they are really needed).

What match data is really needed and how to reduce fields in the API response

Most monitoring systems do not use the full volume of data provided by the sports API. For the score widget, match IDs, teams, current score, status, and minute are important. For the analytics dashboard — separate blocks of statistics. For betting services — markets and odds from oddsBase. The rest can be requested less frequently or not at all.

In the API /v2/{sportSlug}/matches you receive an object матч with a large number of fields: домашнийСчет, выезднойСчет, currentMatchMinute, status, liveEvents, matchStatistics, oddsBase, highlights etc. To reduce the total load, it makes sense to separate the logic:

  • for constant live monitoring, use only the list of matches with key fields (score, status, minute, basic odds);
  • match details through /v2/{sportSlug}/matches/{matchId} request only based on user actions (opening the match page, hovering the cursor, clicking on the card);
  • a separate endpoint /v2/{sportSlug}/matches/{matchId}/events should be called only by those services that really need the full event chronology, not just the current score.

Below is an example of how to keep only the necessary minimum in memory for a fast interface from the full match structure:

function mapMatchForWidget(match) {
  return {
    id: match.id,
    tournament: match.tournament?.name,
    homeTeam: match.homeTeam?.name,
    awayTeam: match.awayTeam?.name,
    status: match.status,
    minute: match.currentMatchMinute,
    score: `${match.homeScore?.current ?? 0}:${match.awayScore?.current ?? 0}`,
    // пример работы с коэффициентами букмекеров из oddsBase
    mainOdds: match.oddsBase?.find(m => m.group === '1X2') || null
  };
}
// data.matches — результат вызова /v2/{sportSlug}/matches
const compactMatches = data.matches.map(mapMatchForWidget);

Such «trimming» of the structure does not reduce the number of requests to the API, but allows for effective caching and quick rendering of the interface. You clearly separate the data layer that should be updated as often as possible (minimum set of fields) and the extended information layer that can be requested only by triggers. This is especially useful when working with many sports: football, hockey, basketball, tennis, table tennis, esports, and other supported disciplines. api-sport.ru.

Optimal request frequency to sports API during live monitoring

Request frequency is the main lever for controlling the consumption of the sports API. Too infrequent polling will lead to delays in the interface, while too frequent polling will quickly «eat» the limit. It is important to find a reasonable balance considering the type of project: media portal, betting platform, analytical service, or internal BI system.

For most live monitoring scenarios via REST API, an interval of 5–15 seconds is sufficient to display the score and key events, even if more than 50 matches are tracked simultaneously. For pre-match lines and long-term statistics, the interval can be increased to 30–60 seconds or more. Remember that the data sources themselves (league feeds, odds providers) are also updated discretely, so requests more frequently than once every few seconds usually do not provide additional practical benefits.

Working approach to setting the polling frequency:

  • divide matches into «critical» (key tournaments, top leagues, VIP clients) and «background» coverage;
  • for critical matches, use a more frequent interval, such as 5–7 seconds, for others — 15–30 seconds;
  • separately configure the frequency of odds updates oddsBase, if your project is related to betting: often 10–20 seconds is sufficient;
  • plan in advance for a transition to WebSocket/streaming in the architecture to reduce the number of REST requests in the future while maintaining or even increasing the speed of data updates.

Below is an example of a simple API polling loop for a set of matches by their ID:

const API_BASE = 'https://api.api-sport.ru/v2/basketball';
const API_KEY = 'YOUR_API_KEY';
const INTERVAL_MS = 10_000; // 10 секунд
const matchIds = [111, 222, 333];
async function pollMatches() {
  const url = `${API_BASE}/matches?ids=${matchIds.join(',')}&status=inprogress`;
  const response = await fetch(url, {
    headers: { 'Authorization': API_KEY }
  });
  const data = await response.json();
  // обновите виджеты счета и коэффициентов
  console.log(new Date().toISOString(), 'матчей в игре:', data.totalMatches);
}
setInterval(pollMatches, INTERVAL_MS);

Such a loop easily scales to dozens and hundreds of matches, as a large batch is processed in one request. If necessary, multiple such loops can be run for different sports or tournaments, flexibly distributing the load and overall API limit consumption.

How to use WebSocket and streaming to reduce the number of REST requests to the API

REST requests are great for initializing data and background updates, but with aggressive live monitoring of 50+ matches, they inevitably lead to a large number of requests. The solution is streaming data via WebSocket. In this mode, the client establishes a connection once, subscribes to the matches of interest, and then receives updates as they occur without constant polling.

On the side the personal account api-sport.ru new opportunities are already developing, and soon the platform will receive support for WebSocket subscriptions. This will significantly reduce the consumption of REST requests: REST will remain for obtaining the primary list of matches (for example, through /v2/{sportSlug}/matches filters by tournaments and status), while further changes in score, live events liveEvents, statistics, and odds will come in real-time through a single persistent connection.

The conceptual scheme for working with the WebSocket channel may look like this:

  • you request a list of the needed matches via REST and form an array of their IDs;
  • you open a WebSocket connection to the address specified in the documentation api-sport.ru;
  • you send a message with the subscription type and the list of match IDs;
  • you update the UI and internal cache as events come through the channel.

An example of pseudocode for working with WebSocket (address and message format should be clarified in the official documentation when the functionality becomes available):

const WS_URL = 'wss://YOUR_WS_ENDPOINT'; // точный URL будет указан в документации api-sport.ru
const matchIds = [14570728, 14586240];
const socket = new WebSocket(WS_URL);
socket.onopen = () => {
  socket.send(JSON.stringify({
    action: 'subscribe',
    sport: 'football',
    matches: matchIds
  }));
};
socket.onmessage = (event) => {
  const message = JSON.parse(event.data);
  if (message.type === 'match_update') {
    // обновление счета, минуты, liveEvents, oddsBase и т.п.
    console.log('Обновление матча:', message.payload.id, message.payload);
  }
};

Transitioning to streaming is especially beneficial for projects working with bookmaker lines and frequent odds changes: instead of a thousand REST requests per minute, a single stable WebSocket connection is sufficient, through which only real changes in matches and betting markets come.

Caching and local database for sports data: how to reduce the load on the API

A significant portion of the expense of a sports API consists of repetitive requests for rarely changing data: team lineups, tournament, season, and player directories. This data is ideal for caching and local storage in a database. The more you offload to your own cache, the fewer requests need to be made to the external API when working with 50+ matches simultaneously.

In the api-sport.ru ecosystem, there are several types of data with different dynamics:

  • static/rarely changing: sports types (/v2/sport), categories and tournaments (/v2/{sportSlug}/categories, /v2/{sportSlug}/categories/{categoryId}), tournament seasons, basic information about teams and players (/v2/{sportSlug}/teams, /v2/{sportSlug}/players);
  • moderately dynamic: match schedules, statuses «not started / completed»;
  • highly dynamic: live events, score, current minute, bookmaker odds oddsBase.

Optimal strategy: store static and moderately dynamic data in a local database (PostgreSQL, MySQL, MongoDB, etc.) or in an in-memory cache (Redis, Memcached, built-in language structures), and only access the external API to update the live part. Below is an example of a simple in-memory cache for matches with minimal expiration logic:

const cache = new Map();
const TTL_MS = 10_000; // кэшируем матч на 10 секунд
function setToCache(key, value) {
  cache.set(key, { value, expiresAt: Date.now() + TTL_MS });
}
function getFromCache(key) {
  const item = cache.get(key);
  if (!item || item.expiresAt < Date.now()) {
    cache.delete(key);
    return null;
  }
  return item.value;
}
async function getMatchesWithCache(url) {
  const cached = getFromCache(url);
  if (cached) return cached;
  const response = await fetch(url, { headers: { Authorization: 'YOUR_API_KEY' } });
  const data = await response.json();
  setToCache(url, data);
  return data;
}

By combining such a cache with a local database, you can, for example, update the directories of tournaments and teams once a day through /v2/{sportSlug}/categories и /v2/{sportSlug}/teams, while polling only in real-time for /v2/{sportSlug}/matches current matches. As a result, the number of requests to the external API decreases, the interface works faster, and internal services receive data from a local, predictable source.

Setting up triggers and events in the sports API instead of constant polling of matches

Even without built-in webhooks, you can significantly reduce API consumption through well-configured triggers on your backend. The idea is simple: you do not react to every API response, but only track changes in important fields — scores, statuses, live events liveEvents and odds in oddsBase. This helps reduce the load on databases, task queues, and external integrations, and in the long run, simplifies the transition to WebSocket streaming.

Using the data provided by by the sports events API api-sport.ru, you can build your own event logic layer:

  • compare the new snapshot with the previous one at each update of the set of matches;
  • When changing the score, minutes, or status, create domain events: «Goal», «Match started», «Match finished»;
  • for changes in coefficients in oddsBase launch your own alerts and automated strategies;
  • record only events, not every technical API poll — this reduces the volume of internal operations.

Below is a simplified example of a goal detector based on an array of matches from /v2/{sportSlug}/matches:

let previousSnapshot = new Map();
function detectGoals(currentMatches) {
  const events = [];
  currentMatches.forEach(match => {
    const prev = previousSnapshot.get(match.id);
    const homeScore = match.homeScore?.current ?? 0;
    const awayScore = match.awayScore?.current ?? 0;
    if (prev) {
      if (homeScore > prev.homeScore || awayScore > prev.awayScore) {
        events.push({
          type: 'goal',
          matchId: match.id,
          homeScore,
          awayScore,
          minute: match.currentMatchMinute
        });
      }
    }
    previousSnapshot.set(match.id, { homeScore, awayScore });
  });
  return events;
}

In a production system, such events can be sent to a message queue, push notifications, alert systems, and analytics. As a result, your service reacts only to real changes in matches and bookmaker lines, not to every technical request to the API. When WebSocket and AI functions appear on the api-sport.ru platform, such an event-driven architecture will allow for easy migration of most logic from REST polls to push updates, further reducing request consumption and speeding up data delivery to users.