Comprendre un envoi de webhook
Le contrat en bref
Section intitulée « Le contrat en bref »| Point | Valeur |
|---|---|
| Méthode | POST |
| En-têtes envoyés | Host, User-Agent: GuzzleHttp/7, Content-Type: application/json, Content-Length. Rien d’autre : ni Accept, ni signature, ni identifiant d’événement, ni identifiant de site |
| Corps | JSON compact, champs de l’objet à la racine, plus une clé changed. Pas d’enveloppe, pas de métadonnée |
| Identification de l’événement | uniquement par l’URL appelée. Déclarez une URL distincte par clé |
| Délais | 10 secondes pour établir la connexion, 30 secondes pour votre réponse |
| Tentatives | 5 tentatives au total, et seulement si la connexion échoue (DNS, refus, délai dépassé, certificat invalide) : 30 secondes d’attente entre les trois premières, puis les deux dernières enchaînées sans attente |
| Codes de réponse | tous acceptés sans distinction. Un 500 de votre côté n’est jamais rejoué |
| Doublon garanti | si vous répondez en plus de 30 secondes, l’envoi est considéré comme perdu et rejoué jusqu’à quatre fois, alors qu’il vous est déjà parvenu |
| Redirection | interdite. Sur 301, 302 ou 303, la requête est rejouée en GET, le contenu est perdu, et Ciklik enregistre un 200 trompeur |
| Certificat TLS | valide et émis par une autorité reconnue. Un certificat auto-signé fait échouer l’envoi sans laisser de trace |
| Ordre | non garanti. Un updated_* peut vous parvenir avant le created_* du même objet |
| Fraîcheur | le contenu est relu au moment de l’envoi, il peut être plus récent que l’événement. Seul changed décrit l’instant de l’événement |
| Contrat machine | /openapi/ciklik-webhooks.yaml |
Les 18 clés d’événement
Section intitulée « Les 18 clés d’événement »| Clé | Objet | Délai | Détail |
|---|---|---|---|
created_subscription | Abonnement | 0 s | Détail |
updated_subscription | Abonnement | 0 s | Détail |
deleted_subscription | Abonnement | 0 s | Détail |
updated_change_choices | Abonnement | 0 s | Détail |
created_shippingbox | Expédition | 0 s | Détail |
updated_shippingbox | Expédition | 0 s | Détail |
deleted_shippingbox | Expédition | 0 s | Détail |
created_checkoutorder | Commande | 10 s | Détail |
updated_checkoutorder | Commande | 0 s | Détail |
created_checkouttransaction | Transaction | 10 s | Détail |
updated_checkouttransaction | Transaction | 10 s | Détail |
created_checkoutinvoice | Facture | 15 s | Détail |
created_user | Client | 0 s | Détail |
updated_user | Client | 0 s | Détail |
created_address | Adresse | 0 s | Détail |
updated_address | Adresse | 0 s | Détail |
created_optin | Inscription marketing | 10 s | Détail |
updated_optin | Inscription marketing | 0 s | Détail |
updated_change_choices n’appartient pas aux 17 clés de l’API : elle n’est activable que par l’équipe Ciklik, voir Configurer les webhooks par l’API.
Ce que Ciklik n’envoie pas
Section intitulée « Ce que Ciklik n’envoie pas »- Pas de signature ni de secret partagé. L’URL de réception est le seul secret du dispositif.
- Pas de nom d’événement dans le contenu. Rien ne dit qu’il s’agit d’un
created_subscriptionplutôt que d’unupdated_user. - Pas d’identifiant d’envoi ni d’horodatage d’événement, donc aucune clé d’idempotence fournie.
- Aucun accusé de réception attendu. Le code de réponse renvoyé n’est pas analysé.
Le contenu de l’envoi
Section intitulée « Le contenu de l’envoi »Le corps est constitué des champs de l’objet concerné, à la racine, plus une clé changed. L’objet dépend de la clé d’événement : il est décrit champ par champ sur la page de référence correspondante (tableau ci-dessus). Voici le plus simple du catalogue, un created_optin, quatre champs et changed :
{ "email": "claire.martin@example.com", "tenant_id": 1, "valid": true, "list_id": "9f2c4e7a1b", "changed": []}Le champ changed
Section intitulée « Le champ changed »changed prend trois formes selon le type d’événement.
Un tableau JSON vide, pas un objet vide :
{ "changed": []}Un objet {colonne: nouvelle valeur}, fragment réel de updated_subscription.json :
{ "changed": { "next_billing": "2026-11-10 08:15:42", "end_date": "2026-11-09 21:59:59", "updated_at": "2026-09-10T08:15:42.000000Z" }}{ "changed": { "deleted": true }}Cinq règles à connaître avant d’exploiter changed :
- Ce sont des valeurs brutes de la base, pas les valeurs telles que l’API les renvoie ailleurs : dates au format
Y-m-d H:i:sen UTC sans fuseau, colonnes JSON sous forme de chaîne encodée, décimaux en chaîne. updated_atfigure danschangedsur presque toutes les modifications ; il n’est absent que si deux écritures tombent dans la même seconde.- Les noms de colonnes internes peuvent différer des noms de champs exposés ailleurs dans le contenu.
- Un envoi peut contenir des champs que vous n’avez pas modifiés vous-même, parce qu’un traitement interne a touché le même enregistrement au même moment.
- Ne faites jamais dépendre une décision métier de la seule présence d’une clé dans
changed: vérifiez aussi sa valeur.
Formats de données
Section intitulée « Formats de données »| Type | Format | Exemple |
|---|---|---|
| Dates | ISO 8601 UTC avec microsecondes et suffixe Z ; T00:00:00.000000Z pour une date sans heure | 2026-09-10T08:15:42.000000Z |
| Montants de commande | chaîne, virgule décimale (total_tax_paid, total_discount_inc, total_paid, total_shipping_paid) | "31,81" |
| Autres montants | chaîne, point décimal (revenue, customerRevenue, shipping) | "31.81" |
| Prix de ligne | nombre flottant (items[].price) | 29.9 |
| Compteurs de l’objet expédition | chaîne, alors que la valeur est numérique (subscriptions_count, shipped_count, orderable_id à la racine de l’expédition ; le shipped_count d’une formule ou d’un transporteur reste un entier) | "3" |
Objets à structure libre
Section intitulée « Objets à structure libre »Quatre endroits du contenu ne sont pas un contrat de champs et ne doivent pas être exploités au-delà de ce qui suit :
items[].orderable: reflet interne du produit ou de la formule, non contractuel. N’exploitez queid,name,priceetref.transporter.relayOptions: contenu variable selon le transporteur, non contractuel, à ignorer.invoice.customer: instantané des coordonnées client à l’émission de la facture, structure libre.invoice.company: instantané des coordonnées de votre société à l’émission de la facture, structure libre.
Délais, ordre et doublons
Section intitulée « Délais, ordre et doublons »Le délai dépend de la clé : 0, 10 ou 15 secondes (tableau des 18 clés). Ce n’est pas une garantie de fraîcheur, c’est l’inverse : le contenu est relu au moment où l’envoi part, pas au moment de l’événement. Entre les deux, l’objet a pu être modifié à nouveau. Seul changed décrit fidèlement l’instant de l’événement ; le reste du corps reflète l’état le plus récent connu au moment de l’envoi.
Aucun ordre n’est garanti : délais différents selon la clé et plusieurs envois pouvant être traités en parallèle, si bien qu’un updated_* peut arriver avant le created_* du même objet. Les doublons sont fréquents et normaux : écritures successives sur un même objet, cascades entre abonnement, expéditions et commandes, ou réponse trop lente qui déclenche un nouvel envoi alors que le premier est bien arrivé. Traitez ces cas comme la norme, voir Bonnes pratiques et dépannage pour la parade.
Cycle de vie d’un envoi
Section intitulée « Cycle de vie d’un envoi »Étape par étape :
événement dans votre boutique (création, modification ou suppression) -> résolution de l'URL déclarée (mise en cache 60 s) -> mise en file, délai de 0, 10 ou 15 s selon la clé -> POST vers votre URL de réception connexion : 10 s max, lecture de votre réponse : 30 s max -> échec de connexion (DNS, refus, délai, certificat) ? oui -> nouvelle tentative, jusqu'à 5 au total : 30 s entre les trois premières, puis les deux dernières enchaînées sans attente non -> code de réponse journalisé tel quel, aucune nouvelle tentative -> ligne journalisée dans la trace conservée 20 jours (sauf échec de connexion)Si votre boutique est PrestaShop
Section intitulée « Si votre boutique est PrestaShop »- Le mécanisme et le contenu des envois sont exactement les mêmes que pour une boutique Ciklik classique.
- Les abonnements portent en plus le champ
external_fingerprint, et les commandes le champprestashop_order_id. - Le passage d’une commande en demande de rétractation n’est jamais notifié : c’est volontaire côté PrestaShop.
- Le module PrestaShop dispose de son propre canal de synchronisation, distinct de ces webhooks marchands. Ne les confondez pas.
- Un jeton d’API est créé automatiquement pour les sites PrestaShop, voir Configurer les webhooks par l’API.
Voir aussi la rubrique PrestaShop.
Contrat lisible par une machine
Section intitulée « Contrat lisible par une machine »Le fichier /openapi/ciklik-webhooks.yaml décrit les 18 clés, les trois opérations de configuration et un exemple réel par clé. Chargez-le dans un client d’API, générez-en des types, ou donnez-le à un assistant de code pour qu’il écrive votre endpoint de réception.