BentoSDK

Sportmonks sports data

Rate-limited Sportmonks proxies on the tournaments host — fixtures, squads, cricket, and motorsport without your own API token.

By the end: you can call Bento’s Sportmonks proxies safely (cached + rate-limited) instead of hitting Sportmonks directly.

These routes live on the tournaments host (PARLAY_TOURNAMENT_URL). They are not on createBentoSdk().tournaments today (proxy namespaces were trimmed from the public SDK surface). Use fetch (or any HTTP client) against the host origin.

Do not put a Sportmonks api_token in client code. The server injects it. If you send one, it is stripped.

Setup

export PARLAY_TOURNAMENT_URL='https://bento-fun-tournaments-backend-3nku.onrender.com'
export BENTO_BUILDER_API_KEY='bnt_…'   # same key as markets / createBentoSdk

Environments

const base = process.env.PARLAY_TOURNAMENT_URL!; // no trailing slash

Catalog / betting still use the markets host. Sports data uses this tournaments-host proxy.

Prefer the right TTL (this is the rate limit)

Every proxy call should pass a ttl profile. The backend uses stale-while-revalidate: fresh cache is served without upstream; stale can be served while refreshing; identical in-flight requests are single-flighted.

ttlFreshStale windowUse for
live30s5 minLive scores / livescores only (see clamp below)
ended60s24hFinished fixtures / final stats
news5 min1hNews-style payloads (v3 only)
logo24h7dStatic images / logos
default60s30 minSchedules, squads, standings

Server TTL clamp: ttl: 'live' is honored only on live-ish paths (livescores, fixtures/latest, inplay, paths containing /live/). On other paths the server forces default so clients can’t short-circuit the cache.

Client rules (so you don’t burn the shared Sportmonks quota):

  1. Always set ttl — don’t rely on default for live data.
  2. Poll no faster than the fresh window (e.g. live ≥ 30s).
  3. Reuse responses; check _meta.fromCache / _meta.isStale instead of re-requesting.
  4. Prefer the typed GET helpers below for common football needs (they’re already TTL-cached server-side).
  5. Use GET only on the v3 proxy (method: 'POST' is rejected).

Backend protections (automatic)

You don’t configure these — they protect the shared upstream and the public surface:

LayerLimit
Per-IP proxy POST60 req/min on /bento/sportmonks/proxy + cricket-v2
Per-IP football GET helpers120 req/min
Host-wide floor~300 req/min/IP
Per-cache-key concurrency8 (overflow → stale)
Global upstream gate~12 concurrent sports upstream calls
Circuit breaker5× HTTP 429 in 30s → path open 60s (stale only)
Path allowlistfootball/ | cricket/ | motorsport/ (+ cricket-v2 roots)

If you see 429 with Retry-After, back off. During a Sportmonks 429 storm, responses may stay stale on purpose.

Routes

1. Sportmonks v3 proxy (football / cricket path roots / motorsport)

POST ${PARLAY_TOURNAMENT_URL}/bento/sportmonks/proxy

const res = await fetch(`${base}/bento/sportmonks/proxy`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-builder-api-key': process.env.BENTO_BUILDER_API_KEY!,
  },
  body: JSON.stringify({
    method: 'GET', // default GET
    // Must start with football/ | cricket/ | motorsport/
    path: 'football/fixtures/date/2026-08-05',
    params: { include: 'participants' }, // api_token stripped if present
    ttl: 'default',
  }),
});

const body = (await res.json()) as {
  data: unknown; // upstream Sportmonks JSON (usually { data: ... })
  _meta?: { fromCache: boolean; isStale: boolean; fetchedAt: number; cacheKey: string };
};

// Most clients use body.data as if it came from Sportmonks directly
console.log(body.data, body._meta?.fromCache);
Body fieldNotes
pathRelative Sportmonks v3 path, e.g. football/leagues, motorsport/stages. Regex ^[\w\-/]+$.
paramsQuery params forwarded upstream (never send api_token).
ttllive | ended | logo | news | default (live clamped to live paths)
methodGET only (POST → 400)

2. Cricket v2 proxy (separate Sportmonks host)

POST ${PARLAY_TOURNAMENT_URL}/bento/sportmonks/cricket-v2/proxy

Cricket v2 is not on the v3 host. Same envelope + similar TTL / circuit-breaker behavior. Allowed path roots include fixtures, livescores, teams, seasons, squad, etc.

const res = await fetch(`${base}/bento/sportmonks/cricket-v2/proxy`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-builder-api-key': process.env.BENTO_BUILDER_API_KEY!,
  },
  body: JSON.stringify({
    path: 'livescores',
    params: {},
    ttl: 'live',
  }),
});
const { data, _meta } = await res.json();

3. Cached football helpers (prefer these when they fit)

MethodPath
Fixture snapshotGET /bento/sportmonks/football/fixture/:fixtureId/snapshot
Team squadGET /bento/sportmonks/football/team/:teamId/squad
Team season statsGET /bento/sportmonks/football/team/:teamId/season-stats
const builderHeaders = {
  'x-builder-api-key': process.env.BENTO_BUILDER_API_KEY!,
};

const snapshot = await fetch(
  `${base}/bento/sportmonks/football/fixture/${fixtureId}/snapshot`,
  { headers: builderHeaders },
).then((r) => r.json());

const squad = await fetch(
  `${base}/bento/sportmonks/football/team/${teamId}/squad`,
  { headers: builderHeaders },
).then((r) => r.json());

These are server-cached aggregations — better than inventing equivalent v3 proxy paths for the same data.

Auth

Builder API key required — send the same x-builder-api-key you use on the markets host (BENTO_BUILDER_API_KEY / createBentoSdk({ apiKey })). Mint a key once on markets — tournaments validates against the same BuilderApp store (no separate registration).

No user JWT required for these Sportmonks proxy reads (the server holds the Sportmonks token). Use the tournaments host URL from Environments.

LayerHeaderPurpose
Builder (app)x-builder-api-keyWhich app is calling
User (optional)Authorization: Bearer …Not needed for sports data reads

Do not confuse this with markets sdk.user (Builder key + Bearer JWT for bets).

What not to do

Don’tDo instead
Call api.sportmonks.com with your own key from the appCall Bento’s proxy
Poll live every 1–5sttl: 'live' and poll ≥ 30s
Omit ttl on hot pathsSet live / ended / default explicitly
Forward arbitrary pathsStick to allowlisted roots
Omit x-builder-api-keySend BENTO_BUILDER_API_KEY on every sports proxy call
Treat proxy as a betting APIBetting stays on markets host / tournament chips
  • EnvironmentsPARLAY_TOURNAMENT_URL
  • Cookbook — method shortlist (markets + tournaments)
  • OpenAPI specstournaments.json includes these paths
  • Other sports proxies on the same host (NFL/MLB/NBA/OpenF1/Odds) follow the same “cache + gate” idea; Sportmonks is the primary documented surface for soccer/cricket/motorsport data

On this page