Official Python SDK for the Foresportia API
Project description
Foresportia Python SDK
Official Python SDK for the Foresportia API, a football analytics API that provides match data, model probabilities, predicted picks, confidence signals, and Core Analytics payloads for building or enriching football prediction models.
The SDK targets server-side Python (3.9+) with a synchronous, typed client.
Installation
pip install foresportia
Optional extras:
pip install "foresportia[ml]" # numpy + scikit-learn for the ML example
pip install -e ".[dev]" # local development from a clone
Authentication and key safety
Authentication uses the X-API-Key header only. The SDK never puts the key in
a URL, and the key never appears in repr(), logs, or exception messages.
Store the key in an environment variable rather than in source code:
export FORES_API_KEY="fs_beta_your_key_here"
$env:FORES_API_KEY = "fs_beta_your_key_here"
from foresportia import ForesportiaClient
client = ForesportiaClient.from_env() # reads FORES_API_KEY
# or explicitly:
client = ForesportiaClient(api_key="...", timeout=10.0)
The base URL must be HTTPS. Plain HTTP is only accepted for localhost or
with allow_insecure_base_url=True (development/testing only).
Do not commit API keys to source control, notebooks, screenshots, or support tickets.
Quickstart
from foresportia import ForesportiaClient
with ForesportiaClient.from_env() as client:
leagues = client.list_leagues()
for league in leagues.data:
print(league.code, league.name, league.matches_available)
matches = client.list_league_matches(
"PREMIER_LEAGUE",
include="upcoming",
start="2026-07-15",
days=7,
)
for match in matches.data:
print(match.kickoff, match.home_team, "vs", match.away_team, match.pick)
Every typed method returns an ApiResponse with:
response.data # typed result (list[League], list[MatchSummary], MatchDetail, BulkResult)
response.payload # full JSON payload as a dict
response.etag # ETag header for conditional requests
response.quota # parsed rate-limit / quota headers
response.status_code # HTTP status
response.not_modified # True for 304 responses
Available competitions
leagues = client.list_leagues()
for league in leagues.data:
print(league.code, league.name, league.country, league.activity_status)
Your API key only sees the competitions enabled for it. Use the codes exactly
as returned (for example in list_league_matches).
Match detail
Match IDs from list endpoints look like fsm:v1:<64 hex characters>. Pass
them exactly as returned:
match = client.get_match("fsm:v1:0123...abcdef")
detail = match.data
print(detail.home_team, "vs", detail.away_team)
print(detail.probabilities) # 1X2, over/under, BTTS, draw no bet, ...
print(detail.ratings) # ELO-style ratings
print(detail.raw) # complete Core Analytics payload
Bulk (Starter plan)
Fetch up to 100 matches in one call. IDs are validated client-side (1–100
unique fsm:v1:* IDs), order is preserved, and per-ID failures are reported
without hiding successful results:
bulk = client.get_matches_bulk([id_1, id_2, id_3])
for detail in bulk.data.results:
print(detail.id, detail.home_team, "vs", detail.away_team)
for error in bulk.data.errors:
print("failed:", error.match_id, error.code) # e.g. match_not_found
Today endpoints
today = client.list_today_matches()
picks = client.list_today_picks(limit=20)
Quotas and rate limits
The API reports quota state in response headers; the SDK parses them into
response.quota (fields are None when the header is absent):
response = client.list_leagues()
print(response.quota.remaining) # X-RateLimit-Remaining
print(response.quota.units_remaining_hour) # X-Quota-Units-Remaining-Hour
print(response.quota.units_remaining_day) # X-Quota-Units-Remaining-Day
print(response.quota.match_rows_remaining_day) # X-Match-Rows-Remaining-Day
Quota enforcement stays server-side. On HTTP 429 the SDK raises
ForesportiaRateLimitError (or ForesportiaConcurrencyLimitError) carrying
retry_after and the quota snapshot. Retrying after 429 is opt-in:
client = ForesportiaClient.from_env(retry_on_rate_limit=True, max_retries=2)
ETags and conditional requests
Pass a previous ETag to skip unchanged payloads. A 304 Not Modified is a
normal response, not an error:
first = client.get_match(match_id)
second = client.get_match(match_id, etag=first.etag)
if second.not_modified:
detail = first.data # reuse the cached payload
else:
detail = second.data
Error handling
from foresportia import (
ForesportiaAuthenticationError, # 401
ForesportiaAuthorizationError, # 403
ForesportiaNotFoundError, # 404
ForesportiaValidationError, # 400 / 422 / client-side validation
ForesportiaRateLimitError, # 429
ForesportiaConcurrencyLimitError, # 429 concurrency_limit_exceeded
ForesportiaServerError, # 5xx
ForesportiaTransportError, # network / timeout
ForesportiaAPIError, # base class for all of the above
)
try:
matches = client.list_today_matches()
except ForesportiaRateLimitError as exc:
print("rate limited, retry after", exc.retry_after, "seconds")
except ForesportiaAPIError as exc:
print(exc.status_code, exc.error_code, exc.endpoint)
Exceptions carry status_code, error_code (the API business code such as
match_not_found or bulk_limit_exceeded), endpoint, retry_after, and a
quota snapshot when available. The API key is never included.
Retries and timeouts
-
Explicit timeout per client (
timeout=10.0, default 20 s). -
Retries are disabled by default (
max_retries=0). A request that times out client-side may still have been processed and counted against your quota server-side, so each retry can consume an extra quota unit. Opt in explicitly when that trade-off is acceptable:client = ForesportiaClient.from_env(max_retries=2)
When enabled, only GET requests are retried, on network errors and 502/503/504, with bounded exponential backoff.
-
No automatic retry on 400/401/403/404, nor on 429 unless
retry_on_rate_limit=True. -
The bulk POST is never retried on 5xx.
-
Use the client as a context manager (
with ... as client:) or callclient.close().
Machine learning example
A runnable script is provided in
examples/ml_starter_features.py:
it fetches upcoming matches, extracts probabilities, markets, and confidence
into a feature matrix, and optionally fits a small scikit-learn model
(pip install "foresportia[ml]"). Foresportia outputs are model probabilities,
not guaranteed predictions; you need your own historical labels to train
anything meaningful.
rows = []
for match in client.list_league_matches("PREMIER_LEAGUE", days=14).data:
p = match.probabilities
rows.append([p.get("home"), p.get("draw"), p.get("away"),
match.markets.get("btts"), match.confidence.get("score")])
Legacy methods
The v0.1 dict-based methods keep working unchanged:
client.me()
client.usage()
client.picks_today()
client.matches_today()
client.leagues()
client.league_matches("FIN", include="all", days=14, limit=10)
client.world_cup_2026_matches(limit=10)
Prefer the typed list_* / get_* methods for new code.
Links
- API documentation: https://www.foresportia.com/api/docs/
- LLM-friendly API reference: https://www.foresportia.com/api/docs/llms-full.txt
- Homepage: https://www.foresportia.com
- Developer docs (EN): https://www.foresportia.com/en/developers.html
- API dashboard (EN): https://www.foresportia.com/en/api-dashboard.html
- Repository: https://github.com/QBarbedienne/foresportia-python
- Issues: https://github.com/QBarbedienne/foresportia-python/issues
Disclaimer
Foresportia provides football probabilities, model outputs, and analytics data. It does not provide betting advice, financial advice, bookmaker odds, guaranteed outcomes, or instructions to place wagers. Any use of Foresportia data is the responsibility of the user and should comply with applicable laws, regulations, and platform policies.
License
MIT. See LICENSE.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file foresportia-0.2.0.tar.gz.
File metadata
- Download URL: foresportia-0.2.0.tar.gz
- Upload date:
- Size: 30.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
050019cb415aedc3bd7f28f3738b2dd6df5dfdc1c5802688489abf0488d04dd1
|
|
| MD5 |
7171e56d520414f846968e08b2e1d62f
|
|
| BLAKE2b-256 |
a6f582bf44c75995df7e6ca5effb0a5b469a3a0b56a2eca066a7cd86fc67d021
|
Provenance
The following attestation bundles were made for foresportia-0.2.0.tar.gz:
Publisher:
publish.yml on QBarbedienne/foresportia-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
foresportia-0.2.0.tar.gz -
Subject digest:
050019cb415aedc3bd7f28f3738b2dd6df5dfdc1c5802688489abf0488d04dd1 - Sigstore transparency entry: 2168078840
- Sigstore integration time:
-
Permalink:
QBarbedienne/foresportia-python@b81066e1c197229920f019af6178110f64a7ff93 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/QBarbedienne
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b81066e1c197229920f019af6178110f64a7ff93 -
Trigger Event:
push
-
Statement type:
File details
Details for the file foresportia-0.2.0-py3-none-any.whl.
File metadata
- Download URL: foresportia-0.2.0-py3-none-any.whl
- Upload date:
- Size: 15.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
47308b2cdc49120e0bab1108ca669b34b3538f0b6e1ca412f623f25da4186ddb
|
|
| MD5 |
892f542ec2317261344836474da7d83d
|
|
| BLAKE2b-256 |
d618552e1d3586b000fafd2a92e0fcd0d9114360f2f308cabad8e3dd9bf15fc5
|
Provenance
The following attestation bundles were made for foresportia-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on QBarbedienne/foresportia-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
foresportia-0.2.0-py3-none-any.whl -
Subject digest:
47308b2cdc49120e0bab1108ca669b34b3538f0b6e1ca412f623f25da4186ddb - Sigstore transparency entry: 2168078877
- Sigstore integration time:
-
Permalink:
QBarbedienne/foresportia-python@b81066e1c197229920f019af6178110f64a7ff93 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/QBarbedienne
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b81066e1c197229920f019af6178110f64a7ff93 -
Trigger Event:
push
-
Statement type: