Gérez votre vitrine depuis votre serveur ou depuis un assistant : création et réglages, catégories, articles et photos, livraison, pages, publication, commandes, messages de la page Contact, assistance IA. Même norme que l'API v2 (une clé par appel, enveloppes data / error, messages en français), mêmes règles que la page Ma vitrine du portail : limites fixées par CashChap, identité vérifiée, contrôle des fichiers, journal d'activité.
Clé secrète LIVE du service (SKLIVE_…, Portail › Développeurs › Clés API), côté serveur uniquement. La vitrine vend toujours en mode Live : une clé SKSANDBOX_… répond 403live_key_required, une clé publique, de terminal ou de session 403secret_key_required.
Clé absente : 401missing_api_key (en-tête WWW-Authenticate) ; clé inconnue, mal formée ou désactivée : 401invalid_api_key. La clé est comparée en temps constant, jamais journalisée.
La vitrine est celle du service de la clé (une par service). Un service sans vitrine répond 404storefront_not_found avec details.can_create ; créez-la avec POST /v2/vitrine.
Toute écriture est inscrite dans Compte › Journal d'activité du portail (action « VITRINE (API) », mode Live, adresse IP et User-Agent de l'appel).
Enveloppes identiques à l'API v2 : {"data", "meta"} ou {"error"}, jamais de champ success ; X-Request-Id reprend meta.request_id. Les champs sont en anglais snake_case, les dates en ISO 8601 UTC, les montants dans la devise du service (currency, XOF sans décimales). Un champ inconnu est refusé (validation_failed, code unknown_field) ; un corps qui n'est pas un objet JSON répond 400invalid_json.
Versions : CashChap-Version donne la version de la norme v2 publiée (2.6.0), CashChap-Vitrine-Version celle de cette API (1.0.0) ; les ajouts compatibles changent la version mineure.
Pagination des articles, commandes et messages par curseur : limit (1 à 200, 50 par défaut), cursor = meta.next_cursor de la page précédente ; meta.has_more, meta.total.
Idempotence des créations (POST /v2/vitrine, catégories, articles, photos, analyses, génération, réponse à un message) : en-tête Idempotency-Key facultatif (1 à 128 caractères : lettres, chiffres, -, _). Même clé et même corps : même réponse, en-tête Idempotent-Replayed: true ; même clé et corps différent : 409idempotency_conflict ; requête encore en cours : 409request_in_progress. Mémoire : 24 h.
Débit, par clé et par minute : 300 lectures, 60 écritures, 10 lancements IA. Au-delà : 429rate_limited avec Retry-After.
Actions irréversibles (zone Danger, suppression groupée, suppression des brouillons IA) : le corps doit porter "confirm": true, sinon 422confirmation_required.
La vitrine
Route
Rôle
GET/v2/vitrine
Objet storefront : adresse (slug, url), status (draft, published, suspended), nom, présentation, thème et couleur, logo et bannière, téléphone, WhatsApp et adresse (montrés au client après son paiement seulement), options de livraison, seo, pixels, kyc et daily_limit, compteurs (counts), limites de la plateforme (limits), disponibilité de l'IA.
POST/v2/vitrine
Création en brouillon : public_name (2 à 80), slug (3 à 30 caractères, minuscules, chiffres, tirets ; noms de la plateforme réservés) et, facultatifs, description, theme, accent_color (#rrggbb), phone, whatsapp, address, seo {title, description, keywords, auto}, pixels {meta, tiktok}, logo et banner (image). Identité du promoteur vérifiée exigée (403 account_not_activated) ; KYC partiel : daily_limit 200 000 XOF. 201.
PATCH/v2/vitrine
Réglages : seuls les champs envoyés changent (mêmes champs que la création, sauf slug, plus pickup_enabled et delivery_enabled). logo: null retire le logo. Un texte SEO saisi passe en source manual : l'IA ne l'écrase plus.
GET/v2/vitrine/themes
Les treize designs (id, label, accent_color…), les univers de démonstration et les limites.
POST/v2/vitrine/slug
Changer l'adresse (slug) : une fois par 30 jours (409 slug_change_too_soon), l'ancienne redirige pendant 30 jours.
POST/v2/vitrine/publier · /suspendre
Mise en ligne (au moins un article actif, sinon 409 storefront_not_publishable) ; suspension (page « momentanément indisponible »).
DELETE/v2/vitrine/logo · /banner
Retrait du logo (icônes régénérées) ou de la bannière.
POST/v2/vitrine/demo · DELETE
Articles de démonstration d'un univers (universe : mode, alimentation, electronique, beaute, services, artisanat), marqués demo ; suppression de tous les articles de démonstration.
POST/v2/vitrine/danger
action : delete_all_articles, delete_all_categories ou reset (brouillon, textes et thème par défaut, adresse conservée, e-mail au titulaire), avec confirm: true. Les commandes sont toujours conservées.
Une image se donne sous trois formes, dans un objet : {"base64": "…", "filename": "photo.jpg"} (ou une URL de données data:image/jpeg;base64,…), {"url": "https://cashchap.com/vitrine-image/signee/…"} (lien signé CashChap : l'image est copiée, rien n'est téléchargé) ou, pour les photos d'article seulement, {"url": "https://…"} : le serveur télécharge l'image (hôte public résolu, https, sans redirection, 4 Mo au plus). Toute image passe les contrôles de Ma vitrine : nom et contenu suspects refusés (malicious_file_rejected, inscrit dans le journal du compte), type réel vérifié, réencodage et redimensionnement par le serveur, miniature. Formats : JPEG, PNG, GIF, WebP, AVIF, HEIC, BMP, TIFF, SVG assaini.
Catégories
Route
Rôle
GET/v2/vitrine/categories
Liste ordonnée (position), avec articles_count ; meta.uncategorized_articles.
POST/v2/vitrine/categories
name (80 car.), description (200), active. 30 catégories au plus ; un nom déjà pris (ou trop proche) répond 409 category_name_taken. 201.
PATCH/v2/vitrine/categories/{id}
name, description, active, position.
POST/v2/vitrine/categories/ordre
ids dans l'ordre voulu (les catégories absentes suivent).
DELETE/v2/vitrine/categories/{id}
Suppression ; ses articles deviennent « sans catégorie ».
name (2 à 120), price (> 0, arrondi à la devise), description, promo {type: none | price | percent, price, percent (1 à 99), starts_at, ends_at (une date seule est lue à l'heure de Porto-Novo)}, stock (null = illimité), category_id, active, featured (6 au plus), position, variants [{name, price, stock, active}], video_url (YouTube, Vimeo, TikTok), photos [image…]. Les photos refusées sont détaillées dans meta.photos. Limite d'articles de la plateforme : 409 article_limit_reached. 201.
PATCH/v2/vitrine/articles/{id}
Modification partielle (mêmes champs sauf photos) ; variants remplace la liste (une variante avec id est conservée) ; active, featured, category_id (déplacement), position.
POST/v2/vitrine/articles/ordre
ids dans l'ordre voulu ; list : catalog (défaut) ou featured (« À la une »).
Suppression (photos, variantes, vidéo) ; les commandes passées gardent le nom de l'article.
POST/v2/vitrine/articles/{id}/photos
photos [image…] : résultat par photo dans meta.results, liste des photos en data. Limite par article : photo_limit_reached. 201 dès qu'une photo est acceptée.
POST/v2/vitrine/articles/{id}/photos/ordre
ids des photos dans l'ordre voulu.
POST/v2/vitrine/photos/{id}/principale
Photo principale.
PATCH/v2/vitrine/photos/{id}
alt (texte alternatif, 125 car., source manual), main.
pickup_enabled, delivery_enabled, zones (nom, fee, delay).
POST/v2/vitrine/livraison
Remplacement d'un bloc : pickup_enabled, delivery_enabled, zones [{id (pour garder une zone), name, fee, delay}]. Sans zone, la livraison se ferme et le retrait en boutique est forcé.
GET/v2/vitrine/pages
Les trois pages du menu : about, delivery, contact.
POST/v2/vitrine/pages/{type}
title (80), content (5 000, texte sans HTML), active. La page contact est toujours visible (formulaire relayé par CashChap) : seul son titre se règle, aucune coordonnée du vendeur n'y figure.
Commandes
Route
Rôle
GET/v2/vitrine/commandes
Liste paginée, de la plus récente à la plus ancienne ; status : pending, paid, failed, expired, cancelled, to_deliver (payées, non livrées), deposit (acompte reçu) ; from, to, search. meta.totals_by_status. Téléphones masqués.
GET/v2/vitrine/commandes/{id}
Détail synchronisé avec les paiements : status, settlement (full, deposit_pending, deposit_received), delivery_state et next_delivery_state, montants, customer (téléphone en clair), delivery (mode, zone, adresse structurée, position, contact), lines, transaction, payment_url, tracking_url.
POST/v2/vitrine/commandes/{id}/livraison
state : prepared, shipped, delivered, dans l'ordre, pour une commande payée (ou acompte reçu) ; le client est prévenu par e-mail. Sinon 409 delivery_state_invalid.
POST/v2/vitrine/commandes/{id}/annuler
Annulation d'une commande encore payable (sans acompte reçu) : lien de paiement désactivé. Sinon 409 order_not_cancellable.
Messages de la page Contact
Route
Rôle
GET/v2/vitrine/messages
Liste paginée ; status : new, read, replied, spam ; search ; meta.unread. La lecture ne change jamais le statut.
GET/v2/vitrine/messages/{id}
Détail : texte complet, téléphone en clair, article et commande concernés, réponses envoyées.
POST/v2/vitrine/messages/{id}/statut
status : read (marquer lu), replied, spam, new.
POST/v2/vitrine/messages/{id}/repondre
text (2 à 3 000 car.) : e-mail envoyé par CashChap au nom de la boutique, message d'origine cité, journalisé. Sans adresse e-mail du client : 422 message_reply_impossible. 201.
Assistance IA
Disponible quand CashChap l'active (GET /v2/vitrine/ia : available, quota_remaining). Sinon les lancements répondent 503ai_unavailable ; quota du jour épuisé : 429ai_quota_exceeded. Les traitements longs sont asynchrones : la route de lancement répond 202 avec l'objet et son status (pending, processing, completed, failed, confirmed) ; interrogez la route d'état jusqu'à completed, puis confirmez les brouillons.
Route
Rôle
POST/v2/vitrine/analyses
Analyse de photos : photos [{base64, filename}] (30 au plus par défaut). Chaque photo passe les contrôles des photos d'article. 202.
GET/v2/vitrine/analyses · /analyses/{id}
Analyses récentes ; état d'une analyse avec ses drafts (index, name, description, category, price, variants, photos, state).
POST/v2/vitrine/analyses/{id}/confirmer
lines [{index, name, price, category, description, variants (« Taille M, Taille L »)}], active : articles créés avec leurs photos. 201.
DELETE/v2/vitrine/analyses/{id}
Suppression d'une analyse et de ses fichiers.
POST/v2/vitrine/generation
Génération d'articles : category_ids (catégories existantes, 10 au plus), count (1 à 10 par catégorie), theme. Les brouillons sont de vrais articles, inactifs, marqués ai_draft, avec une image provisoire. 202.
GET/v2/vitrine/generation · /generation/{id}
Générations récentes ; état d'une génération avec draft_articles.
POST/v2/vitrine/generation/confirmer
lines [{id, name, price, description, category_id, variants}] : mis en vente (référencement IA planifié).
DELETE/v2/vitrine/generation/brouillons
Efface les brouillons IA non confirmés (confirm: true).
POST/v2/vitrine/referencement
Régénère tout le référencement (accueil et articles) en tâche de fond ; les textes saisis à la main sont conservés. 202.
Le serveur MCP officiel @cashchap/mcp expose chaque route de cette API sous la forme d'un outil vitrine_* pour les assistants (Claude Desktop, Claude Code, Cursor…) : vitrine_voir, vitrine_creer, vitrine_modifier, vitrine_publier, vitrine_categories_*, vitrine_articles_*, vitrine_photos_*, vitrine_livraison_*, vitrine_pages_*, vitrine_commandes_*, vitrine_messages_*, vitrine_analyse_*, vitrine_generation_*, vitrine_referencement_*. Il utilise la même clé secrète que les outils de paiement (CASHCHAP_API_KEY, mode live), appelle CASHCHAP_PORTAIL_URL (https://cashchap.com par défaut) et exige une confirmation explicite pour les actions destructrices. Variable CASHCHAP_MCP_VITRINE : true (gestion complète, défaut), lecture (consultation seule) ou false.
Codes d'erreur
Codes propres à l'API vitrine, en plus des codes communs de la norme v2 (missing_api_key, invalid_api_key, secret_key_required, validation_failed, rate_limited, idempotency_conflict…). Chaque erreur porte error.type, le code HTTP et un message en français.
Code
HTTP
Type
Message
invalid_json
400
invalid_request
Le corps de la requête doit être un objet JSON valide.
request_too_large
413
invalid_request
Le corps de la requête est trop lourd.
invalid_idempotency_key
400
invalid_request
La clé d'idempotence doit contenir 1 à 128 caractères (lettres, chiffres, - et _).
route_not_found
404
not_found
Cette route n'existe pas dans l'API vitrine. Consultez la documentation.
method_not_allowed
405
invalid_request
Cette méthode HTTP n'est pas acceptée sur cette route.
missing_api_key
401
authentication_error
Clé API absente : envoyez l'en-tête Authorization: Bearer <clé secrète>.
invalid_api_key
401
authentication_error
La clé API est inconnue ou n'est plus active. Vérifiez la clé dans Développeurs › Clés API.
secret_key_required
403
permission_denied
L'API vitrine exige la clé SECRÈTE du service (SKLIVE_…), côté serveur uniquement.
live_key_required
403
permission_denied
La vitrine est un objet Live : utilisez la clé secrète LIVE du service, jamais la clé Sandbox.
account_unavailable
403
permission_denied
Le compte de ce service est indisponible (supprimé ou suspendu). Contactez le support CashChap.
service_inactive
403
permission_denied
Ce service n'existe pas ou a été désactivé.
account_not_activated
403
permission_denied
L'identité du promoteur doit être vérifiée (dossier d'activation validé) pour ouvrir ou publier une vitrine.
rate_limited
429
rate_limited
Trop de requêtes. Réessayez dans quelques instants.
request_in_progress
409
conflict
Une requête avec cette clé d'idempotence est encore en cours. Réessayez dans une seconde.
idempotency_conflict
409
conflict
Cette clé d'idempotence a déjà servi pour une autre requête.
validation_failed
422
validation_error
La requête contient des champs invalides.
confirmation_required
422
validation_error
Cette action est irréversible : renvoyez-la avec "confirm": true.
internal_error
500
api_error
Une erreur interne est survenue. Réessayez dans un instant.
storefront_feature_disabled
503
service_unavailable
Les vitrines ne sont pas encore ouvertes sur la plateforme CashChap.
storefront_not_found
404
not_found
Ce service n'a pas encore de vitrine : créez-la avec POST /v2/vitrine.
storefront_already_exists
409
conflict
Ce service a déjà une vitrine : modifiez-la avec PATCH /v2/vitrine.
storefront_limit_reached
409
conflict
Votre compte a atteint le nombre maximal de vitrines.
storefront_not_publishable
409
conflict
Ajoutez au moins un article actif avant de publier la vitrine.
slug_change_too_soon
409
conflict
L'adresse ne peut être changée qu'une fois par 30 jours.
theme_unknown
422
validation_error
Thème inconnu : consultez GET /v2/vitrine/themes.
category_not_found
404
not_found
Catégorie introuvable dans cette vitrine.
category_limit_reached
409
conflict
Le catalogue est limité à 30 catégories.
category_name_taken
409
conflict
Une catégorie porte déjà ce nom (ou un nom trop proche).
article_not_found
404
not_found
Article introuvable dans cette vitrine.
article_limit_reached
409
conflict
Le catalogue a atteint le nombre maximal d'articles (limite de la plateforme).
featured_limit_reached
409
conflict
Six articles au plus peuvent être mis en avant. Retirez-en un d'abord.
photo_not_found
404
not_found
Photo introuvable dans cette vitrine.
photo_limit_reached
409
conflict
Limite de photos par article atteinte.
invalid_image
422
validation_error
L'image n'a pas pu être lue ou traitée.
malicious_file_rejected
422
validation_error
Fichier refusé : son nom ou son contenu est suspect. Ce refus est inscrit dans votre journal d'activité.
remote_image_refused
422
validation_error
Cette adresse d'image n'est pas acceptée.
remote_download_disabled
403
permission_denied
Le téléchargement d'images par adresse est fermé : envoyez l'image en base64.
demo_universe_unknown
422
validation_error
Univers de démonstration inconnu.
page_type_unknown
404
not_found
Type de page inconnu : about, delivery ou contact.
order_not_found
404
not_found
Commande introuvable dans cette vitrine.
order_not_cancellable
409
conflict
Cette commande ne peut plus être annulée.
delivery_state_invalid
409
conflict
Cette étape de livraison n'est pas possible pour cette commande.
message_not_found
404
not_found
Message introuvable dans cette vitrine.
messages_unavailable
503
service_unavailable
Les messages de la page Contact sont momentanément indisponibles.
message_reply_impossible
422
validation_error
Impossible de répondre à ce message par e-mail.
email_not_sent
503
service_unavailable
L'e-mail n'a pas pu partir. Réessayez dans un instant.
ai_unavailable
503
service_unavailable
L'assistance IA n'est pas disponible sur la plateforme pour le moment.
ai_quota_exceeded
429
rate_limited
Quota d'assistance IA atteint pour aujourd'hui. Réessayez demain.
ai_model_failed
502
provider_error
Le modèle n'a pas répondu : les textes actuels sont conservés. Réessayez dans un instant.
analysis_not_found
404
not_found
Analyse de photos introuvable dans cette vitrine.
analysis_not_ready
409
conflict
Cette analyse n'est pas prête à être confirmée.
analysis_no_photo
422
validation_error
Aucune photo exploitable dans cet envoi.
generation_not_found
404
not_found
Génération d'articles introuvable dans cette vitrine.