#Import et export
Deux routes pour déplacer un thème entier : le télécharger en un fichier, le reposer ailleurs. C’est la sauvegarde avant une expérimentation, le transport d’un thème d’un site à un autre, et l’archive qu’on garde hors ligne.
Pour modifier un fichier, ce n’est pas ici : voir Fichiers.
#Un JSON, et pas une archive ZIP
Shopify livre un .zip. Nous livrons un .json qui contient les mêmes fichiers,
et le choix est assumé.
Produire une archive demanderait une dépendance pour empaqueter, une autre pour dépaqueter, et l’inspection du contenu à l’import deviendrait autrement plus délicate — une archive peut cacher des chemins traversants, des liens symboliques, des fichiers qui se décompressent en gigaoctets. Un JSON est lisible, se relit à l’œil nu, et son import se valide champ par champ.
Le jour où l’on acceptera les .zip de Shopify, le format d’import restera
celui-ci : il suffira de convertir à l’entrée.
#Exporter
/api/themes/<id>/export{
"format": "webcosa-theme",
"format_version": 1,
"nom": "Origo",
"version": "1.0.0",
"origine": "origo",
"exporte_le": "2026-08-05T09:41:12.003Z",
"fichiers": {
"layout/theme.liquid": "<!doctype html>\n<html lang=\"fr\">…</html>\n",
"templates/index.json": "{\n \"sections\": { … },\n \"order\": [\"entete\", \"hero\"]\n}\n",
"config/settings_schema.json": "[\n { \"name\": \"Couleurs\", \"settings\": [] }\n]\n"
}
}{ "error": "introuvable" }Portée lecture. Une clé de sauvegarde doit pouvoir exporter sans obtenir au
passage le droit d’écrire les thèmes.
La réponse porte deux en-têtes qui comptent :
Content-Type: application/json; charset=utf-8
Content-Disposition: attachment; filename="origo-1.0.0.json"
Cache-Control: no-storeLe nom de fichier est dérivé du nom du thème — accents retirés, minuscules,
tout ce qui n’est ni lettre ni chiffre remplacé par un tiret — suivi de sa
version. no-store parce qu’on retélécharge un thème justement quand on vient de
le modifier.
formatchaîneToujours webcosa-theme. C’est ce que l’import exige à la lettre.
format_versionentierLa version du format d’archive, pas celle du thème. Vaut 1, et l’import
n’accepte que 1 : une archive produite par une version future sera refusée
franchement plutôt que lue de travers.
nomchaîneLe nom du thème au moment de l’export.
versionchaîneL’étiquette de version du thème.
originechaîne ou nullLe thème du catalogue dont il descend. Présent dans l’archive, ignoré à l’import — voir plus bas.
exporte_lehorodatagePurement informatif. Rien ne le relit.
fichiersobjetUne carte chemin → contenu, en clair. C’est le thème entier : Liquid, JSON de
configuration, CSS, SVG.
curl -s "https://cms.webcosa.com/api/themes/$THEME/export" \-H "Authorization: Bearer $WEBCOSA_CLE" \-o origo-sauvegarde.json 27 fichiers, 412 KoL’archive contient le code complet du thème, config/settings_data.json
compris — donc les valeurs de réglages du site : couleurs, textes, adresses,
numéros de téléphone. Ce n’est pas un secret d’authentification, mais ce n’est
pas non plus un fichier à laisser traîner dans un dossier partagé.
#Importer
/api/themes/importerCorps de la requête
{
"format": "webcosa-theme",
"format_version": 1,
"nom": "Origo — reprise",
"version": "1.0.0",
"fichiers": {
"layout/theme.liquid": "<!doctype html>…",
"templates/index.json": "{ \"sections\": {}, \"order\": [] }",
"config/settings_schema.json": "[]"
}
}{ "ok": true, "themeId": "55555555-5555-4555-8555-555555555555" }{
"error": "archive_invalide",
"message": "Ce fichier n'est pas un thème Webcosa, ou il vient d'une version que cette installation ne sait pas lire."
}{
"error": "fichier_requis_manquant",
"message": "Il manque un fichier indispensable. Attendus : layout/theme.liquid, config/settings_schema.json, templates/index.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)." }Portée themes. Un import crée toujours un thème neuf, en brouillon : il ne
remplace jamais un thème existant, et il n’y a pas de « réimporter par-dessus ».
Le corps est le contenu d’un fichier d’export, tel quel.
formatchaînerequisDoit valoir exactement webcosa-theme.
format_versionentierrequisDoit valoir 1. Aucune autre valeur n’est acceptée.
nomchaînerequisDe 1 à 80 caractères, espaces de bordure retirés. C’est le nom que portera le thème créé — change-le si tu réimportes sur le même site, sinon deux thèmes homonymes cohabiteront dans la liste.
versionchaînedéfaut : 1.0.0Jusqu’à 20 caractères. Absente, le thème est créé en 1.0.0.
originechaîne ou nullAccepté par le schéma, jusqu’à 40 caractères — puis écrasé à null. Un thème
importé ne descend plus d’un de nos modèles ; lui laisser une filiation ferait
croire à des mises à jour qui ne viendront jamais.
Le champ n’est donc conservé dans l’archive que pour la lisibilité humaine.
fichiersobjetrequisUne carte de chaînes vers des chaînes. Une valeur qui n’est pas une chaîne — un
nombre, un objet imbriqué — fait échouer la validation avec archive_invalide,
avant tout contrôle de chemin.
#Ce que l’archive doit contenir
L’archive est validée deux fois : d’abord sa forme, puis chacun de ses fichiers, avec exactement les mêmes règles qu’une écriture unitaire.
error | Cause |
|---|---|
archive_invalide | Un champ de tête manquant, mal typé, ou format_version différent de 1 |
vide | fichiers ne contient aucune entrée |
trop_de_fichiers | Plus de 120 entrées |
fichier_trop_gros | Une entrée dépasse 524 288 unités de code UTF-16 |
chemin_invalide | Une entrée est hors des six dossiers, porte une extension refusée, ou tente une traversée |
fichier_requis_manquant | Il manque layout/theme.liquid, templates/index.json ou config/settings_schema.json |
creation_impossible | La ligne du thème n’a pas pu être écrite |
ecriture_impossible | Les fichiers n’ont pas pu être écrits — le thème créé est alors effacé, pour ne pas laisser une coquille |
À la différence de PUT /api/themes/<id>/fichiers, l’import ne vérifie pas la
syntaxe Liquid. Une archive dont une section ne compile pas s’installe sans
erreur ; le défaut n’apparaît qu’au rendu, sous forme de commentaire HTML dans la
page. Voir Le bac à sable.
C’est cohérent avec la provenance attendue — une archive vient d’un export, donc d’un thème qui s’écrivait déjà fichier par fichier — mais ce n’est pas une garantie sur laquelle s’appuyer.
#Ce qu’un thème importé peut faire
Liquid ne donne accès ni au disque, ni au réseau, ni à du JavaScript serveur : un thème ne peut pas lire la base ni sortir du site. Mais il produit du HTML, et rien n’échappe ce HTML — pas plus ici que chez Shopify.
Un thème venu d’ailleurs peut donc poser une balise script sur le site de celui
qui l’installe, sous son domaine, avec accès à ses cookies.
Aujourd’hui c’est acceptable : on n’importe que ce qu’on a soi-même exporté, et le seul site atteint est le sien. N’importe pas une archive dont tu n’es pas l’auteur. Le jour où des thèmes circuleront entre comptes, il faudra assainir le HTML rendu — et cette décision se prend avant d’ouvrir cette porte, pas après.
Le corps de la requête ne contient aucun identifiant de site, et c’est
délibéré. Le thème atterrit sur le site résolu par l’authentification, et nulle
part ailleurs : accepter un site_id dans l’archive rendrait cette route capable
d’écrire chez le voisin, à l’endroit précis du produit où l’on accepte du code
venu du dehors.
#Déplacer un thème d’un site à un autre
Exporter depuis le site source
curl -s "https://cms.webcosa.com/api/themes/$SOURCE/export" \-H "Authorization: Bearer $WEBCOSA_CLE" \-H "X-Webcosa-Site-Cible: atelier-durand" \-o theme.jsonRenommer, si les deux sites sont proches
Deux thèmes appelés « Origo » sur des sites différents ne gênent personne. Deux sur le même site, si.
jq '.nom = "Origo — repris de Durand"' theme.json > theme-a-importer.jsonImporter sur le site cible
L’en-tête change, la clé non : elle atteint tous les sites de son porteur.
curl -s -X POST https://cms.webcosa.com/api/themes/importer \-H "Authorization: Bearer $WEBCOSA_CLE" \-H "X-Webcosa-Site-Cible: menuiserie-bertin" \-H "Content-Type: application/json" \--data-binary @theme-a-importer.json{"ok":true,"themeId":"55555555-5555-4555-8555-555555555555"}Regarder avant de publier
Le thème est arrivé en brouillon. Les réglages de
config/settings_data.jsonviennent du site d’origine : couleurs, textes, coordonnées. Relisez-les avant lePATCHde publication décrit dans Thèmes.

