The API is live on the free tier — create a key in the dashboard. Interactive reference: api.polx.io/docs. Datasets marked planned on the Datasets page (odds movement, models, streaming) are not yet callable.

Quick start

Create a key in the dashboard, then make your first request. Every dataset lives under one base URL.

curl https://api.polx.io/v1/live?min_minute=20 \
  -H "X-API-Key: polx_..."
{
  "data": [
    { "match_id": 190412345, "minute": 56, "score": {"home": 2, "away": 1},
      "stats": { "dangerous_attacks": {"home": 17, "away": 24} },
      "derived": { "tempo_per_min": 0.73 } }
  ],
  "next_cursor": "eyJtIjoxOTA0MTIzNDV9"
}

Authentication

Send your key in the X-API-Key header. Keys are scoped to your account and plan; rotate them from the dashboard at any time. Requests without a valid key return 401; requests past your plan's limit return 429 with a Retry-After header. Every response carries x-ratelimit-remaining (per minute) and x-quota-remaining (credits this month). The free tier is 300 credits a month at 30 requests a minute, limited to the first 50 accounts; signal endpoints cost 2 credits, everything else 1.

Conventions

  • JSON everywhere, snake_case field names, times in UTC ISO-8601.
  • List endpoints return { data, next_cursor }; pass cursor to continue and limit (max 200) to size pages.
  • Ids are canonical: match_id, team_id, league_id are stable across every dataset.
  • Odds inside snapshots are returned as the price plus implied probabilities.

Endpoints

GroupEndpointParameters
LiveGET /liveleague, min_minute, max_minute, limit
GET /matches/{id}/live
MatchesGET /matches/{id}
GET /matches/{id}/timelinefrom_minute, to_minute
GET /matches/{id}/stats
GET /resultsdate (YYYY-MM-DD), league, limit
GET /fixturesdate, league, limit
Form & H2HGET /teams/{id}/formn
GET /h2hhome, away
Signals (premium, 2 credits)GET /signalsmarket, outcome, algorithm, environment, minute_gte, minute_lte, odds_gte, odds_lte, since, match_id, expand=state, limit, cursor
GET /signals/{id}
GET /signals/feedsince, environment, limit
GET /signals/markets
ScreenerPOST /screener/matchesJSON body of filters, scope=live|historical
ReferenceGET /leagues · GET /teams · GET /search · GET /coverageq, country
Account (Clerk session)GET /me · GET/POST /keys · DELETE /keys/{id}

Screener grammar

The screener takes a flat filter object; every key is field_op where op is one of eq, gte, lte, in.

POST /v1/screener/matches
{
  "scope": "live",
  "minute_lte": 20,
  "goals_gte": 2,
  "tempo_gte": 1.2,
  "league_in": [173, 244]
}

Filters: minute_gte, minute_lte, goals_gte, goals_lte, goal_diff_eq, goal_diff_abs_lte, tempo_gte, tempo_lte, shots_on_target_gte, corners_gte, red_cards_gte, possession_home_gte, ft_over_implied_gte, ft_goal_line_eq, league_in, date_from, date_to, limit.

MCP server

polx speaks MCP natively. The remote endpoint at https://api.polx.io/mcp (Streamable HTTP) needs nothing installed — authenticate with your API key and every tool call is metered like a REST call. In Claude Code:

claude mcp add --transport http polx https://api.polx.io/mcp \
  --header "X-API-Key: polx_..."

For Claude Desktop or any client that prefers a local process, the polx-mcp package runs the same tools over stdio:

{
  "mcpServers": {
    "polx": {
      "command": "npx",
      "args": ["-y", "polx-mcp"],
      "env": { "POLX_API_KEY": "polx_..." }
    }
  }
}

Tools: search_football, get_live_matches, get_match, get_match_timeline, get_match_stats, get_results, get_fixtures, get_team_form, get_head_to_head, screen_matches, get_signals, get_signal_markets, get_coverage. A good first prompt for an agent: "Which matches are in play right now with 2+ goals before the 25th minute and a tempo above 1.2?"

SDKs & OpenAPI

The OpenAPI spec is live at https://api.polx.io/openapi.json — generate a client with any OpenAPI tool today; published SDKs follow. An agent-readable copy of this reference lives at https://polx.io/llms.txt.

pip install polx          # Python
npm install @polx/sdk     # TypeScript