← All field notes fantasy football api scoring python

Build a Fantasy Soccer Points Calculator in Python

A fantasy soccer score is an application rule applied to football observations. The same performance can produce different totals in different games. Start with a written scoring version, eligible fixtures, correction policy and missing-data behavior. This tutorial uses a deliberately small custom ruleset: four points per goal, three per assist and minus one per yellow card. It does not implement official Fantasy Premier League scoring or NFL fantasy football.

Write a scoring contract before a leaderboard

A fantasy soccer score is an application rule applied to football observations. The same performance can produce different totals in different games. Start with a written scoring version, eligible fixtures, correction policy and missing-data behavior. This tutorial uses a deliberately small custom ruleset: four points per goal, three per assist and minus one per yellow card. It does not implement official Fantasy Premier League scoring or NFL fantasy football.

This distinction matters when someone searches for a fantasy football API. Stats API provides association-football data, including per-match player statistics where covered. Your application decides points, transfers, captain multipliers, deadlines and league rules. An API response containing goals and assists is not an official fantasy score, even if the calculated number happens to match another game's total.

Select only inputs your rule actually needs

Read GET /football/matches/{match_id}/player-stats for a real match ID obtained from discovery. The response groups players under teams and includes a player object, minutes and a canonical statistics object. Check coverage.player_statistics_available and inspect the required fields for each player. Coverage describes support; it does not guarantee every individual statistic is populated for every match.

For this three-field rule, unknown goals, assists or yellow_cards make the total unknown. Replacing null with zero awards a plausible but unverified score. Conversely, a known zero is meaningful and should remain zero. The function below returns the names of missing inputs so the interface can explain why one player is pending without hiding the rest of the match.

Run the reproducible example

This Python 3 example uses deliberately synthetic inputs, not a downloaded match or a forecast for a real fixture. Save it as example.py and run python3 example.py. It uses only the standard library and its assertions check the behavior discussed here. Replace the fixture inputs with validated API records when connecting your application; demo identifiers are not production lookup values.

Complete offline example python
WEIGHTS = {"goals": 4, "assists": 3, "yellow_cards": -1}

def score(statistics):
    missing = [name for name in WEIGHTS if statistics.get(name) is None]
    if missing:
        return {"points": None, "missing": missing}
    if any(type(statistics[name]) is not int or statistics[name] < 0 for name in WEIGHTS):
        raise ValueError("counts must be nonnegative integers")
    return {"points":sum(statistics[k]*w for k,w in WEIGHTS.items()), "missing":[]}

fixture = {"goals":1,"assists":2,"yellow_cards":1}
assert score(fixture) == {"points":9,"missing":[]}
assert score({"goals":0,"assists":0,"yellow_cards":0})["points"] == 0
assert score({"goals":0,"assists":None,"yellow_cards":0}) == {"points":None,"missing":["assists"]}
print(score(fixture))

Read the result

The example prints nine points with no missing inputs. A player with an unknown assist count receives points=null and missing=[assists]. This is a projected statistics object, not a complete API response, and all numbers were created for the test.

Make corrections replayable

Use a unique local key consisting of match ID, player ID and ruleset version. Persist the input values or a reference to the retained response, plus your calculation timestamp. When source values change, replace the calculation for that key and rebuild the affected leaderboard. Appending another score event for the same performance would credit the player twice.

Keep captaincy and other user-specific adjustments in a separate layer. A match performance has one base score under a given rule; different fantasy teams can apply their own allowed multiplier. This separation makes a corrected assist easy to propagate without rewriting account-specific selections or confusing source statistics with game settings.

Test the rules at their boundaries

The worked fixture scores one goal, two assists and one yellow card as nine points. The second check proves that three known zero values yield a legitimate zero, while the third proves that an unknown assist prevents a final total. Add cases for every rule you introduce, especially minutes thresholds, negative totals and whether red and yellow card penalties can overlap.

Before publishing a real contest, test representative covered matches and define when scores become provisional or final. A finished match may still receive a correction. Stats API also offers GET /football/players/{player_id}/stats with a required season_id for observed season summaries, with separate rows for transfer teams. Those summaries are not your fantasy scoring rules: retain eligible per-match inputs and compute the particular fantasy total your application needs, keeping included and missing match counts visible.

Connect this to your project

Start by checking match coverage and inspecting player-statistics responses for your target competitions. Then implement one small scoring rule and retain its inputs before adding roster or transfer features. The product and contract pages help establish available operations; the existing test guide helps turn your rulebook into repeatable checks.

Read the match endpoint guide → Check the football API → Test your football integration →