Skip to content

Référence API

Cette fiche donne une vue d'ensemble de l'API REST de TimePick, organisée par familles d'endpoints. Elle sert de point d'entrée pour un développeur ou un intégrateur qui doit appeler l'API depuis un script ou un outil externe — elle ne documente pas chaque endpoint en détail. Pour la liste exhaustive, chaque route est déclarée dans un fichier de server/src/routes/ sur GitHub.

API interne, sans garantie de stabilité

Cette API a été conçue pour l'interface web de TimePick elle-même, pas comme une API publique versionnée. Tant que le projet est en pré-V1 (état au 2026-07-13), ses chemins, ses formats de payload et ses codes d'erreur peuvent changer sans préavis ni période de dépréciation. Un usage en intégration externe reste possible mais doit être revalidé à chaque mise à jour de l'instance.

Base et authentification

URL de base : https://<votre-domaine.tld>/api (ou http://localhost:3000/api en développement).

La quasi-totalité des endpoints hors /setup, /public (lecture) et /health requièrent l'en-tête :

Authorization: Bearer <token>

Le <token> est un JWT de session, obtenu via le flux magic link :

  1. POST /api/auth/login avec { "email": "alice@example.org" } — envoie un email contenant un lien de connexion. La réponse est volontairement générique (anti-énumération), qu'un compte corresponde ou non à l'email :

    json
    {
      "data": {
        "message": "Si cet email est enregistré, vous recevrez un lien de connexion."
      }
    }
  2. Le lien reçu par email contient un token en paramètre. Le client appelle ensuite POST /api/auth/verify avec { "token": "<token>" }, qui ouvre la session et renvoie le JWT à utiliser dans l'en-tête Authorization pour tous les appels suivants.

Deux rôles distincts sont portés par le JWT : admin (accès à /api/admin/*) et user (accès à /api/me/* et aux réservations, si hasMemberAccess est vrai — c'est-à-dire si l'utilisateur est invité sur au moins un événement).

Détail des durées de vie de session/token, du rate limiting et des autres protections : voir Sécurité.

Enveloppe de réponse

Toutes les réponses de succès sont enveloppées dans un objet data. Exemple réel, réponse de POST /api/auth/verify :

json
{
  "data": {
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…",
    "sessionTTL": 7200,
    "user": {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "email": "alice@example.org",
      "firstName": "Alice",
      "lastName": "Dupont",
      "role": "user",
      "hasMemberAccess": true
    }
  }
}

Les réponses d'erreur suivent le même principe avec la clé error :

json
{
  "error": {
    "code": "INVALID_TOKEN",
    "message": "Lien de connexion invalide."
  }
}

Conversion snake_case → camelCase

La base de données stocke ses colonnes en snake_case (first_name, is_published…). Un middleware global (snakeToCamelMiddleware, monté avant toutes les routes dans server/src/app.ts) convertit automatiquement chaque réponse JSON de succès en camelCase (firstName, isPublished…) avant l'envoi au client. Les corps de requête envoyés par le client, eux, restent en camelCase — la conversion inverse est gérée côté requêtes SQL, pas au niveau de l'API.

Familles d'endpoints

PréfixeRôleAuthentification
/api/authConnexion par magic link (demande, vérification), rafraîchissement de session, connexion de secours, renvoi d'invitationPublic pour la demande/vérification/secours ; user/admin pour le rafraîchissement
/api/setupConfiguration initiale (création du premier admin, test SMTP de démarrage)Public — se ferme dès qu'un administrateur existe
/api/publicConsultation d'un événement publié par UUID et de ses créneaux, gestion de ses propres réservationsAuth optionnelle en lecture (mode consultation sans session) ; user requis pour réserver/annuler
/api/meProfil et données de l'utilisateur connecté (événements, créneaux réservés, créneaux disponibles)user (accès à un membre admin également)
/api/adminAdministration : dashboard/analytics, utilisateurs, événements, créneaux, invitations, paramètres SMTP/emails/identité visuelle, configuration (polling, TTL), enveloppes d'email (shell-parts), codes de secours, notifications d'annulationadmin
/api/admin/uploadsUpload d'image pour l'éditeur d'emails (max 5 Mo, retourne une URL absolue)admin
/healthStatut de santé public, binaire (ok/degraded), sans détail internePublic

Deux préfixes publics annexes

Le code expose aussi /api/events (liste et détail des événements publiés, sans authentification, filtrage minimal) et /api/slots (regroupe des routes de gestion admin des créneaux et de réservation/annulation par un membre authentifié, sous un préfixe distinct de /api/admin et /api/public). Ces deux préfixes se recoupent fonctionnellement avec /api/public et /api/admin/events/:id/slots — voir le code pour arbitrer lequel utiliser dans une intégration (server/src/routes/public.events.routes.ts, server/src/routes/slots.routes.ts).

Détail — /api/admin, sous-familles

Sous-préfixe / groupeExemples de routesDescription
Dashboard / analyticsGET /admin/dashboard, GET /admin/stats, GET /admin/analytics/…KPI, réservations brutes, engagement, activité par événement
UtilisateursGET/POST /admin/users, GET/PUT/DELETE /admin/users/:id, POST /admin/users/bulk-delete, POST /admin/users/import, GET /admin/users/exportCRUD, import/export CSV, suppression groupée
ÉvénementsGET/POST /admin/events, PUT/DELETE /admin/events/:id, POST /admin/events/:id/duplicate, PUT /admin/events/:id/publish | /unpublish, PUT /admin/events/:id/opening-dateCRUD, publication, duplication, date d'ouverture
CréneauxGET/POST /admin/events/:eventId/slots, GET/PUT/DELETE /admin/slots/:idGestion des créneaux d'un événement
InvitationsPOST /admin/events/:id/invitations/send, GET /admin/events/:id/invitations, POST /admin/events/:id/invitations/:userId/resend, POST /admin/events/:id/invitations/resend-unansweredEnvoi, statut, relances
Paramètres (/admin/settings)GET/PUT/DELETE /settings/smtp, GET/PATCH /settings/email-brand, GET/PATCH /settings/email-templates/:templateKeySMTP, identité visuelle, modèles d'email
ConfigurationGET/PUT /admin/config/polling-interval, GET/PUT /admin/config/magic-linkIntervalle de polling, TTL magic link
Enveloppes d'email (/admin/shell-parts)PUT/DELETE /shell-parts/:ownerKind/:ownerId/:partKindParties MJML d'en-tête/pied de page (cascade marque → modèle → événement)
Codes de secoursGET /admin/recovery-codes/status, POST /admin/recovery-codes/generate, PATCH /admin/recovery-codes/dismissGénération et statut des codes de secours admin
Notifications d'annulationGET /admin/cancellation-notifications, POST /admin/cancellation-notifications/resendNotifications en attente et relance groupée

Exemple de payload d'erreur de validation

json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Format d'email invalide"
  }
}

La forme exacte du corps d'erreur varie selon l'endpoint et son ancienneté : certaines routes renvoient { "error": { "code", "message" } }, d'autres { "error": "message" }, d'autres encore un code seul (par exemple { "code": "INVALID_CREDENTIALS" } sur la connexion de secours — comportement observé sur l'instance de référence, juillet 2026). Seul le code HTTP fait foi de manière uniforme.

Endpoint de santé

GET /health (public, hors préfixe /api) renvoie un statut binaire sans authentification, utilisable par une sonde de supervision externe :

json
{
  "status": "ok",
  "timestamp": "2026-07-13T08:00:00.000Z",
  "services": {
    "smtp": "ok"
  }
}

status et services.smtp valent ok ou degraded (chaînes) ; le code HTTP reste 200 dans les deux cas.

Un statut détaillé réservé aux administrateurs (base de données incluse) existe à GET /api/admin/health. Voir Dépannage pour l'usage de ces deux endpoints en diagnostic.

Rate limiting

Plusieurs endpoints sensibles (/api/auth/login, /api/auth/emergency-login, envois de test SMTP/email, upload d'image) sont limités en nombre de requêtes par fenêtre de temps, indépendamment de toute configuration. Le détail des seuils est documenté dans Sécurité — Limitation de débit ; un dépassement renvoie un code HTTP 429 avec { "error": { "code": "RATE_LIMITED", … } }.

Pour aller plus loin

Publié sous licence FSL-1.1-MIT.