Liste de conventions furry dans le monde entier — scrapées sur furryguides.com, furrycons.com, consurf.net et highwaytotail.com, dédupliquées puis normalisées dans un seul format.
Les routes de lecture (/api/conventions, /api/calendar, /api/status) sont publiques, en lecture seule, et accessibles en CORS depuis les domaines autorisés. Les routes de gestion (création, édition, suppression, résolution de conflits) sont réservées au staff : elles exigent à la fois un token Cognito valide (groupe gestionconvsfur) et un header Origin correspondant exactement au dashboard de gestion — un token seul ne suffit jamais.
Spécification complète, testable en direct :
/docs(Swagger UI) ou/api/openapi.json(OpenAPI 3.0 brut).
Toute réutilisation publique de ces données (site, bot, application, export) doit créditer visiblement la source avec un lien vers electrothewolf.fr. Voir les conditions d'utilisation pour le détail.
GET /api/conventionsListe des conventions au format JSON, filtrable et paginable.
| Paramètre | Type | Description |
|---|---|---|
continent |
string | Filtre par continent (Europe, North America, South America, Asia, Oceania, Africa) |
country |
string | Filtre par pays (nom complet ou code, insensible à la casse) |
year |
string | Filtre par année de début, ex 2026 |
future |
0 | 1 |
Par défaut 1 — ne retourne que les événements à venir |
q |
string | Recherche floue sur le nom, la ville ou le pays |
limit |
integer | Nombre maximum de résultats |
offset |
integer | Décalage de pagination |
Réponse 200
{
"meta": { "total": 120, "filtered": 42, "offset": 0, "updatedAt": "2026-08-09T03:00:00.000Z" },
"conventions": [ /* Convention[] */ ]
}
GET /api/conventions/{id}Une seule convention à partir de son identifiant stable (slug du nom + date de début, ex furrydelphia-2026-08-06). 404 si non trouvée.
GET /api/calendarExport .ics téléchargeable, filtrable comme /api/conventions (sans pagination — continent, country, year, future).
GET /api/statusMétadonnées : date de dernière mise à jour, nombre total de conventions, valeurs distinctes de continent/pays/année, et la liste complète des conventions.
Convention| Champ | Type | Description |
|---|---|---|
id |
string | Identifiant stable, généré côté API |
name |
string | |
startDate / endDate |
string (date) | |
location |
string | Libellé complet du lieu |
city / country / continent |
string | |
url |
string (uri) | Site officiel |
description |
string | |
source |
string | Origine du scraping ou manual |
address |
string | null | |
attendance |
string | null | Ex "6.7k" |
website |
string | null (uri) | |
price |
string | null | Ex "$120" ou "€90 – €150" (best-effort) |
registrationUrl |
string | null (uri) | Lien d'inscription/billetterie détecté (best-effort) |
registrationStatus |
unknown | open | closed | announced | null |
Best-effort, non garanti |
registrationOpenDate |
string (date) | null | Best-effort |
registrationCheckedAt |
string (date-time) | null | Dernière tentative d'enrichissement |
logoUrl |
string | null (uri) | og:image best-effort |
manualFields |
string[] | null | Champs corrigés à la main par le staff, jamais réécrasés par un scrape |
Toutes les routes ci-dessous exigent security: staffAuth — un Authorization: Bearer <id_token> Cognito du groupe gestionconvsfur, et un Origin égal au dashboard de gestion.
POST /api/conventionsCrée une convention manuellement. Enregistrée avec source: "manual", jamais écrasée par un scrape ultérieur. 409 si une convention avec le même nom + date de début existe déjà.
Champs requis : name, startDate, endDate, city, country, url, description.
PUT /api/conventions/{id}Patch partiel — seuls les champs présents dans le corps sont modifiés. Un champ modifié parmi name/startDate/endDate/city/country/continent/url/description/address/price/registrationOpenDate est marqué dans manualFields et ne sera plus jamais écrasé par un futur scrape. Modifier name ou startDate recalcule l'id. Toute résolution de conflit en attente sur un champ modifié ici est automatiquement purgée.
DELETE /api/conventions/{id}Supprime la convention et purge les conflits en attente qui lui sont liés.
GET /api/conflictsListe les conflits en attente d'arbitrage staff.
Un conflit apparaît quand un scrape trouve, pour startDate, endDate ou price, une valeur différente de celle déjà stockée — au lieu d'écraser silencieusement, l'ancienne et la nouvelle valeur sont mises en attente d'arbitrage.
POST /api/conflictsRésout un conflit :
action |
Effet |
|---|---|
accept |
Applique la valeur proposée par la source |
reject |
Garde la valeur actuelle |
override |
Applique une valeur saisie à la main (value requis) |
Corps : { "conventionId": string, "field": "startDate" | "endDate" | "price", "action": "accept" | "reject" | "override", "value"?: string }
GET /api/scrape (alias POST)Relance le scraping de toutes les sources et met à jour le stockage. Tourne automatiquement toutes les 24h via cron Vercel (non soumis au cooldown) ; les appels manuels sont limités à une fois toutes les 3h sauf ?force=true.
GET /api/enrich (alias POST)Visite le site officiel des conventions à venir pour en extraire inscription/billetterie/logo (best-effort). Cooldown de 7 jours par convention sauf ?force=true ou ?id=<id> pour cibler une seule convention.
Toutes les erreurs suivent le même format :
{ "ok": false, "error": "message" }
| Code | Signification |
|---|---|
400 |
Champs requis manquants |
401 |
Token manquant ou invalide |
403 |
Origine non autorisée ou compte hors groupe staff |
404 |
Ressource introuvable |
409 |
Conflit (doublon nom + date de début) |