How fresh are our prices?

SockOdds re-reads its source about every 2 minutes, stamps every bookmaker price with the time we last saw it (or, where the source gives a price no time of its own, the time of the record it arrived in), and marks a price we have not seen recently as unavailable rather than serving it as current. This page sets out exactly what the API does, and the fields you can check on every response so you never have to take our word for it.

Checked against the API's code on 6 October 2026. The thresholds the API is applying right now are published live at https://api.sockodds.com/health.

The numbers

WhatValueWhere you can see it
How often SockOdds pulls from its odds pipelineAbout every 2 minutes: each pass is scheduled 120 seconds after the previous oneinfo.lastUpdatedAt moves forward; freshness.newestSourceUpdatedAt on /health
How long a price from the live price table counts as current10 minutes after we last saw itexpiresAt on the price; freshness.quoteExpirySeconds on /health
When a price or an event is treated as stale45 minutes without an updateavailable and info.stale; freshness.staleAfterSeconds on /health
Shared read cache in front of the databaseAt most 30 seconds, and cleared on every write from the pipelineAvailability is worked out again on every request, after the cache
Native WebSocket stream (Pro and Platform)Re-reads the API every 30 secondsA snapshot when anything changed, a heartbeat when nothing did

What "~2 min update frequency" covers

The plan cards on pricing say ~2 min update frequency. That is how often SockOdds pulls from its odds pipeline: each pass is scheduled 120 seconds after the previous one, and a pass itself takes some seconds, so passes land a little over two minutes apart. Developer, Rookie, Pro and Platform keys all read the same store, so they see the same freshness; plans differ in leagues, bookmakers and volume, not in how current the prices are.

It is not how often each bookmaker is checked. That happens upstream of us, and the cadence varies by bookmaker and league. So a price can be older than two minutes when it reaches you, and lastUpdatedAt tells you by how much. This is a pre-match and in-play reference feed refreshed every couple of minutes, not a low latency trading feed.

The timestamps on every response

FieldWhereWhat it means
info.lastUpdatedAtEach eventWhen our odds pipeline last wrote this event's record.
info.staleEach eventtrue when info.lastUpdatedAt is more than 45 minutes old. The consensus fields bookOdds, bookSpread, bookOverUnder, fairOdds, fairSpread and fairOverUnder are then null and fairOddsAvailable is false.
lastUpdatedAtodds.<oddID>.byBookmaker.<bookmakerID>When we last observed this bookmaker's price.
expiresAtSame, on prices from our live price tablelastUpdatedAt plus 10 minutes. After it the price is served available: false.
snapshotUpdatedAtSame, only when a price has no time of its ownThe time of the event record the price arrived in. It is not a separate observation of the price.
availableSamefalse when the price has expired, is more than 45 minutes old, or is suspended. Decided at the moment of your request.
suspendedSame, when presenttrue when the bookmaker shows the price but is not taking bets on it. available is then false.
bookOddsAvailableEach oddtrue when at least one bookmaker price on it is available.
metadataUpdatedAt/players/ and /stats/ responsesWhen the reference catalogue behind those responses was generated.

Two prices as they arrive, one live and one suspended:

{
  "sportsbet": {
    "bookmakerID": "sportsbet",
    "odds": "-125",
    "decimal": 1.8,
    "available": true,
    "lastUpdatedAt": "2026-10-06T05:01:12.000Z",
    "expiresAt": "2026-10-06T05:11:12.000Z"
  },
  "tab": {
    "bookmakerID": "tab",
    "odds": "-118",
    "decimal": 1.85,
    "available": false,
    "suspended": true,
    "lastUpdatedAt": "2026-10-06T05:00:47.000Z",
    "expiresAt": "2026-10-06T05:10:47.000Z"
  }
}

When a bookmaker goes stale

  • Availability is decided on every request, from the clock at that moment. A price does not stay available: true because it was cached.
  • A price from the live price table is served available: false once expiresAt passes, 10 minutes after we last saw it. Any price is served available: false once it is more than 45 minutes old.
  • A suspended selection is listed with available: false and suspended: true, not hidden.
  • A stale price stays listed under byBookmaker, so you can see the last price and when it was seen. When the event's record is next rewritten, a price is carried forward only if the source still lists it, so a bookmaker that has gone quiet drops out of byBookmaker.
  • Events are never deleted. An event whose record has not been written for 45 minutes stays in the feed with info.stale: true.
  • oddsAvailable=true on /events/ returns only events with at least one available price.

Check freshness yourself

Skip stale events and unavailable prices, then apply your own age limit to lastUpdatedAt:

const res = await fetch("https://api.sockodds.com/v2/events/?leagueID=AFL&oddsAvailable=true", {
  headers: { "x-api-key": process.env.SOCKODDS_API_KEY },
});
const { data } = await res.json();
const now = Date.now();
for (const event of data) {
  if (event.info.stale) continue; // the event's record is over 45 minutes old
  for (const odd of Object.values(event.odds)) {
    for (const [bookmakerID, quote] of Object.entries(odd.byBookmaker)) {
      if (!quote.available) continue; // expired, stale or suspended
      const seen = Date.parse(quote.lastUpdatedAt ?? quote.snapshotUpdatedAt);
      const ageSeconds = Math.round((now - seen) / 1000);
      if (ageSeconds > 300) continue; // your own threshold: here, five minutes
      console.log(event.eventID, odd.oddID, bookmakerID, quote.odds, ageSeconds + "s old");
    }
  }
}

The thresholds the API is applying are on its health endpoint, which needs no key:

curl https://api.sockodds.com/health
{
  "status": "ok",
  "pipeline": "healthy",
  "freshness": {
    "newestSourceUpdatedAt": "2026-10-06T05:02:41.000Z",
    "staleAfterSeconds": 2700,
    "quoteExpirySeconds": 600
  }
}
pipeline is healthy while the newest event record is under 45 minutes old, stale after that, and empty before the first pull. Before you act on any price, check it on the bookmaker through links.bookmakers: prices move between our observations.
Need help?FAQ · Email · Contact

Search across the SockOdds documentation and catalogue.