🏓 API AFTT

API REST pour les données du tennis de table belge

📖 Lexique des Codes

🗺️ Codes Provinces

HHainaut
LiLiège
NNamur
LuLuxembourg
WBrabant Wallon
AAntwerpen
EOost-Vlaanderen
OWest-Vlaanderen
LLimburg
VVlaams-Brabant
KBrussels

🏓 Classements

Du plus bas au plus haut :

NC E6 E4 E2 E0 D6 D4 D2 D0 C6 C4 C2 C0 B6 B4 B2 B0 A

👤 Catégories d'âge

PREPré-minimes (-9 ans)
MINMinimes (9-10 ans)
CADCadets (11-12 ans)
JUNJuniors (13-14 ans)
SENSeniors (21-39 ans)
V40Vétérans 40+
V50Vétérans 50+
V60Vétérans 60+

✅ Résultats

VVictoire
DDéfaite
WOWalk-over (forfait)

🚀 Endpoints

🏥 Health & Stats

GET /health Vérifier l'état de l'API
Exemple de requête :
GET /health
Réponse :
{ "status": "ok" }
GET /api/stats Statistiques de la base de données
Exemple de requête :
GET /api/stats
Réponse :
{
  "clubs": 823,
  "players": 45210,
  "matches": 156420,
  "players_with_matches": 12500
}

🏢 Clubs

GET /api/clubs Liste des clubs
Paramètres :
ParamTypeDescription
provincestringFiltrer par province (ex: Hainaut)
limitintNombre max de résultats
offsetintPagination
Exemples :
GET /api/clubs
GET /api/clubs?province=Hainaut
GET /api/clubs?limit=50&offset=0
Réponse :
{
  "count": 156,
  "clubs": [
    { "code": "H004", "name": "ETT MANAGE", "province": "Hainaut" },
    { "code": "H005", "name": "CTT GODARVILLE", "province": "Hainaut" }
  ]
}
GET /api/clubs/provinces Liste des provinces
GET /api/clubs/provinces
Réponse :
{
  "provinces": ["Antwerpen", "Brabant Wallon", "Hainaut", "Liège", "Limburg", ...]
}
GET /api/clubs/{code} Détail d'un club
GET /api/clubs/H004
Réponse :
{
  "code": "H004",
  "name": "ETT MANAGE",
  "province": "Hainaut",
  "address": "Rue de la Salle 12",
  "city": "Manage"
}
GET /api/clubs/{code}/players Joueurs d'un club
GET /api/clubs/H004/players
Réponse :
{
  "club": { "code": "H004", "name": "ETT MANAGE" },
  "count": 52,
  "players": [
    {
      "licence": "176506",
      "name": "DEBESSEL CHRISTOPHER",
      "ranking": "C2",
      "points_current": 1285,
      "category": "SEN"
    }
  ]
}
POST /api/clubs/{code}/scrape Scraper un club (rafraîchir les données)
POST /api/clubs/H004/scrape
Réponse :
{
  "success": true,
  "club_code": "H004",
  "total_players": 52,
  "players_scraped": 52,
  "message": "Scraping terminé: 52 joueurs, 52 fiches"
}

⚠️ Cette requête peut prendre 30-60 secondes

👤 Joueurs

GET /api/players Liste des joueurs avec filtres
Paramètres :
ParamTypeDescription
club_codestringFiltrer par club (ex: H004)
rankingstringFiltrer par classement (ex: B2)
min_pointsfloatPoints minimum
max_pointsfloatPoints maximum
searchstringRecherche par nom/licence
limitintMax résultats (1-1000)
Exemples :
GET /api/players?club_code=H004
GET /api/players?ranking=B2
GET /api/players?min_points=1000&max_points=1500
GET /api/players?search=DEBESSEL
GET /api/players/{licence} Fiche complète d'un joueur
GET /api/players/176506
Réponse :
{
  "licence": "176506",
  "name": "DEBESSEL CHRISTOPHER",
  "club_code": "H004",
  "ranking": "C2",
  "points_start": 1200,
  "points_current": 1285,
  "total_wins": 25,
  "total_losses": 12,
  "stats_masculine": [
    { "opponent_ranking": "C4", "wins": 8, "losses": 2 }
  ],
  "matches_masculine": [
    {
      "date": "2024-12-10",
      "opponent_name": "MARTIN PIERRE",
      "opponent_ranking": "C4",
      "result": "V",
      "score": "3-1"
    }
  ]
}
GET /api/players/{licence}/matches Matchs d'un joueur
Paramètres :
ParamDescription
fiche_type"masculine" ou "feminine"
opponentLicence de l'adversaire
GET /api/players/176506/matches
GET /api/players/176506/matches?fiche_type=masculine
GET /api/players/176506/matches?opponent=152478
GET /api/players/{licence1}/vs/{licence2} Confrontation entre deux joueurs
GET /api/players/176506/vs/152478
Réponse :
{
  "player1": { "licence": "176506", "name": "DEBESSEL CHRISTOPHER" },
  "player2": { "licence": "152478", "name": "MARTIN PIERRE" },
  "player1_wins": 5,
  "player2_wins": 2,
  "matches": [...]
}

🏆 Rankings

GET /api/rankings/top Classement des meilleurs joueurs
Paramètres :
ParamDescription
limitNombre de joueurs (1-500)
provinceFiltrer par province
club_codeFiltrer par club
rankingFiltrer par classement
GET /api/rankings/top?limit=100
GET /api/rankings/top?province=Hainaut&limit=50
GET /api/rankings/top?club_code=H004
GET /api/rankings/progressions Meilleures progressions de la saison
GET /api/rankings/progressions?limit=50

🏅 Interclubs

GET /api/interclubs/divisions Liste des divisions interclubs
Parametres :
ParamTypeDescription
categorystringFiltrer par categorie (ex: National, Prov. Hainaut)
genderstringFiltrer par genre (Hommes, Dames)
Exemples :
GET /api/interclubs/divisions
GET /api/interclubs/divisions?category=National
GET /api/interclubs/divisions?gender=Hommes
Reponse :
{
  "count": 400,
  "divisions": [
    {
      "division_index": 1,
      "division_name": "Division 1 - National - Hommes",
      "division_category": "National",
      "division_gender": "Hommes"
    }
  ]
}
GET /api/interclubs/rankings Classement d'une division pour une semaine
Parametres (obligatoires) :
ParamTypeDescription
division_indexintIndex de la division
weekintNumero de semaine (1-22)
Exemple :
GET /api/interclubs/rankings?division_index=5&week=10
Reponse :
{
  "division_index": 5,
  "week": 10,
  "count": 12,
  "rankings": [
    {
      "rank": 1,
      "team_name": "ETT Manage A",
      "played": 10,
      "wins": 8,
      "losses": 1,
      "draws": 1,
      "forfeits": 0,
      "points": 17
    }
  ]
}
GET /api/interclubs/team/{team_name}/history Progression d'une equipe semaine par semaine
Parametres :
ParamTypeDescription
division_indexintFiltrer par division (optionnel)
Exemple :
GET /api/interclubs/team/ETT%20Manage%20A/history
GET /api/interclubs/team/ETT%20Manage%20A/history?division_index=5
Reponse :
{
  "team_name": "ETT Manage A",
  "count": 22,
  "history": [
    { "week": 1, "rank": 3, "played": 1, "wins": 1, "losses": 0, "draws": 0, "points": 2 },
    { "week": 2, "rank": 2, "played": 2, "wins": 2, "losses": 0, "draws": 0, "points": 4 }
  ]
}
GET /api/interclubs/search Recherche d'equipes interclubs
Parametres :
ParamTypeDescription
qstringTerme de recherche (min 2 caracteres)
limitintMax resultats (1-200, defaut: 50)
GET /api/interclubs/search?q=Manage
GET /api/interclubs/search?q=CTT&limit=20
Reponse :
{
  "query": "Manage",
  "count": 3,
  "teams": [
    { "team_name": "ETT Manage A", "division_index": 5, "division_name": "Division 2A - Prov. Hainaut - Hommes" },
    { "team_name": "ETT Manage B", "division_index": 42, "division_name": "Division 3C - Prov. Hainaut - Hommes" }
  ]
}
GET /api/interclubs/stats Statistiques interclubs
GET /api/interclubs/stats
Reponse :
{
  "divisions_count": 400,
  "rankings_count": 52000,
  "teams_count": 3200,
  "min_week": 1,
  "max_week": 22
}
POST /api/scrape/interclubs Lancer le scraping des classements interclubs
Parametres (optionnels) :
ParamTypeDescription
weeksstringSemaines (ex: "1,2,3" ou "1-5"). Defaut: 1-22
divisionsstringIndices de divisions (ex: "1,5,10"). Defaut: toutes
resume_divisionintReprendre depuis cette division
resume_weekintReprendre depuis cette semaine
Exemples :
# Scrape complet (~8800 pages, 1.5-3h)
POST /api/scrape/interclubs

# Test rapide (1 division, semaine 1)
POST /api/scrape/interclubs?weeks=1&divisions=5

# Scrape semaines 1-5 pour toutes les divisions
POST /api/scrape/interclubs?weeks=1-5

# Reprendre apres interruption
POST /api/scrape/interclubs?resume_division=42&resume_week=3
Reponse :
{
  "status": "started",
  "task_id": "interclubs_20260210_030000",
  "weeks": [1, 2, 3, ...],
  "divisions": "all",
  "message": "Scraping interclubs demarre en arriere-plan"
}

⚠️ Le scrape complet prend 1.5 a 3 heures (~8800 pages)

GET /api/scrape/interclubs/status Statut du scraping interclubs en cours
GET /api/scrape/interclubs/status
Reponse :
{
  "running": true,
  "task_id": "interclubs_20260210_030000",
  "status": "running",
  "elapsed_seconds": 1234.5,
  "total_rankings": 15000,
  "errors_count": 2,
  "last_success": { "division_index": 42, "week": 5 }
}
GET /api/scrape/interclubs/logs/{task_id} Logs temps reel du scraping interclubs
GET /api/scrape/interclubs/logs/interclubs_20260210_030000
POST /api/scrape/interclubs/cancel Annuler le scraping interclubs en cours
POST /api/scrape/interclubs/cancel
Reponse :
{
  "status": "cancelled",
  "task_id": "interclubs_20260210_030000",
  "message": "Scraping interclubs annule"
}

🔍 Recherche

GET /api/search Recherche de joueurs
Paramètres :
ParamDescription
qTerme de recherche (min 2 caractères)
limitMax résultats (1-200)
GET /api/search?q=DEBESSEL
GET /api/search?q=176506
GET /api/search?q=DEB&limit=20
Réponse :
{
  "query": "DEBESSEL",
  "count": 2,
  "players": [
    { "licence": "176506", "name": "DEBESSEL CHRISTOPHER", "ranking": "C2" }
  ]
}

💻 Exemples de Code

JavaScript (Fetch)

const API = window.location.origin;

// Stats
const stats = await fetch(`${API}/api/stats`).then(r => r.json());

// Clubs du Hainaut
const clubs = await fetch(`${API}/api/clubs?province=Hainaut`).then(r => r.json());

// Joueurs d'un club
const players = await fetch(`${API}/api/clubs/H004/players`).then(r => r.json());

// Recherche
const results = await fetch(`${API}/api/search?q=DEBESSEL`).then(r => r.json());

// Fiche joueur
const player = await fetch(`${API}/api/players/176506`).then(r => r.json());

Python

import requests

API = 'https://lkkkwcg88c04c4g8kgw884ko.chris-ia.com'

# Stats
stats = requests.get(f'{API}/api/stats').json()

# Clubs du Hainaut
clubs = requests.get(f'{API}/api/clubs', params={'province': 'Hainaut'}).json()

# Joueurs d'un club
players = requests.get(f'{API}/api/clubs/H004/players').json()

# Recherche
results = requests.get(f'{API}/api/search', params={'q': 'DEBESSEL'}).json()

cURL

# Stats
curl https://lkkkwcg88c04c4g8kgw884ko.chris-ia.com/api/stats

# Clubs du Hainaut
curl "https://lkkkwcg88c04c4g8kgw884ko.chris-ia.com/api/clubs?province=Hainaut"

# Scraper un club (POST)
curl -X POST https://lkkkwcg88c04c4g8kgw884ko.chris-ia.com/api/clubs/H004/scrape