API REST

L'API REST du Labo du Yeti expose l'intégralité des fonctionnalités du CMS via des endpoints HTTP versionnés sous le préfixe /api. Toutes les routes sont servies par backend/src/server.js (Express ESM) et chaque router est isolé dans backend/src/routes/. Cette page documente l'ensemble des endpoints groupés par router, avec rôles requis, capabilities, exemples de payload, réponses et codes d'erreur typiques.

Convention Toutes les requêtes JSON utilisent Content-Type: application/json. Les réponses suivent le format { ok: true, ... } en cas de succès et { ok: false, error: "code", message: "..." } en cas d'erreur. Les dates sont au format ISO 8601.

Authentification globale

Deux mécanismes d'authentification cohabitent :

Le middleware requireAuth (backend/src/middleware/auth.js) accepte les deux. requireRole(...) et requireCapability(featureId) sont chaînés ensuite pour le contrôle d'accès granulaire. Voir Authentification & RBAC.

Rate limits

Quatre niveaux de rate limiting sont actifs :

LimiterCibleQuota
GlobalToutes routes API600 req/min/IP
loginLimiter/auth/login, /auth/2fa/*, /auth/password-reset/*10 req/min/IP
aiGenLimiterGénérations IA (cocon, blog, articles)10 req/min/IP
restoreLimiter/backup/restore1 req/min/IP
submitLimiter/forms/:formId (soumissions publiques)10 req/min/IP

Le dépassement renvoie 429 Too Many Requests avec un header Retry-After.

Codes d'erreur communs

CodeSignificationCas typiques
400Bad RequestPayload invalide, champ requis manquant
401UnauthorizedJWT absent/expiré, token API invalide
403ForbiddenRôle insuffisant, capability désactivée
404Not FoundRessource inexistante
409ConflictSlug déjà pris, conflit optimistic locking
412Precondition Failedif_updated_at obsolète (concurrent edit)
429Too Many RequestsRate limit dépassé
500Server ErrorErreur interne (consulter logs)

/api/auth — Authentification

Géré par backend/src/routes/auth.js avec le service backend/src/services/auth-service.js. Cycle complet : bootstrap initial, login, 2FA email, password reset 3-étapes, gestion des admins et tokens API.

GET /api/auth/status

GET Public. Renvoie l'état d'initialisation du CMS.

{ "ok": true, "bootstrapped": true, "two_factor_enabled": false }

POST /api/auth/bootstrap

POST Public, rate limit 10/min. Crée le premier compte owner (un seul appel possible).

curl -X POST https://example.com/api/auth/bootstrap \
  -H "Content-Type: application/json" \
  -d '{"fullname":"Jean Dupont","username":"admin","email":"admin@example.com","password":"S3cur3!Pass"}'

Erreurs : 409 si déjà bootstrappé, 400 si payload invalide.

POST /api/auth/login

POST Public, rate limit 10/min. Accepte email ou username.

{ "login": "admin@example.com", "password": "S3cur3!Pass" }

Réponse 200 : { ok: true, requires_2fa: false, user: { id, role, ... } }. Si 2FA activée, renvoie { ok: true, requires_2fa: true, challenge_id }. Erreurs : 401 credentials invalides, 429 trop de tentatives.

POST /api/auth/2fa/verify

POST Public, rate limit 10/min. Vérifie le code 6 chiffres envoyé par email.

{ "challenge_id": "uuid", "code": "123456" }

POST /api/auth/password-reset/{request,verify,confirm}

POST Cycle 3-étapes : request (email cible), verify (token reçu par mail), confirm (nouveau mot de passe). Rate limit 10/min sur chaque étape.

GET /api/auth/me

GET Auth requise. Retourne le profil courant : { id, fullname, username, email, role, last_login_at }.

CRUD /api/auth/admins

Règle owner Seul un owner peut modifier le rôle d'un autre utilisateur ou supprimer un autre owner. Voir RBAC pour la matrice complète.

GET / PUT /api/auth/security

Lecture (owner, admin) et mutation (owner uniquement) de la config sécurité : mode développement, activation 2FA globale.

/api/auth/tokens

Capability settings_tokens requise (owner et admin par défaut).

curl -X POST https://example.com/api/auth/tokens \
  -H "Authorization: Bearer cmstok_existing" \
  -d '{"name":"CI/CD","scopes":"read","expires_at":"2027-01-01T00:00:00Z"}'

Réponse : { ok: true, token: "cmstok_NEW_RAW", id: "..." }. Le token brut est retourné une seule fois.

/api/pages — Pages statiques

Router : backend/src/routes/pages.js, service : backend/src/services/pages-service.js. Capability pages requise.

Mutations réservées aux rôles owner, admin, webmaster, editor. Verrouillage optimiste via if_updated_at dans le body PUT : retourne 412 Precondition Failed si la version locale est obsolète.

{
  "slug": "a-propos",
  "title": "À propos",
  "status": "published",
  "if_updated_at": "2026-05-26T10:30:00Z",
  "overrides": { "hero.title": "Bienvenue" }
}

/api/blog — Blog

Router : backend/src/routes/blog.js. Capability blog requise sur l'ensemble des endpoints.

Config & taxonomies

Articles

curl -X POST https://example.com/api/blog/articles/abc123/generate \
  -H "Authorization: Bearer cmstok_xxx" \
  -d '{"prompt_extras":"Ton expert, 1200 mots","model":"claude-opus"}'

Réponse { ok: true, article: { ..., status: "draft", ai_usage: { input_tokens, output_tokens } } }.

Prévisualisations & templates globaux

/api/cocon — Cocon SEO

Router : backend/src/routes/cocon.js, service : backend/src/services/cocon-service.js. Capability cocon requise. Pages parent/enfants, variables cartésiennes, quota 5 pages/7j configurable.

Content groups

Pages générées

Médias & preview token

Quota anti-spam 5 pages générées / 7 jours / groupe par défaut. Erreur 409 avec error: "quota_exhausted" et next_slot_at. Notifications email aux rôles admin + webmaster 5 min après chaque créneau libéré.

/api/media — Médiathèque centrale

Router : backend/src/routes/media.js, capability media.

Mutations ouvertes aux rôles owner, admin, webmaster, editor. Conversion WebP automatique si l'extension webp-auto-converter est active.

/api/forms — Formulaires

Router : backend/src/routes/forms.js, capability forms. Auto-détection des <form data-cms-form> dans les templates.

/api/ai — Configuration IA

Router : backend/src/routes/ai.js, capability settings_ai, rôles owner + admin uniquement.

{
  "openai":    { "api_key": "sk-...", "default_model": "gpt-4o-mini" },
  "anthropic": { "api_key": "sk-ant-...", "default_model": "claude-opus" },
  "default_provider": "anthropic"
}

/api/images — Banques d'images

Router : backend/src/routes/images.js, capability settings_apis.

/api/search — Recherche web

Router : backend/src/routes/search.js. Configuration des providers (Brave, SerpAPI, Tavily) pour sourcing d'articles.

/api/build — Build & sitemap

Router : backend/src/routes/build.js, capability build.

curl -X POST https://example.com/api/build \
  -H "Authorization: Bearer cmstok_xxx"

Réponse : { ok: true, generated: { pages: 42, articles: 18, cocon: 120 }, duration_ms: 3120 }. Voir Build & Publication.

/api/layouts — Layouts globaux

Router : backend/src/routes/layouts.js, capability layouts. Templates HTML appliqués à toutes les pages (header, footer, structure).

/api/global — Config globale

Router : backend/src/routes/global.js. Paramètres du site (nom, logo, slogan), header, footer, thème, SMTP.

/api/extensions — Système d'extensions

Router : backend/src/routes/extensions.js, capability extensions, rôles owner/admin/webmaster pour mutations. Marketplace install ZIP (max 10 MB).

Les routes propres aux extensions actives sont exposées sous /api/ext/<id>/.... Voir Système d'extensions.

/api/capabilities — Matrice RBAC

Router : backend/src/routes/capabilities.js. Matrice rôle × feature, mutations réservées à owner.

/api/backup — Sauvegarde & restauration

Router : backend/src/routes/backup.js, capability settings_security, rôle owner exclusivement.

Opération destructive POST /restore remplace la totalité du contenu. Une safety backup automatique est créée avant l'écrasement et listée par /list. Zip slip guard actif (refus des chemins remontants).

/api/logs — Audit

Router : backend/src/routes/logs.js, capability logs.

curl "https://example.com/api/logs?type=user_login&limit=50" \
  -H "Authorization: Bearer cmstok_xxx"

/api/health, /api/version, /api/stats, /api/branding

Endpoints système servis depuis backend/src/server.js (hors router dédié).

Ces endpoints alimentent la plateforme de reporting cross-sites via token API cmstok_*.

/api/ext — Routes d'extensions

Racine dynamique : chaque extension active expose ses routes sous /api/ext/<extension-id>/.... L'authentification et les capabilities sont déterminées par le manifest de l'extension (manifest.permissions). Les hooks events et filter sont enregistrés automatiquement au boot par le loader (extensions/installed/<id>).

Exemples curl complets

# Login + récupération du cookie JWT
curl -c cookies.txt -X POST https://example.com/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"login":"admin@example.com","password":"S3cur3!Pass"}'

# Lister les pages (cookie)
curl -b cookies.txt https://example.com/api/pages

# Créer un article via token API
curl -X POST https://example.com/api/blog/articles \
  -H "Authorization: Bearer cmstok_xxx" \
  -F "template=@./template.html" \
  -F 'meta={"title":"Mon article","category_id":"abc"};type=application/json'

# Lancer un build
curl -X POST https://example.com/api/build \
  -H "Authorization: Bearer cmstok_xxx"

# Exporter un backup
curl -OJ -H "Authorization: Bearer cmstok_xxx" \
  https://example.com/api/backup/export

Pour aller plus loin