Aller au contenu

#Atelier, transfert et devis

Les routes que la portée atelier ouvre aux clés d'API — ce que le CLI appelle pour construire un site et le remettre à sa cliente. Même authentification que le reste (Authorization: Bearer wc_…, X-Webcosa-Site-Cible pour désigner le site), même forme d'erreur.

Une clé atelier ne se délivre qu'à un compte partenaire ou agence (POST /api/cles répond 403 portee_reservee sinon). Elle couvre aussi tout ce que themes couvrait.

#Sites

RouteCe qu'elle fait
POST /api/sitescrée un site. Corps { nom, slug?, theme?, metier?, pour? }. Un partenaire le crée en atelier (formule atelier, rien de facturé, pas d'essai) ; un client, dans la limite de sa formule ; l'agence peut ajouter proprietaire. pour: { courriel?, formule?, presence?, devis_id? } pose l'intention « pour une cliente » : elle préremplit le transfert et relie le devis au site
GET /api/sitesles sites accessibles : { id, slug, name, status, role, proprietaire, formule, etat, presence }
POST /api/sites/publierdraft → live. Refusé si le site attend son paiement (402 site_a_activer) ou est suspendu
POST /api/sites/transfertenvoie « Reprenez votre site ». Corps { courriel, formule: depart|pro|croissance, presence?, message?, devis? } — chaque champ absent est pris dans le pour de la création. Propriétaire + partenaire, site en atelier
GET /api/sites/transfertle transfert vivant, ou null — jamais l'empreinte du lien. ouvert_le / ouvertures : la cliente a demandé son code
PATCH /api/sites/transfert{ action: "renvoyer" } : jeton neuf, l'ancien meurt, trois par jour
DELETE /api/sites/transfertannule

theme doit être un identifiant du catalogue (vela, origo, fondant…) ; sinon 400 theme_inconnu avec la liste themes.

#Contenu

RouteCe qu'elle fait
GET /api/pages, POST /api/pagesle routage des pages ; POST { title, slug? }
PATCH /api/pages/<id>, DELETE, POST /api/pages/<id>/publishtitre, adresse, SEO, accueil ; corbeille ; publication. Une nouvelle adresse emporte la mise en page (templates/<adresse>.json de chaque thème du site, sans jamais écraser un gabarit déjà présent à la nouvelle), les liens du menu et, avec rediriger: true si la formule comprend les redirections, une 301 depuis l'ancienne ; la réponse dit ce qui a suivi (renommage)
PATCH /api/pages/referencementle référencement de plusieurs pages en une requête : { pages: [{ id, seo }] }, 1 à 60 pages, seo complet (déjà fusionné) ; même permission que la route unitaire, pages à la corbeille refusées, cache public purgé une fois
GET /api/menus, PATCH /api/menus{ slug: "main-menu" | "footer-menu", content: { items } }, le menu entier. garde: { site, majLe } facultatif : 409 autre_site ou 409 modifie_entre_temps si le site ou le menu a changé depuis la lecture (updated_at)
GET /api/parametres/<onglet>, PATCHgeneral, contact, seo, legal, suivi, acces, ia ; { content }, le bloc entier. Quatre champs, ajoutés depuis, sont facultatifs et conservés quand l'envoi les omet : general.icone (l'icône d'onglet), seo.imagePartage (l'image de partage par défaut), contact.horairesDetail (les horaires jour par jour, lundi d'abord), contact.whatsapp (le bouton WhatsApp) ; "" retire une image, null les horaires. ia règle les robots d'IA du robots.txt du site : { gere, chatgpt, perplexity, claude, gemini, entrainement }, six booléens ; gere: true (le défaut) laisse la plateforme décider et ignore les cinq autres, false ferme chaque assistant à false (gemini = Google-Extended, entrainement = GPTBot, ClaudeBot, CCBot). garde: { site, majLe } facultatif, comme pour les menus
PUT /api/theme/compositionune page validée contre les schémas de section
POST /api/fichiers/televersermultipart/form-data, champ fichier (JPEG, PNG, WebP, AVIF, 5 Mo). Rend { fichier: { path, publicUrl, … } }

Les textes d'une page vivent dans templates/<adresse>.json du thème publié : PUT /api/themes/<id>/fichiers les écrit, comme n'importe quel fichier de thème.

#Devis

RouteCe qu'elle fait
POST /api/devisun brouillon. Corps : { site_id?, cliente: { nom, courriel, entreprise?, adresse?, code_postal?, ville?, siret? }, objet, formule, presence?, inclus[], delais?, validite_jours?, mise_en_route_cents?, corrections_heure_cents? }
GET /api/devisles devis du compte
GET /api/devis/<id ou numéro>le devis, une URL de PDF valable cinq minutes, et evenements[] — le journal : cree, modifie, envoye, renvoye, ouvert, code_demande, signe, refuse, paye, annule, expire, chacun avec cree_le et un detail (le motif d'un refus, par exemple). Le devis porte aussi ouvert_le, ouvertures, refuse_le, refus_motif
GET /api/devis/<id>/pdfle PDF lui-même — le signé s'il existe ; un brouillon se rend à la volée (aperçu) — servi par notre domaine, inline
GET /api/devis/completer?siret=… ou ?adresse=…remplir la cliente : l'entreprise et son adresse d'après le SIRET (annuaire des entreprises), ou des adresses complètes en tapant (Base Adresse Nationale) — { entreprise, adresse, code_postal, ville, siret } / { adresses: [{ label, adresse, code_postal, ville }] }
PATCH /api/devis/<id>tant qu'il est brouillon
POST /api/devis/<id>/envoyerrend le PDF, pose le lien de signature, envoie le courriel
DELETE /api/devis/<id>annule (jamais un devis signé)

Le numéro est WC-AAAA-NNNN. La facture, elle, est émise par Stripe au paiement.

#La signature — publique

Ces routes n'ont ni clé ni session : le jeton du lien reçu par la cliente est l'autorisation. Elles répondent sur signature.webcosa.com comme sur le CMS.

RouteCe qu'elle fait
GET /api/signature/<jeton>le devis tel que la page l'affiche, peutSigner, peutPayer, URL du PDF
POST /api/signature/<jeton>/otpenvoie un code à six chiffres à l'adresse du devis (cinq par heure)
POST /api/signature/<jeton>/signer{ nom, code, consentement: true, demarrageImmediat: true }. Empreinte SHA-256 du PDF, horodatage RFC 3161, PDF signé, ligne de preuve
POST /api/signature/<jeton>/payerStripe Checkout, paiement unique, facture Stripe. Exige un devis signé
POST /api/signature/<jeton>/ouvert« la page a été affichée » — appelée par le navigateur au montage, jamais au rendu serveur (les antivirus suivent les liens). Compte les ouvertures ; le partenaire est prévenu à la première
POST /api/signature/<jeton>/compte{ motDePasse } (8 caractères au moins), sur un devis réglé : crée le compte Webcosa à l'adresse du devis (déjà prouvée par le code de signature), le relie au devis (compte_id), journalise acces_cree. 409 compte_existant si l'adresse a déjà un compte (relié au passage) ; 409 devis_non_paye avant le paiement
POST /api/signature/<jeton>/refuser{ motif? } (600 caractères). Le devis passe refuse, la signature se ferme, le partenaire reçoit le mot. Sans code : refuser n'engage à rien

#La reprise d'un site — publique

POST /api/transferts/code avec { jeton } envoie un code de connexion à l'adresse du transfert — et crée le compte s'il n'existe pas. La réponse est la même que le jeton existe ou non. L'acceptation (POST /api/transferts/accepter) exige une session à cette adresse.

#Codes d'erreur propres à l'atelier

errorStatutSignification
portee_reservee403une clé atelier demandée par un compte qui n'est ni partenaire ni agence
partenaire_requis403la route exige un partenaire ou l'agence
theme_inconnu400theme n'est pas dans le catalogue (themes liste les valeurs)
transfert_en_attente409cette adresse a un site qui l'attend : elle passe par le lien de reprise, pas par une création
site_hors_atelier409le site n'est plus en atelier, il ne se transfère pas
transfert_deja_envoye409un transfert vivant existe déjà (renvoyer ou annuler)
transfert_a_soi_meme400l'adresse est celle du partenaire
site_a_activer402le site attend son premier paiement : rien ne le met en ligne d'ici là
devis_fige409le devis n'est plus brouillon (ou est signé, payé, annulé)
devis_non_signe409paiement demandé avant la signature
devis_non_refusable409seul un devis envoyé se refuse
code_faux, code_expire, code_epuise403le code de signature