Aller au contenu

#Thèmes

Un site a plusieurs thèmes et un seul publié — celui que voient ses visiteurs. Les quatre méthodes de /api/themes couvrent tout ce qui arrive à un thème dans sa vie : naître, se faire copier, changer de nom, monter en ligne, disparaître. Le contenu, lui, se manipule fichier par fichier depuis Fichiers.

Toutes les opérations portent sur le site résolu — celui de X-Webcosa-Site-Cible, ou le premier accessible. Un identifiant de thème qui n’appartient pas à ce site répond 404 introuvable, jamais 403 : distinguer « n’existe pas » de « appartient à quelqu’un d’autre » confirmerait à un curieux que l’uuid deviné existe bien quelque part.

#Lister

GET/api/themes
200
json
{
  "site": {
    "id": "9f2c4a11-0d38-4e77-b6c2-5f9a13d8e401",
    "slug": "atelier-durand",
    "nom": "Atelier Durand"
  },
  "themes": [
    {
      "id": "11111111-1111-4111-8111-111111111111",
      "nom": "Origo",
      "version": "1.0.0",
      "role": "publie",
      "origine": "origo",
      "maj_le": "2026-08-05T09:12:44.108Z"
    },
    {
      "id": "22222222-2222-4222-8222-222222222222",
      "nom": "Origo (copie)",
      "version": "1.0.0",
      "role": "brouillon",
      "origine": "origo",
      "maj_le": "2026-08-04T17:02:11.740Z"
    }
  ]
}
409 — le compte n’a aucun site
json
{ "error": "no_site" }

Portée lecture suffit. Le thème publié vient en tête : c’est celui qu’on vient voir en premier. Les brouillons suivent, du plus récemment modifié au plus ancien.

siteobjet

Le site réellement résolu, avec son id, son slug et son nom. Présent à chaque appel, et pas par confort : sans en-tête de désignation, la clé retient le premier site accessible, un ordre qui change le jour où un site s’ajoute au compte. Le CLI inscrit ce champ dans son .webcosa.json pour ne plus jamais dépendre de cet ordre.

themes[].iduuid

L’identifiant du thème, celui qu’attendent toutes les autres routes.

themes[].nomchaîne

Jusqu’à 80 caractères. Modifiable par PATCH.

themes[].versionchaîne

Celle déclarée par le thème d’origine, recopiée à l’installation. L’API ne la modifie jamais — c’est une étiquette, pas un compteur.

themes[].rolepublie | brouillon

publie pour le thème servi aux visiteurs, brouillon pour tous les autres. Un site n’a qu’un publie à la fois, garanti par un index en base et non par le code applicatif.

themes[].originechaîne ou null

L’identifiant du thème du catalogue dont celui-ci descend — origo, forge, vela, piazza. null pour un thème importé : l’import efface la filiation, parce que laisser croire à des mises à jour qui ne viendront jamais serait pire que de ne rien dire.

themes[].maj_lehorodatage

Réécrite à chaque écriture de fichier et à chaque publication. C’est elle qui ordonne la liste.

#Installer un thème du catalogue

POST/api/themes

Corps de la requête

json
{ "action": "installer", "origine": "origo" }
201
json
{ "ok": true, "themeId": "33333333-3333-4333-8333-333333333333" }
400 — origine inconnue
json
{ "error": "theme_inconnu" }
402 — site inactif
json
{
  "error": "site_inactif",
  "etat": "expire",
  "message": "Ce site n'est plus actif : ses modifications sont bloquées. Reprends un abonnement depuis le CMS (Réglages → Abonnement)."
}
403 — clé en lecture seule
json
{ "error": "portee_insuffisante" }
actioninstallerrequis

Distingue les deux formes acceptées par cette route. installer et dupliquer n’ont aucun champ en commun, d’où deux formes plutôt qu’un champ optionnel.

originechaînerequis

L’identifiant d’un thème du catalogue, de 1 à 40 caractères. Quatre valeurs existent aujourd’hui : origo, forge, vela, piazza.

curl -s -X POST https://cms.webcosa.com/api/themes \-H "Authorization: Bearer $WEBCOSA_CLE" \-H "X-Webcosa-Site-Cible: atelier-durand" \-H "Content-Type: application/json" \-d '{"action":"installer","origine":"forge"}'{"ok":true,"themeId":"33333333-3333-4333-8333-333333333333"}
Note

Installer ne publie pas. Le thème arrive en brouillon, et il faut un second geste — le PATCH ci-dessous — pour qu’il remplace celui que voient les visiteurs. On installe pour regarder ; publier d’office changerait le site public d’un client au moment où il explore, et il n’y a pas de bouton « annuler » pour ses visiteurs.

#Dupliquer

POST/api/themes

Corps de la requête

json
{ "action": "dupliquer", "id": "11111111-1111-4111-8111-111111111111" }
201
json
{ "ok": true, "themeId": "44444444-4444-4444-8444-444444444444" }
404 — thème inconnu, ou d’un autre site
json
{ "error": "introuvable" }
400 — les fichiers ne passent pas la validation
json
{ "error": "fichier_requis_manquant", "message": "Il manque un fichier indispensable. Attendus : layout/theme.liquid, config/settings_schema.json, templates/index.json." }

La copie reprend la version et l’origine de la source, et prend son nom suivi de (copie). Elle arrive en brouillon, comme tout thème installé.

C’est le geste qui rend l’édition de code sans danger : on travaille sur une copie, on regarde, et on publie quand on est content. Le CLI le propose de lui-même quand on tente de suivre un thème publié.

Attention

id doit être un uuid bien formé — un identifiant court de huit caractères, comme celui qu’affiche theme lister, vaut 400 invalid_input. Le raccourci est une commodité du CLI, qui le résout avant d’appeler l’API ; l’API, elle, ne devine rien.

#Renommer et publier

PATCH/api/themes

Corps de la requête

json
{ "id": "22222222-2222-4222-8222-222222222222", "nom": "Atelier v2", "publier": true }
200
json
{ "ok": true }
404 — thème inconnu, ou d’un autre site
json
{ "error": "introuvable" }
500 — la publication a échoué
json
{ "error": "publication_impossible" }
iduuidrequis

Le thème visé. Confronté au site avant toute action.

nomchaîne

De 1 à 80 caractères, espaces de bordure retirés. Appliqué en premier, pour qu’un appel qui renomme et publie d’un coup mette en ligne le thème déjà renommé.

publierbooléen

true met le thème en ligne et démet celui qui l’était.

false ne fait rien — il n’existe aucune façon de dépublier. C’est volontaire : un site sans thème publié n’affiche plus rien. On remplace un thème en ligne par un autre, on ne l’éteint pas.

Les deux champs sont facultatifs : un corps réduit à id répond 200 ok sans rien changer. C’est sans conséquence, mais ce n’est pas une confirmation que le thème existe — ça, c’est le 404 qui le dit.

Danger

Un uuid mal recopié dans publier aurait pu éteindre le site. La publication démet d’abord le thème publié, puis promeut l’identifiant demandé : avec un identifiant étranger au site, la première moitié réussissait et la seconde ne trouvait rien — le site se retrouvait sans thème publié.

C’est la raison pour laquelle l’appartenance est vérifiée par une lecture distincte, avant d’agir, et pas seulement par les filtres des mises à jour qui suivent. Un update qui ne touche aucune ligne ne rend aucune erreur.

Publier fait aussi naître une page d’accueil si le site n’en a pas encore. Publier, c’est mettre le site en ligne ; sans page d’accueil, l’écran « Pages » reste vide, le référencement n’a nulle part où poser un titre, et il n’y a rien à ouvrir dans l’éditeur. L’échec de cette création ne fait pas échouer la publication — un thème bien en ligne ne doit pas être annulé par une page manquante.

curl -s -X PATCH https://cms.webcosa.com/api/themes \-H "Authorization: Bearer $WEBCOSA_CLE" \-H "Content-Type: application/json" \-d '{"id":"22222222-2222-4222-8222-222222222222","publier":true}'{"ok":true}

#Retirer

DELETE/api/themes?id=<uuid>
200
json
{ "ok": true }
400 — paramètre id absent
json
{ "error": "invalid_input" }
404 — thème inconnu, ou d’un autre site
json
{ "error": "introuvable" }
409 — c’est le thème publié
json
{
  "error": "theme_publie",
  "message": "Ce thème est celui que voient tes visiteurs. Publie-en un autre avant de le retirer."
}

Le thème publié ne se supprime pas. Ce serait éteindre l’apparence du site en un appel, sans rien pour la remplacer. Il faut d’abord en publier un autre — ce qui est exactement le geste qu’on veut forcer.

La suppression emporte les fichiers du thème avec elle, et il n’y a ni corbeille ni version précédente. Exportez avant, si le doute existe : voir Import et export.

Note

C’est la seule écriture de cette section qui n’exige pas que le site soit actif. Retirer un brouillon ne change rien à ce que voient les visiteurs, et un site en fin d’essai peut encore faire le ménage chez lui. Le thème publié, lui, reste protégé par la garde ci-dessus.

#L’ordre des contrôles

Il compte, parce qu’il décide de l’erreur qu’on reçoit quand plusieurs sont vraies à la fois.

RangContrôleRefus
1Clé valable401 unauthorized
2Portée suffisante403 portee_insuffisante
3Le compte a au moins un site409 no_site
4Site demandé accessible403 site_interdit
5Site actif — POST et PATCH seulement402 site_inactif
6Corps conforme400 invalid_input
7Le thème est bien du site404 introuvable

Un site dont l’essai est terminé répond donc 402 même si le corps de la requête est absurde : la facturation est vérifiée avant la forme.