Skip to content
IlanAMG edited this page Sep 25, 2026 · 28 revisions

API

Statut : 🟡 Brouillon · Màj : 2026-09-24 · Tickets : —

Contrat du MVP. Préfixe /v1. Authentification par jeton Firebase quand indiqué. Les schémas Zod dans packages/shared font foi ; cette page en est le résumé lisible.

Conventions

  • Pagination par curseur : ?cursor=&limit= (max 50), réponse { items, nextCursor }.
  • Erreurs : { code, message, details? }, codes HTTP standards. Codes métier stables : validation_error, unauthorized, forbidden, not_found, conflict, rate_limited, coherence_blocked, premium_required (en 402, avec details.reason pour alimenter E-17 : premium_route ou create_limit, et details.limit pour la création ; D-023).
  • Dates ISO 8601 UTC ; coordonnées { lat, lng }.
  • Toutes les lectures publiques sont cachables (Cache-Control court, ETag).

Découverte (public)

Méthode Route Description
GET /routes/search Parcours dans une zone avec filtres. Query : bbox=w,s,e,n, audiences[], moods[], conditions[], durations[], budgets[], transports[], `sort=recommended
GET /users/:id/profile Profil public (D-023) : avatar, prénom, membre depuis, quartier, bio, certified et certification (critères avec valeur, seuil et état, pour la sheet d'explication), chiffres routesPublished, routesCompleted, ratingAvg (chacun null s'il n'existe pas), anecdotes dans l'ordre (questionKey, libellé, réponse), parcours à la une dans l'ordre (cards), parcours publiés (cards ; query `sort=recent
GET /routes/:id/ratings Avis visibles, paginés
GET /routes/search/count Même query, réponse { count } pour le compteur des filtres. breakdown=all_but_one ajoute without : le nombre de parcours obtenu en retirant chaque filtre actif pris isolément, groupe par groupe et jamais valeur par valeur, pour les suggestions du zéro résultat de E-03 (D-010)
GET /routes/:id Fiche complète (étapes, lieux, horaires du jour, computed, vérification, lieux signalés). ?token= pour un parcours privé. Parcours access = premium pour un appelant non abonné : étape 1 complète, étapes suivantes réduites à heure, catégorie, durée et trajet, sans lieu, coordonnées ni conseil, et pas de tracé (D-014). Parcours retiré : 410 avec la date du retrait
GET /routes/:id/timeline Query startsAt= : timeline recalculée et conflits
GET /geocode Query q=, proxy Mapbox Geocoding restreint FR, avec cache
GET /weather/today Query city=paris : `{ condition: 'rainy'
GET /config Taxonomies, libellés, seuils publics (dont ceux de la certification), questions d'anecdote actives (clé, libellé, ordre), version minimale de l'app

Compte (auth)

Méthode Route Description
GET /me Profil complet (bio, quartier, anecdotes, à la une), rôle, plan, préférences, canCreateRoute (faux pour un compte gratuit qui a déjà son parcours), certification (critères avec valeur, seuil et état). Plus de compteurs du mois (D-023)
PATCH /me Prénom ou pseudo, avatar, bio (150 caractères), quartier (facultatif), isPublic, préférences de notification, anecdotes (liste ordonnée [{ questionKey, answer }], 3 au plus, question unique, réponse de 150 caractères) et featuredRouteIds (3 au plus, parcours publiés de l'appelant), enregistrés en une transaction par « Enregistrer » de Modifier le profil ; 422 validation_error sinon
POST /webhooks/revenuecat Webhook signé : met à jour plan et plan_expires_at
DELETE /me Suppression de compte, sans paramètre (D-025) : parcours publiés anonymisés (auteur « Membre Widoo »), tout le reste supprimé
POST /me/devices Enregistrement du jeton push

Favoris et programmation (auth)

Méthode Route Description
GET /me/favorites
PUT / DELETE /me/favorites/:routeId Sans limite (D-023)
GET /me/planned Query status=
POST /me/planned { routeId, startsAt } → programmation avec timeline et checklist. 402 premium_required (parcours Premium pour un non-abonné) ; sans limite sinon (D-023)
POST /me/planned/:id/rating { rating, comment? } ; exige un Go terminé ; crée ou met à jour route_ratings
PATCH /me/planned/:id startsAt, checklist, status (in_progress, completed, cancelled), personalNote
POST /me/planned/:id/steps/:stepId/done Coche une étape (Go) ; corps facultatif { signal: { kind, reason?, comment? } } pour la vérification sur place
GET /me/planned/:id/maps-url URL Google Maps à pied jusqu'à une étape, construite côté serveur : une URL par étape, jamais pour tout le parcours (D-032)

Création (auth)

Méthode Route Description
GET /me/routes Mes parcours, tous statuts
POST /routes Crée un brouillon ; 402 premium_required (details.reason = create_limit) si un compte gratuit a déjà un parcours non supprimé (D-023)
PATCH /routes/:id Informations, ambiances, publics, conditions, transport
PUT /routes/:id/steps Remplace la liste ordonnée des étapes ; retourne le résultat d'orchestration (computed, warnings, errors)
POST /routes/:id/submit Passe en pending ; 422 coherence_blocked si règles bloquantes
POST /routes/:id/status private, draft, unpublished par l'auteur
POST /media/upload-url { ownerType, ownerId, contentType } → URL signée et mediaId
DELETE /media/:id

Lieux (auth)

Méthode Route Description
GET /places/search Query q=, near=, category= : lieux Widoo existants
POST /places Création ; répond 409 avec le candidat si un lieu proche de même nom existe, sauf force=true
PATCH /places/:id Auteur du lieu tant qu'il n'est utilisé que par ses parcours ; sinon modérateur
POST /places/:id/signals `{ kind: 'confirm'

Admin (rôle moderator ou admin)

Méthode Route Description
GET /admin/moderation File pending et changes_requested
POST /admin/routes/:id/publish
POST /admin/routes/:id/request-changes { message }
POST /admin/routes/:id/reject { reasonCode, message }
POST /admin/routes/:id/unpublish
GET /admin/signals Groupés par lieu
POST /admin/places/:id/verify Remet verified, purge les signaux ouverts
POST /admin/places/:id/close Passe closed, parcours concernés en needs_fix
POST /admin/signals/:id/reject
POST /admin/ratings/:id/hide Masque un commentaire
POST /admin/users/:id/certification `{ override: 'none'
POST /internal/certification Recalcul nocturne du badge Créateur certifié selon les seuils de settings
POST /internal/recommendation Recalcul nocturne des composantes stockées du score
GET /admin/stats Compteurs du tableau de bord
POST /admin/places/import CSV, rôle admin

Interne (jeton de service, Cloud Scheduler)

Méthode Route Description
POST /internal/recompute Recalcul des parcours dont un lieu a changé
POST /internal/reminders Rappels J-1 et H-1 des parcours programmés
POST /internal/verification-decay Passage verified → stale après 90 jours

Clone this wiki locally