Les webhooks Apenday envoient à votre système une notification à chaque étape de la vie d’un rendez-vous : prise, modification, annulation, clôture et enquête de satisfaction.
Les types d’événements #
| Événement | Envoyé quand |
|---|---|
meeting_confirmed | Un rendez-vous est pris |
meeting_updated | Le client modifie son rendez-vous, ou un conseiller ou un administrateur le déplace ou le réaffecte. Également envoyé quand les données personnelles du rendez-vous sont anonymisées |
meeting_cancelled | Le client annule son rendez-vous |
meeting_cancelled_by_consultant | Un conseiller ou un administrateur annule le rendez-vous, dans Apenday ou par l’API |
meeting_terminated | Le conseiller marque le rendez-vous comme terminé, dans Apenday ou par l’API |
meeting_missed | Le conseiller marque le rendez-vous comme manqué, dans Apenday ou par l’API |
meeting_rated | Le client renseigne l’enquête de satisfaction |
Un webhook porte sur un seul événement : souscrivez un webhook par événement à suivre. Chaque notification indique son événement dans l’en-tête X-Apenday-Event, une même URL peut donc recevoir plusieurs événements.
Souscrire à un webhook #
Souscrivez depuis le back-office, comme décrit dans Gérer vos webhooks depuis le back-office, ou par l’API REST (documentation de la ressource Hooks).
Par l’API, envoyez une requête POST sur https://app.apenday.com/api/public/hooks, authentifiée par votre clé d’API (voir Utiliser l’API Apenday) :
POST /api/public/hooks
Content-Type: application/json
X-AUTH-TOKEN: votre-cle-api
{
"url": "https://mydomain.com/url-a-notifier", // URL qui recevra les notifications
"event": "meeting_confirmed" // Événement à suivre
}
L’URL doit commencer par https:// et être accessible depuis Internet. Une URL en http:// ou pointant vers une adresse privée est refusée avec un code 422.
Exemple de réponse :
{
"@context": "/api/contexts/Hooks",
"@id": "/api/public/hooks/03a84931-3bb6-47b5-8323-336c236a6b93",
"@type": "Hooks",
"event": "meeting_confirmed",
"url": "https://mydomain.com/url-a-notifier",
"enabled": true, // false une fois le webhook désactivé
"signed": true, // Les notifications de ce webhook sont signées
"secret": "9f2c8a...4e71" // Secret de signature, renvoyé uniquement ici
}
Pour vous désabonner, envoyez une requête DELETE sur l’adresse donnée par la propriété @id de la réponse.
Le secret de signature #
Le champ secret de la réponse ci-dessus n’est renvoyé qu’une seule fois, par la requête qui vient de créer l’abonnement. Il n’apparaît dans aucune autre réponse de l’API et n’est plus consultable ensuite. Enregistrez-le dans votre système au moment où vous le recevez.
Il vous sert à vérifier que les notifications reçues viennent bien d’Apenday et que leur contenu n’a pas été modifié en chemin. La marche à suivre, avec un exemple de vérification complet en PHP et un en JavaScript, est détaillée ici : Vérifier la signature des notifications de rendez-vous.
Le format des notifications #
Chaque notification est une requête POST vers l’URL du webhook, avec les en-têtes suivants :
| En-tête | Contenu |
|---|---|
Content-Type | application/json |
X-Apenday-Event | L’événement, parmi les valeurs du tableau ci-dessus. Exemple : meeting_confirmed |
X-Apenday-Event-Id | Identifiant unique de l’événement, identique pour toutes les tentatives d’envoi et pour tous les webhooks qui reçoivent cet événement. Exemple : 3f6c1a2e-8d4b-4c7e-9a51-0b2e7d9c4f10 |
X-Apenday-Event-Timestamp | Moment de l’événement, en secondes écoulées depuis le 1er janvier 1970, en UTC. Identique pour toutes les tentatives d’envoi. Exemple : 1789479700 |
Un webhook signé ajoute les en-têtes X-Apenday-Timestamp et X-Apenday-Signature, décrits dans Vérifier la signature des notifications de rendez-vous.
Le corps porte l’état complet du rendez-vous au moment de l’envoi, et non les seuls champs modifiés. Son format est le même pour tous les événements :
{
"@context": "/api/contexts/Appointment",
"@id": "/api/public/appointments/XXXXX", // Adresse du rendez-vous dans l'API publique
"@type": "Appointment",
"id": "Identifiant_du_rendez-vous",
"meeting_id": "Identifiant_de_levenement",
"meeting_name": "Nom de l'évènement",
"meeting_technical_name": "Nom technique de l'évènement",
"meeting_type": "default", // default, call, video ou other
"status": "scheduled", // scheduled, cancelled, cancelled_by_consultant, terminated ou missed
"date": "2025-06-11T16:30:00+02:00", // date et heure de début
"end_date": "2025-06-11T17:15:00+02:00", // date et heure de fin
"consultants": [
{
"name": "Nom du conseiller",
"email": "Adresse email du conseiller",
"external_id": null // Votre identifiant de conseiller, s'il est renseigné
}
],
"customer_firstname": "Prénom du client", // "unknown" si le formulaire ne demande pas ce champ
"customer_lastname": "Nom du client",
"customer_email": "email du client",
"customer_phone_number": "numéro de téléphone",
"other_form_values": {
// ... autres valeurs du formulaire, puis :
"createdAt": "2025-06-01T08:12:00+00:00", // Création du rendez-vous, en UTC
"updatedAt": "2025-06-02T06:45:00+00:00" // Dernière mise à jour du rendez-vous, en UTC
},
"agency_name": "Nom de l'agence",
"agency_id": null, // Identifiant Apenday de l'agence
"agency_external_id": null, // Identifiant de l'agence dans votre système
"agency_crm_id": null, // Identifiant de l'agence dans votre CRM
"satisfaction_score": null, // Note de l'enquête de satisfaction
"satisfaction_comment": null, // Commentaire de l'enquête de satisfaction
"utm_campain": null, // Paramètres UTM
"utm_source": null, // Paramètres UTM
"utm_medium": null, // Paramètres UTM
"tags": [], // Libellés des tags posés sur le rendez-vous
"front_actions": {
// URLs des pages publiques du rendez-vous, voir ci-dessous
}
}
Le contenu de front_actions #
Ce bloc rassemble les URLs des pages publiques du rendez-vous. Les clés présentes varient selon l’état du rendez-vous et le type d’évènement : ne considérez aucune d’elles comme garantie, et testez sa présence avant de l’utiliser.
| Clé | Présente quand |
|---|---|
cancel | Le rendez-vous est encore annulable |
update | Le rendez-vous est encore modifiable |
survey | Le rendez-vous peut être évalué |
download_ics | Le rendez-vous est au statut scheduled |
video_url_user | Le rendez-vous est une visio au statut scheduled : lien de la visio pour le client |
video_url_consultant | Le rendez-vous est une visio au statut scheduled, selon le paramétrage de l’événement : lien de la visio pour le conseiller |
Le bloc front_actions est entièrement absent de la charge quand aucune action n’est disponible, ce qui est notamment le cas d’un rendez-vous passé. Ne comptez donc pas non plus sur la présence de la clé elle-même.
Répondre à une notification #
Répondez par un code 2xx. Apenday attend la réponse 10 secondes au plus sans activité, et 15 secondes au total : enregistrez la notification, répondez, puis traitez-la.
| Réponse de votre système | Effet |
|---|---|
2xx | Notification délivrée |
410 Gone | Le webhook est désactivé. Il reste visible dans le back-office, où il se réactive, et une nouvelle souscription du même compte au même événement sur la même URL le réactive aussi |
5xx, 408, 429, ou aucune réponse | Nouvelle tentative 1 minute, puis 5 minutes, puis 25 minutes après l’échec précédent. Au-delà, la notification est abandonnée |
Tout autre code, redirection 3xx comprise | Échec enregistré sur le webhook, sans nouvelle tentative. Les redirections ne sont pas suivies |
Une notification peut arriver deux fois, par exemple si votre système la traite mais répond trop tard. Dédoublonnez sur X-Apenday-Event-Id, identique pour toutes les tentatives d’un même événement.
Les notifications ne sont pas garanties dans l’ordre. Pour un même rendez-vous, identifié par le champ id, ignorez une notification dont X-Apenday-Event-Timestamp est antérieur à celui de la dernière notification traitée. Cet horodatage est précis à la seconde : en cas d’égalité, relisez le rendez-vous par l’API publique, à l’adresse donnée par @id.
Une relance porte l’état courant du rendez-vous. Le corps est relu à chaque tentative et non figé au moment de l’événement. Une confirmation relancée après une annulation porte donc le statut cancelled, alors que X-Apenday-Event vaut meeting_confirmed.
Modifier l’URL ou l’événement d’un webhook abandonne les envois en attente. Si vous corrigez l’URL alors qu’une relance est programmée, cette relance n’a pas lieu. Vérifiez les rendez-vous de la période concernée par l’API publique si vous suspectez un manque.
