Metadata-Version: 2.4
Name: fc-clubs-api
Version: 0.1.0
Summary: Unofficial Python client for the EA Sports FC 27 Pro Clubs API, returning pandas DataFrames.
Author: Erkan Dogan
License: MIT License
        
        Copyright (c) 2025 Erkan Dogan
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Homepage, https://github.com/1erkandogan/fc27-clubs-api
Project-URL: Issues, https://github.com/1erkandogan/fc27-clubs-api/issues
Keywords: ea,fc27,pro clubs,api,pandas
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE.md
Requires-Dist: pandas>=1.5
Dynamic: license-file

# FC 27 Clubs API

An unofficial Python client for the **EA Sports FC 27 Pro Clubs API**, the same
endpoints `proclubs.ea.com` calls from the browser. You can find clubs and get
their stats, members, matches and per-player match ratings as tables (pandas
DataFrames).

Not affiliated with or endorsed by EA. The endpoints are undocumented and can
change without notice.

- **New to Python, or want to know how it works?** Read [docs/how-it-works.md](docs/how-it-works.md).
  It walks through the code and explains every import and decision.
- **Want EA's raw responses?** See [docs/endpoints.md](docs/endpoints.md).

## Install

You need Python 3.9 or newer.

```bash
pip install fc-clubs-api   # also installs pandas, the only dependency
```

No API key needed. The whole client is one file, [`fc_clubs_api.py`](fc_clubs_api.py),
and you import it as `fc_clubs_api`.

To work on the code itself, install from a clone instead:

```bash
git clone https://github.com/1erkandogan/fc27-clubs-api.git
cd fc27-clubs-api
pip install -e .   # your edits to fc_clubs_api.py take effect without reinstalling
```

## Quick start

```python
from fc_clubs_api import FC27API

api = FC27API(timezone="Europe/Istanbul")      # match times in your timezone

club_id = api.find_club_id("Your Club Name")   # -> the id, e.g. 1001

print(api.get_club_matches(club_id))           # last 10 league matches
print(api.get_member_stats(club_id))           # squad stats this season
```

Or run the example: `python examples/quickstart.py "Your Club Name"`

## Methods

| Method | Gives you (one row per ...) |
|---|---|
| `find_club_id(name)` | the club's id as a number. If several clubs match, the error lists them. |
| `search_club_by_name(name)` | club matching the name: division, wins, goals, points |
| `get_club_details(club_id)` | club (1 row): name, ids, stadium |
| `get_club_overall_stats(club_id)` | club (1 row): record, goals, streaks, skill rating |
| `get_member_stats(club_id)` | member: games, goals, assists, average rating, pass/tackle rates |
| `get_member_career_stats(club_id)` | member: career totals at the club |
| `get_club_matches(club_id, match_type="leagueMatch", count=10)` | match, from your side: opponent, score, `result` (win/draw/loss), `dnf` |
| `get_match_players(club_id, match_type="leagueMatch", count=10, both_teams=False)` | player per match: rating, goals, assists, shots, passes, tackles |
| `get_playoff_achievements(club_id)` | achievement (EA has only returned an empty list so far) |
| `get_json(endpoint, params)` | EA's raw response as dicts/lists, e.g. `api.get_json("clubs/info", {"clubIds": 1001})` |

- `match_type` is `"leagueMatch"`, `"friendlyMatch"` or `"playoffMatch"`.
- By default, tables have a short set of readable columns. Add `all_columns=True` to
  `search_club_by_name`, `get_club_details`, `get_club_overall_stats`,
  `get_member_stats` or `get_match_players` to get every field EA sends, with EA's names.
- `FC27API(platform="common-gen5", timeout=10, timezone="UTC")`: all settings are optional.
- If there is no data, you get an empty table (`df.empty` is `True`).

## Recipes

```python
from fc_clubs_api import FC27API

api = FC27API(timezone="Europe/Istanbul")
club_id = api.find_club_id("Your Club Name")

# Top 5 scorers this season
members = api.get_member_stats(club_id)
print(members.sort_values("goals", ascending=False).head(5)[["name", "goals", "assists"]])

# Last 5 league results
matches = api.get_club_matches(club_id)
print(matches.head(5)[["timestamp", "opponentName", "goals", "goalsAgainst", "result"]])

# Win rate over the last 10 league matches
wins = (matches["result"] == "win").sum()
print(f"Won {wins} of {len(matches)}")

# One player's recent matches
players = api.get_match_players(club_id)
print(players[players["name"] == "YourGamertag"][["timestamp", "rating", "goals", "assists"]])

# Average match rating per player, best first
print(players.groupby("name")["rating"].mean().sort_values(ascending=False))

# Save any table to open in Excel
members.to_csv("members.csv", index=False)
# members.to_excel("members.xlsx", index=False)   # needs: pip install openpyxl
```

## Errors

- **`FC27APIError`**: EA couldn't be reached, refused the request, or didn't send JSON.
- **`ValueError`**: you passed something invalid, such as an unknown `match_type`, or a
  club name that `find_club_id` couldn't match to one club.

```python
from fc_clubs_api import FC27API, FC27APIError

try:
    df = FC27API().get_club_details(1001)
except FC27APIError as error:
    print("EA problem:", error)
```

## Good to know

- **EA blocks non-browser requests.** Every request sends browser-like headers
  (`HEADERS` in `fc_clubs_api.py`). Without them EA answers 403 or doesn't answer at all.
  Plain `curl` is blocked even with the headers, while Python works.
- **No caching or rate limiting.** Every call goes straight to EA. If you loop over
  many clubs, add a pause between requests (`time.sleep(1)`) so you don't get blocked.

## Tests

```bash
python -m unittest discover -s tests -v
```

The tests run offline, using EA responses saved in `tests/fixtures/`. They keep the real structure,
but every club and player name, id and date is a placeholder.

## Contributing

Bug reports are welcome, especially when EA changes something and the client
breaks. Please open an issue before writing code: the project is deliberately
small and some things that look like oversights are decisions. See
[CONTRIBUTING.md](CONTRIBUTING.md).

## License

MIT, see [LICENSE.md](LICENSE.md).
