The Fantasy Premier League API is a free, keyless JSON API at https://fantasy.premierleague.com/api/. Its main endpoints are bootstrap-static/ (all players, teams and gameweeks), fixtures/, element-summary/{player_id}/, event/{gw}/live/, entry/{manager_id}/ with /history/, /event/{gw}/picks/ and /transfers/, and leagues-classic/{league_id}/standings/. It has no official documentation and no CORS header.
The Premier League doesn't document this API, so this reference comes from live responses. I called every endpoint below on 2026-10-14, during the 2026/27 season, between gameweek 6 (finished) and gameweek 7 (deadline 2026-10-17 10:00 UTC). Each returned HTTP 200 unless marked otherwise.
The endpoints at a glance
| Endpoint | Returns | Status on 2026-10-14 |
|---|---|---|
bootstrap-static/ |
Every player, team and gameweek, plus game rules | 200, 1.7 MB |
fixtures/ |
All 380 fixtures of the season | 200 |
fixtures/?event={gw} |
One gameweek's fixtures | 200 (10 for GW6) |
fixtures/?future=1 |
Only fixtures not yet played | 200 (320) |
element-summary/{player_id}/ |
One player's remaining fixtures, this season's matches, past seasons | 200; unknown ID: 404 |
event/{gw}/live/ |
Every player's stats and points for a gameweek | 200; a future gameweek returns {"elements":[]}
|
event-status/ |
Whether bonus points are added and leagues updated | 200 |
dream-team/{gw}/ |
The best XI of a gameweek | 200 |
entry/{manager_id}/ |
A manager's profile, rank and leagues | 200; unknown ID: 404 |
entry/{manager_id}/history/ |
Points and rank per gameweek, past seasons, chips used | 200 |
entry/{manager_id}/event/{gw}/picks/ |
The 15 players picked in a gameweek, captain, chip, auto-subs | 200; a future gameweek: 404 |
entry/{manager_id}/transfers/ |
Every transfer this season | 200 |
leagues-classic/{league_id}/standings/ |
A classic league table, 50 per page | 200 |
team/set-piece-notes/ |
Set-piece notes per team | 200 |
regions/ |
Countries and regions for manager profiles | 200 (255) |
stats/most-valuable-teams/ |
The 10 highest team values | 200 |
my-team/{manager_id}/ |
Your own team before the deadline | 403 without login |
entry/{manager_id}/transfers-latest/ |
Your latest transfers | 403 without login |
The paths end with a slash. Two paths that older tutorials mention, set-piece-notes/ and bootstrap-dynamic/, returned 404 HTML pages. The base URL itself (/api/) also returns 404.
Check them yourself
import time
import requests
API = "https://fantasy.premierleague.com/api/"
s = requests.Session()
s.headers["User-Agent"] = "fpl-endpoint-check/1.0 (personal script)"
def get(path):
r = s.get(API + path, timeout=30)
return r.status_code, (r.json() if r.headers.get("content-type", "").startswith("application/json") else None)
_, boot = get("bootstrap-static/")
gw = next(e["id"] for e in boot["events"] if e["is_current"]) # latest started gameweek
player = max(boot["elements"], key=lambda p: p["total_points"])["id"] # any player id works
_, overall = get("leagues-classic/314/standings/") # 314 = the Overall league
manager = overall["standings"]["results"][0]["entry"] # any manager id works
paths = [
"bootstrap-static/",
"fixtures/",
f"fixtures/?event={gw}",
f"element-summary/{player}/",
f"event/{gw}/live/",
"event-status/",
f"dream-team/{gw}/",
f"entry/{manager}/",
f"entry/{manager}/history/",
f"entry/{manager}/event/{gw}/picks/",
f"entry/{manager}/transfers/",
"leagues-classic/314/standings/?page_standings=2",
"team/set-piece-notes/",
"regions/",
"stats/most-valuable-teams/",
"my-team/1/",
]
for p in paths:
status, body = get(p)
shape = list(body)[:4] if isinstance(body, dict) else f"list of {len(body)}" if isinstance(body, list) else "-"
print(f"{status} {p:<45} {shape}")
time.sleep(0.5)
Output on 2026-10-14:
200 bootstrap-static/ ['chips', 'events', 'game_settings', 'game_config']
200 fixtures/ list of 380
200 fixtures/?event=6 list of 10
200 element-summary/115/ ['fixtures', 'history', 'history_past']
200 event/6/live/ ['elements']
200 event-status/ ['status', 'leagues']
200 dream-team/6/ ['top_player', 'team']
200 entry/895045/ ['id', 'joined_time', 'started_event', 'favourite_team']
200 entry/895045/history/ ['current', 'past', 'chips']
200 entry/895045/event/6/picks/ ['active_chip', 'automatic_subs', 'entry_history', 'picks']
200 entry/895045/transfers/ list of 36
200 leagues-classic/314/standings/?page_standings=2 ['league', 'standings', 'last_updated_data', 'new_entries']
200 team/set-piece-notes/ ['last_updated', 'teams']
200 regions/ list of 255
200 stats/most-valuable-teams/ list of 10
403 my-team/1/ ['detail']
Key fields, endpoint by endpoint
bootstrap-static/
Top-level keys: events, game_settings, game_config, phases, teams, total_players, element_stats, element_types, elements, chips. On 2026-10-14 it held 667 players, 20 teams, 38 gameweeks and total_players: 11085989.
| Array | Key fields |
|---|---|
elements (players, 109 fields each) |
id, web_name, team, element_type (1 GKP, 2 DEF, 3 MID, 4 FWD), now_cost (tenths of £m), total_points, event_points, form, selected_by_percent, status, chance_of_playing_next_round, news, minutes, goals_scored, assists, expected_goals, expected_assists, defensive_contribution, ep_next, transfers_in_event, price_change_percent
|
teams |
id, name, short_name, strength_overall_home, strength_overall_away, played, win, draw, loss, points, position
|
events (gameweeks) |
id, name, deadline_time, is_previous, is_current, is_next, finished, data_checked, average_entry_score, highest_score, most_captained, top_element
|
element_types |
squad_select (2/5/5/3), squad_min_play, squad_max_play
|
game_settings |
squad_squadsize (15), squad_team_limit (3 per club), squad_total_spend (1000 = £100.0m), transfers_cap, max_extra_free_transfers
|
Several numbers arrive as strings: form, selected_by_percent, expected_goals, price_change_percent. Cast them before comparing. The response carried cache-control: max-age=300, so it changes at most every five minutes.
fixtures/
Each fixture: id, event (gameweek), kickoff_time, team_h, team_a, team_h_score, team_a_score, team_h_difficulty, team_a_difficulty, started, finished, minutes, stats. For a finished match, stats lists goals_scored, assists, own_goals, penalties_saved, penalties_missed, yellow_cards, red_cards, saves, bonus, bps and defensive_contribution, each split into h and a with {value, element} pairs. Difficulty is covered in FPL fixture difficulty from the API.
element-summary/{player_id}/
fixtures (remaining matches, with difficulty and is_home from that player's side), history (one row per match this season: round, opponent_team, minutes, total_points, bps, expected_goals, value, selected, transfers_balance, and more) and history_past (one row per earlier season: season_name, start_cost, end_cost, total_points, minutes).
event/{gw}/live/
elements is a list of every player with id, stats (the same counters as above plus total_points, in_dreamteam and played) and explain, which breaks the points down per fixture: {"identifier": "goals_scored", "points": 10, "value": 2}. Pair it with a manager's picks to compute their score; see FPL live gameweek points from the API.
entry/{manager_id}/ and its sub-paths
| Endpoint | Key fields |
|---|---|
entry/{id}/ |
id, name (team name), started_event, summary_overall_points, summary_overall_rank, summary_event_points, current_event, last_deadline_value, last_deadline_bank, leagues (classic, h2h, cup) |
entry/{id}/history/ |
current (per gameweek: points, total_points, overall_rank, bank, value, event_transfers, event_transfers_cost, points_on_bench), past (season_name, total_points, rank), chips (name, event, time) |
entry/{id}/event/{gw}/picks/ |
picks (15 rows: element, position, multiplier, is_captain, is_vice_captain), active_chip, automatic_subs, entry_history
|
entry/{id}/transfers/ |
element_in, element_in_cost, element_out, element_out_cost, event, time
|
How to find a manager ID, and a full history script: Find your FPL manager ID and pull your team history.
leagues-classic/{league_id}/standings/
league (id, name, ...), standings (page, has_next, results: entry, entry_name, player_name, rank, last_rank, total, event_total), new_entries and last_updated_data. Fifty rows per page; add ?page_standings=2 and keep going while has_next is true. League 314 is the Overall league.
Small endpoints
-
event-status/returned{"status": [{"bonus_added": true, "date": "2026-10-10", "event": 6, "points": "r"}, ...], "leagues": "Updated"}. Checkbonus_addedandleaguesbefore you treat a gameweek's numbers as final. -
dream-team/{gw}/returnstop_player(id,points) andteam(11 rows ofelement,points,position).
Errors
| Situation | Status | Body |
|---|---|---|
| Unknown manager | 404 | {"detail":"No Entry matches the given query."} |
| Unknown player | 404 | {"detail":"No Element matches the given query."} |
| Picks for a gameweek that hasn't started | 404 | {"detail":"Not found."} |
| Your own team without login | 403 | {"detail":"Authentication credentials were not provided."} |
me/ without login |
200 | {"player":null,"watched":[]} |
Rules of the road
-
No browser calls. The responses I checked (
bootstrap-static/,fixtures/,entry/{id}/) carried noAccess-Control-Allow-Originheader, so a web page can'tfetch()them. Use a server, a script or a scheduled job. -
No published rate limit. FPL documents none. Cache
bootstrap-static/(it's 1.7 MB and only changes every five minutes), pause between requests, and back off on errors. My scripts send a descriptiveUser-Agent; the API also answered without one. - The API only shows now. It doesn't keep yesterday's prices, ownership or price-change progress. Save snapshots if you need history; for past seasons, the community vaastav/Fantasy-Premier-League archive on GitHub is the usual source.
-
Prices are in tenths.
now_cost: 61is £6.1m, andsquad_total_spend: 1000is £100.0m.
Related guides for this API
- Find your FPL manager ID and pull your team history.
- FPL live gameweek points from the API.
- FPL fixture difficulty from the API.
- FPL API price change data in Python, for the official price-change fields.
Do it without code
The free FPL query builder lets you pick a mode (gameweek picks, mini-league intel, manager dashboard, price-change predictor and others), a gameweek and manager IDs, and gives you a ready-to-run input with a fixed example of the output. It's a query builder, not a live tool: because of the missing CORS header, it can't call the FPL API from your browser.
At scale
The FPL Intelligence actor on Apify calls these endpoints server-side and turns them into ready answers: captain, transfer and differential picks, a wildcard optimizer, mini-league intel, a manager dashboard, live gameweek tracking, a price-change predictor, and past seasons from the vaastav archive. It exports JSON, CSV or Excel and runs on a schedule. It's free to start, then pay-as-you-go.
Disclosure: I build the datatooly query builder and the Apify actor. Every endpoint above works without either.
Sources: live responses from fantasy.premierleague.com/api/ on 2026-10-14. FPL publishes no API documentation.
Top comments (0)