Langue: Français
Une étape Webhook envoie une requête HTTP à un système externe chaque fois que le flux l'atteint. Les webhooks sont le pont entre ActivityInfo et d'autres outils : des plateformes de flux de travail telles que Power Automate, Zapier, n8n ou Pipedream, des outils de discussion comme Google Chat ou Slack, ou vos propres services.
Configuration
| Paramètre | Description ||-----------|-------------|| Étiquette | Le nom de l'étape, affiché dans le flux et dans l'historique d'exécution. | | URL du webhook | L'URL à laquelle la requête est envoyée. Doit être une URL https://. | | Format de la charge utile | La forme du corps de la requête : Compatible ActivityInfo 4.0, Standard, ou Personnalisé. | | Secret de signature | Facultatif. Lorsqu'il est généré, chaque requête est signée afin que le destinataire puisse la vérifier. Voir Signature. |
Livraison
La requête est un POST HTTP avec Content-type: application/json. Les délais d'attente de connexion et de lecture sont de 15 secondes et les redirections ne sont pas suivies. Une réponse avec un code de statut 2xx marque l'étape comme réussie ; toute autre réponse, ou un échec de connexion, entraîne une nouvelle tentative de livraison.
Toutes les requêtes portent ces en-têtes, suivant la convention standard-webhooks :
| En-tête | Valeur ||---------|--------|| webhook-id | Un ID unique pour l'événement, par ex. msg_cfbin3msbq939jk. Les nouvelles tentatives du même événement portent le même ID, afin que les destinataires puissent dédupliquer. | | webhook-timestamp | L'heure d'envoi, en secondes depuis l'epoch. | | webhook-signature | Présent lorsqu'un secret de signature a été généré. Voir Signature. |
Signature
Générer un secret de signature permet au système récepteur de vérifier qu'une requête provient bien d'ActivityInfo et n'a pas été altérée. La signature suit le schéma symétrique de standard-webhooks :
webhook-signature: v1,<base64 HMAC-SHA256 of "{webhook-id}.{webhook-timestamp}.{body}">
La signature est calculée sur les octets exacts du corps de la requête, quel que soit le format de la charge utile. Le secret est affiché une seule fois lors de sa génération — copiez-le dans le système récepteur à ce moment-là. La modification de l'URL du webhook efface le secret ; enregistrez d'abord la nouvelle URL, puis générez un nouveau secret pour celle-ci.
Formats de la charge utile
Les exemples ci-dessous proviennent tous du même événement : un enregistrement dans un formulaire Enregistrement du patient a été modifié, changeant le champ Statut de « En traitement » à « Récupéré ». Les champs du formulaire portent des codes (NAME, AGE, STATUS, ...) — nous vous recommandons vivement d'attribuer des codes à vos champs, car ils identifient les champs dans les charges utiles et les modèles ci-dessous de manière beaucoup plus lisible que les ID de champ, et survivent au changement d'étiquette.
Le formulaire a un champ de chaque type courant : un numéro de série (NUMBER), un texte (NAME), une quantité (AGE), une date (REGDATE), un mois (MONTH), une semaine (WEEK), une sélection unique (STATUS), une sélection multiple (SYMPTOMS), une référence à un formulaire Clinique (CLINIC), une référence multiple (NEARBY), un point géographique (LOCATION), et un champ calculé (ADULT).
Compatible ActivityInfo 4.0
Le format de charge utile exact des webhooks d'ActivityInfo 4.0, conservé pour les intégrations construites dessus — y compris le connecteur Power Automate. Les automatisations migrées depuis la version 4.0, et les connexions effectuées via Power Automate, utilisent ce format ; les nouvelles étapes de webhook utilisent par défaut le format Standard. Voir Des webhooks d'ActivityInfo 4.0 aux automatisations pour le contexte.
Le corps décrit l'événement : data.update ne contient que les champs modifiés par l'événement (tous les champs pour un enregistrement ajouté), tandis que data.previous — présent pour les modifications et les suppressions — est l'état complet de l'enregistrement stocké avant la modification. Les champs sont indexés par code (ou ID de champ lorsque le champ n'a pas de code). Le type de l'événement est record.added, record.edited, ou record.deleted.
Parce que le corps est construit à partir des valeurs stockées de l'enregistrement, les champs calculés ne sont pas inclus — ils sont calculés à la lecture, non stockés, et n'apparaissent donc jamais dans ce format. Un consommateur qui a besoin d'une valeur calculée doit soit la recalculer, soit utiliser le format Standard ou Personnalisé, qui évaluent les champs calculés comme n'importe quel autre.
{
"type": "record.edited",
"timestamp": "2026-08-02 13:30:00 +0200",
"id": "cfbin3msbq939jk",
"data": {
"update": {
"formId": "cabwlbemsbq938l5",
"formLabel": "Enregistrement du patient",
"recordId": "cuusah2msbq938xi",
"parent": null,
"deleted": false,
"time": "2026-08-02 13:30:00 +0200",
"fields": {
"STATUS": "Récupéré"
}
},
"previous": {
"formId": "cabwlbemsbq938l5",
"formLabel": "Enregistrement du patient",
"recordId": "cuusah2msbq938xi",
"parent": null,
"time": "2026-07-30 11:00:00 +0200",
"fields": {
"NAME": "Amina Yusuf",
"AGE": 34,
"REGDATE": "2026-07-30",
"MONTH": "2026-07",
"WEEK": "2026W31",
"STATUS": "En traitement",
"SYMPTOMS": ["Fièvre", "Toux"],
"CLINIC": {
"reference": {
"recordId": "cfw5r5dmsbq938vh",
"formId": "cprk1xdmsbq93893"
}
},
"LOCATION": {
"latitude": 0.9432,
"longitude": 29.2154
}
}
},
"user": {
"userName": "Amara Diallo",
"userEmail": "amara.diallo@example.org",
"userId": "ci5dxvbkq1v6ueg2"
}
}
}
Valeurs des champs dans ce format :
| Type de champ | Valeur ||---------------|--------|| Texte, numéro de série, code-barres | Texte | | Quantité | Nombre | | Date, semaine, mois | Texte, par ex. "2026-07-30", "2026W31", "2026-07" | | Sélection unique | Le code de l'option si elle en a un, son étiquette sinon | | Sélection multiple | Tableau de codes/étiquettes d'option, dans l'ordre des options du formulaire | | Référence | {"reference": {"recordId": ..., "formId": ...}} | | Référence multiple | Tableau de chaînes "formId:recordId" | | Point géographique | {"latitude": ..., "longitude": ...} | | Pièces jointes | Tableau de {"filename": ..., "mimetype": ..., "url": ...} avec une URL de téléchargement | | Calculé | Non inclus — les champs calculés sont calculés à la lecture, non stockés |
Pour une suppression (record.deleted), update.deleted est true, update.fields est vide, et previous contient le dernier état de l'enregistrement. Les enregistrements de sous-formulaire contiennent un objet parent avec parentRecordId, parentFormId, et parentFormLabel à la place de null.
Standard
Les données d'étape du déclencheur sérialisées en JSON — la même ligne unique, présentée exactement comme les formules la voient. Chaque champ du formulaire est présent à chaque événement (les champs vides sont null, de sorte que la forme de la charge utile est stable), indexé par code de champ (ou étiquette lorsque le champ n'a pas de code). Les structures _previous, _user, et _trigger apparaissent sous les mêmes noms réservés que ceux utilisés par les formules.
{
"_id": "cuusah2msbq938xi",
"NUMBER": null,
"NAME": "Amina Yusuf",
"AGE": 34,
"REGDATE": "2026-07-30",
"MONTH": "2026-07",
"WEEK": "2026W31",
"STATUS": {
"_id": "s2",
"label": "Récupéré"
},
"SYMPTOMS": [
{ "_id": "y1", "label": "Fièvre" },
{ "_id": "y2", "label": "Toux" }
],
"CLINIC": {
"_id": "cfw5r5dmsbq938vh",
"label": "Poste de santé de Mangina"
},
"NEARBY": [
{ "_id": "cfw5r5dmsbq938vh", "label": "Poste de santé de Mangina" },
{ "_id": "c7ptg4xmsbq938wj", "label": "Hôpital de référence de Beni" }
],
"LOCATION": {
"LATITUDE": 0.9432,
"LONGITUDE": 29.2154,
"ACCURACY": null
},
"ADULT": true,
"_lastEditTime": "2026-08-02T11:30:00Z",
"_previous": {
"_id": "cuusah2msbq938xi",
"NUMBER": null,
"NAME": "Amina Yusuf",
"AGE": 34,
"REGDATE": "2026-07-30",
"MONTH": "2026-07",
"WEEK": "2026W31",
"STATUS": {
"_id": "s1",
"label": "En traitement"
},
"SYMPTOMS": [
{ "_id": "y1", "label": "Fièvre" },
{ "_id": "y2", "label": "Toux" }
],
"CLINIC": {
"_id": "cfw5r5dmsbq938vh",
"label": "Poste de santé de Mangina"
},
"NEARBY": [
{ "_id": "cfw5r5dmsbq938vh", "label": "Poste de santé de Mangina" },
{ "_id": "c7ptg4xmsbq938wj", "label": "Hôpital de référence de Beni" }
],
"LOCATION": {
"LATITUDE": 0.9432,
"LONGITUDE": 29.2154,
"ACCURACY": null
},
"ADULT": true,
"_lastEditTime": "2026-07-30T09:00:00Z"
},
"_user": {
"name": "Amara Diallo",
"email": "amara.diallo@example.org",
"id": "ci5dxvbkq1v6ueg2"
},
"_trigger": {
"type": "RECORD_EDITED",
"time": "2026-08-02T11:30:00Z"
}
}
Valeurs des champs dans ce format :
| Type de champ | Valeur ||---------------|--------|| Texte, numéro de série, code-barres | Texte, null si vide | | Quantité | Nombre | | Date, semaine, mois | Texte, par ex. "2026-07-30", "2026W31", "2026-07" | | Sélection unique | {"_id": <id de l'option>, "label": <étiquette de l'option>} | | Sélection multiple | Tableau d'objets {"_id", "label"} | | Référence | {"_id": <id de l'enregistrement>, "label": <libellé d'enregistrement>} — le même libellé lisible par l'homme que l'enregistrement a dans toute l'application | | Référence multiple | Tableau d'objets {"_id", "label"} | | Point géographique | {"LATITUDE", "LONGITUDE", "ACCURACY"} | | Pièces jointes | Tableau d'objets {"_id", "filename", "mimetype"} | | Calculé | Le résultat de la formule | | Valeurs de date et d'heure (_lastEditTime, _trigger.time) | ISO-8601 UTC, par ex. "2026-08-02T11:30:00Z" |
_previous n'est présent que pour le déclencheur de modification ; les entrées _user sont null pour les modifications non attribuables à un utilisateur.
Personnalisé
Vous écrivez vous-même le corps de la requête, sous forme de modèle avec des références ${...} — les mêmes références que celles utilisées par les modèles de l'étape d'e-mail, évaluées par rapport aux données d'étape du déclencheur. C'est le format à utiliser lorsque le système récepteur dicte la forme du corps, comme pour publier un message directement dans un espace Google Chat :
{"text": "Le patient ${NAME} à ${CLINIC.NAME} est maintenant ${STATUS} (était ${_previous.STATUS}), mis à jour par ${_user.name}"}
produit :
{"text": "Le patient Amina Yusuf à Poste de santé de Mangina est maintenant Récupéré (était En traitement), mis à jour par Amara Diallo"}
Une référence peut être un code de champ, une navigation à travers un champ de référence, une entrée _previous/_user/_trigger, ou n'importe quelle formule — le langage de formule complet est disponible en ligne :
{"text": "Patient ${NAME} (${IF(AGE >= 18, 'adulte', 'mineur')}, âge ${AGE}) est maintenant ${STATUS}"}
produit :
{"text": "Patient Amina Yusuf (adulte, âge 34) est maintenant Récupéré"}
Utilisez des guillemets simples pour le texte à l'intérieur d'une formule en ligne, comme dans IF(AGE >= 18, 'adulte', 'mineur') — le langage de formule accepte les deux styles de guillemets, et les guillemets simples gardent le modèle JSON environnant lisible.
Les valeurs interpolées sont automatiquement échappées en JSON : les guillemets, les barres obliques inverses et les sauts de ligne dans vos données arrivent sous la forme \", \\, et \n, de sorte qu'un modèle qui est un document JSON reste un JSON valide quel que soit le contenu des données. Tout ce qui se trouve en dehors de ${...} est envoyé exactement tel quel — y compris les séquences de barres obliques inverses comme \n que vous tapez vous-même — et une référence ${...} qui ne peut être résolue est laissée telle quelle.
L'éditeur de modèle valide chaque référence ${...} par rapport aux données d'étape du déclencheur et offre la même liste de champs cliquable que les étapes de filtre et d'e-mail.