Fortnite API with Python - Complete Tutorial
Learn how to use the Fortnite API with Python. Covers account resolution, stats, shop, cosmetics, and building a simple CLI tool.
pythontutorialplayer-stats
Python + Fortnite API
Python is a natural fit for the Fortnite API — whether you're building a Discord bot with discord.py, a data pipeline, or a quick CLI tool.
Installation
pip install requests httpx python-dotenvCreate a .env file:
FORTNITE_API_KEY=your_key_hereBase Setup
import os
import requests
from dotenv import load_dotenv
load_dotenv()
BASE_URL = "https://prod.api-fortnite.com"
HEADERS = {"x-api-key": os.getenv("FORTNITE_API_KEY")}Resolving a Display Name to Account ID
Stats use Epic account IDs, not display names. Always resolve first:
def get_account_by_display_name(display_name: str) -> dict:
"""Resolve a display name to an Epic account."""
url = f"{BASE_URL}/api/v1/account/displayName/{requests.utils.quote(display_name)}"
response = requests.get(url, headers=HEADERS)
response.raise_for_status()
return response.json() # contains 'id', 'displayName'
def get_player_stats(account_id: str, stat_keys: str = None) -> dict:
"""Fetch stats for an Epic account ID."""
params = {}
if stat_keys:
params["stats"] = stat_keys
url = f"{BASE_URL}/api/v2/stats/{account_id}"
response = requests.get(url, headers=HEADERS, params=params)
response.raise_for_status()
return response.json()Item Shop
def get_item_shop(lang: str = "en", rarity: str = None) -> dict:
params = {"lang": lang}
if rarity:
params["rarity"] = rarity
response = requests.get(f"{BASE_URL}/api/v1/shop", headers=HEADERS, params=params)
response.raise_for_status()
return response.json()Cosmetics Search
def search_cosmetics(query: str, cosmetic_type: str = None, lang: str = "en") -> dict:
params = {"q": query, "lang": lang}
if cosmetic_type:
params["type"] = cosmetic_type
response = requests.get(
f"{BASE_URL}/api/v2/cosmetics/search", headers=HEADERS, params=params
)
response.raise_for_status()
return response.json()Weapon Stats
def get_weapons(category: str = None, gamemode: str = None, patch: str = None) -> dict:
params = {}
if category:
params["category"] = category
if gamemode:
params["gamemode"] = gamemode
if patch:
params["patch"] = patch
response = requests.get(f"{BASE_URL}/api/v2/weapons", headers=HEADERS, params=params)
response.raise_for_status()
return response.json()CLI Stats Tool
import sys
def main():
if len(sys.argv) < 2:
print("Usage: python stats.py <display_name>")
sys.exit(1)
display_name = sys.argv[1]
try:
account = get_account_by_display_name(display_name)
print(f"Account ID: {account['id']}")
stats = get_player_stats(account["id"])
print(f"Stats: {stats}")
except requests.HTTPError as e:
if e.response.status_code == 404:
print(f"Player '{display_name}' not found.")
else:
print(f"Error: {e.response.status_code}")
if __name__ == "__main__":
main()Run it:
python stats.py NinjaAsync Version with httpx
import httpx
import asyncio
async def get_stats_async(display_name: str) -> dict:
async with httpx.AsyncClient(headers=HEADERS) as client:
# Resolve account ID
account_res = await client.get(
f"{BASE_URL}/api/v1/account/displayName/{display_name}"
)
account_res.raise_for_status()
account_id = account_res.json()["id"]
# Fetch stats
stats_res = await client.get(f"{BASE_URL}/api/v2/stats/{account_id}")
stats_res.raise_for_status()
return stats_res.json()
result = asyncio.run(get_stats_async("Ninja"))