Les webhooks TAP4BOOK permettent de recevoir des notifications HTTP en temps réel pour les événements importants du système de gestion de rendez-vous.
Notifications instantanées lors des événements
Signatures HMAC-SHA256
API, Widget, MyBooking, Console
La configuration de l'url webhook devant recevoir les évènements se fait exclusivement via l'interface de gestion TAP4BOOK.
index.php?page=account)Testez votre webhook avec un payload d'exemple
Visualisez les métriques des 30 derniers jours
Consultez l'historique des envois
Une fois configuré, votre webhook recevra :
| Événement | Sources | Description | Données Incluses |
|---|---|---|---|
appointment.created |
API Widget | Un nouveau rendez-vous a été créé par un visiteur | appointment, client |
appointment.updated |
API MyBooking Console | Un rendez-vous a été modifié | appointment, client, changes |
appointment.cancelled |
API MyBooking Console | Un rendez-vous a été annulé | appointment, client, reason |
appointment.completed |
API Console | Un rendez-vous a été marqué comme terminé | appointment, client |
appointment.deleted |
API Console | Un rendez-vous a été supprimé | appointment, client, reason |
appointment.no_show |
API Console | Client absent au rendez-vous | appointment, client |
widget.newvisitor |
Widget | Nouveau visiteur détecté sur widget (notification immédiate) | visitor (avec tous les tags) |
widget.visitornoappointment |
Widget | Visiteur n'a pas pris de rendez-vous avant le timeout | visitor (avec tous les tags) |
widget.visitorconverted |
Widget | Visiteur a pris un rendez-vous (conversion réussie) | visitor, appointment, client |
client.created |
API Widget Console | Un nouveau client a été ajouté | client |
Tous les webhooks TAP4BOOK suivent cette structure standardisée :
{
"event": "appointment.created",
"event_id": "evt_684305a64d0ce3.39098263",
"timestamp": "2025-06-06T14:30:00+00:00",
"api_version": "2.0",
"source": "API|Widget|MyBooking|Console",
"entity": {
"entity_id": 5,
"entity_name": "Cabinet Dr. Martin",
"entity_account_id": "account_abc123"
},
"data": {
// Données spécifiques à l'événement
},
"signature": "sha256_hmac_signature_here"
}
| Champ | Type | Description |
|---|---|---|
event |
string | Type d'événement (voir liste ci-dessus) |
event_id |
string | Identifiant unique de l'événement (pour déduplication) |
timestamp |
string | Horodatage ISO 8601 de l'événement |
api_version |
string | Version du format webhook (actuellement "2.0") |
source |
string | Origine de l'événement : API, Widget, MyBooking, Console |
entity |
object | Informations sur l'entité (cabinet, entreprise) |
data |
object | Données spécifiques à l'événement |
signature |
string | Signature HMAC-SHA256 pour validation |
L'objet client inclut maintenant de nombreux champs personnalisés :
| Champ | Type | Description |
|---|---|---|
client_id / id |
integer | Identifiant unique du client |
entity_id |
integer | Identifiant de l'entité propriétaire |
first_name |
string | Prénom du client |
last_name |
string | Nom de famille du client |
name |
string | Nom complet (prénom + nom) |
email |
string | Adresse email |
phone |
string | Numéro de téléphone au format E164 (sans le +) |
tag1 à tag10 |
string|null | Champs personnalisés libres pour étiqueter les clients |
optin |
integer | Consentement marketing (0 = non, 1 = oui) |
ip_address |
string | Adresse IP de création (peut être masquée selon la configuration) |
created_at |
string | Date de création du client |
updated_at |
string | Date de dernière modification |
L'objet appointment inclut maintenant le champ timezone :
| Champ | Type | Description |
|---|---|---|
timezone |
string | Timezone utilisée pour start_time et end_time (ex: "Europe/Paris") |
TAP4BOOK offre une fonctionnalité de masquage automatique des données sensibles dans les webhooks pour assurer la conformité RGPD et protéger la vie privée des clients.
Pour activer le masquage des données :
mask_clientsDataLorsque le masquage est activé, les champs suivants sont automatiquement masqués :
email : "marie.dupont@XXX.XXX" (préserve le nom utilisateur)client_email : "marie.dupont@XXX.XXX"phone : "336123XXXX" (masque les 4 derniers chiffres)client_phone : "336123XXXX"ip_address : "xx.xx.xx.xx" (masque complètement l'IP)Depuis la version 2.1 de l'API, les webhooks incluent un objet status_details qui fournit des informations enrichies sur le statut du rendez-vous, incluant les labels personnalisés configurés pour votre entité.
Important : Cette information est additionnelle et n'affecte pas le champ status existant pour garantir la rétrocompatibilité.
"status_details": {
"key": "pending", // Identifiant technique (identique au champ status)
"label": "En attente", // Libellé personnalisé ou par défaut
"color": "#FFA500", // Code couleur hexadécimal
"type": "pending", // Type métier : pending, confirmed, completed, cancelled
"is_custom": false, // true si c'est un statut personnalisé
"scope": "default" // Portée : default, global, entity, calendar
}
{
"status": "pending",
"status_details": {
"key": "pending",
"label": "En attente",
"color": "#FFA500",
"type": "pending",
"is_custom": false,
"scope": "default"
}
}
{
"status": "en_validation",
"status_details": {
"key": "en_validation",
"label": "En cours de validation",
"color": "#FF9800",
"type": "pending",
"is_custom": true,
"scope": "entity"
}
}
timestamp : Toujours en UTC au format ISO 8601start_time et end_time : Dans la timezone du calendriertimezone : Timezone utilisée pour les heures du rendez-vous{
"event": "appointment.created",
"event_id": "evt_684305a64d0ce3.39098263",
"timestamp": "2025-06-06T14:30:00+00:00",
"api_version": "2.0",
"source": "API",
"entity": {
"entity_id": 5,
"entity_name": "Cabinet Dr. Martin",
"entity_account_id": "account_abc123"
},
"data": {
"appointment": {
"appointment_id": 789,
"client_firstName": "Marie",
"client_lastName": "Dupont",
"client_name": "Marie Dupont",
"client_email": "marie.dupont@example.com",
"client_phone": "33612345678",
"contract_number": "",
"date": "2025-06-11",
"start_time": "16:00:00",
"end_time": "17:00:00",
"entity_id": 5,
"calendar_id": 15,
"clientCancel_option": 1,
"client_id": "123",
"cancel_token": "a1b2c3d4e5f6789abcdef123456789",
"tags": {
"tag8": "campaign_source",
"tag9": "widget_conversion"
},
"newClientCreated": true,
"timezone": "Europe/Paris"
},
"client": {
"id": 123,
"entity_id": 5,
"name": "Marie Dupont",
"firstName": "Marie",
"lastName": "Dupont",
"phone": "33612345678",
"email": "marie.dupont@example.com",
"tag1": "VIP",
"tag2": "Urgence",
"tag3": null,
"tag4": null,
"tag5": null,
"tag6": null,
"tag7": null,
"tag8": "campaign_source",
"tag9": "widget_conversion",
"tag10": null,
"optin": true,
"ip_address": "192.168.1.100",
"created_at": "2025-06-06 14:30:00",
"updated_at": "2025-06-06 14:30:00"
}
}
}
{
"event": "appointment.created",
"event_id": "evt_684305a64d0ce3.39098263",
"timestamp": "2025-06-06T14:30:00+00:00",
"api_version": "2.0",
"source": "API",
"entity": {
"entity_id": 5,
"entity_name": "Cabinet Dr. Martin",
"entity_account_id": "account_abc123"
},
"data": {
"appointment": {
"appointment_id": 789,
"client_firstName": "Marie",
"client_lastName": "Dupont",
"client_name": "Marie Dupont",
"client_email": "marie.dupont@XXX.XXX",
"client_phone": "336123XXXX",
"contract_number": "",
"date": "2025-06-11",
"start_time": "16:00:00",
"end_time": "17:00:00",
"entity_id": 5,
"calendar_id": 15,
"clientCancel_option": 1,
"client_id": "123",
"cancel_token": "a1b2c3d4e5f6789abcdef123456789",
"tags": {
"tag8": "campaign_source",
"tag9": "widget_conversion"
},
"newClientCreated": true,
"timezone": "Europe/Paris"
},
"client": {
"id": 123,
"entity_id": 5,
"name": "Marie Dupont",
"firstName": "Marie",
"lastName": "Dupont",
"phone": "336123XXXX",
"email": "marie.dupont@XXX.XXX",
"tag1": "VIP",
"tag2": "Urgence",
"tag3": null,
"tag4": null,
"tag5": null,
"tag6": null,
"tag7": null,
"tag8": "campaign_source",
"tag9": "widget_conversion",
"tag10": null,
"optin": true,
"ip_address": "xx.xx.xx.xx",
"created_at": "2025-06-06 14:30:00",
"updated_at": "2025-06-06 14:30:00"
}
}
}
appointment.client_email : "marie.dupont@example.com" → "marie.dupont@XXX.XXX"appointment.client_phone : "33612345678" → "336123XXXX"client.email : "marie.dupont@example.com" → "marie.dupont@XXX.XXX"client.phone : "33612345678" → "336123XXXX"client.ip_address : "192.168.1.100" → "xx.xx.xx.xx"{
"event": "appointment.updated",
"event_id": "evt_684306a64d1ce4.40098264",
"timestamp": "2025-06-06T15:00:00+00:00",
"api_version": "2.0",
"source": "Console",
"entity": {
"entity_id": 5,
"entity_name": "Cabinet Dr. Martin",
"entity_account_id": "account_abc123"
},
"data": {
"appointment": {
"appointment_id": 789,
"entity_id": 5,
"calendar_id": 15,
"slot_id": 457,
"client_id": 123,
"date": "2025-06-05",
"start_time": "09:00:00",
"end_time": "10:00:00",
"status": "confirmed",
"status_details": {
"key": "confirmed",
"label": "Confirmé",
"color": "#0FA66C",
"type": "confirmed",
"is_custom": false,
"scope": "default"
},
"notes": "Première consultation - reportée",
"timezone": "Europe/Paris"
},
"client": {
"client_id": 123,
"id": 123,
"entity_id": 5,
"first_name": "Marie",
"last_name": "Dupont",
"name": "Marie Dupont",
"email": "marie.dupont@example.com",
"phone": "33612345678",
"tag1": "VIP",
"tag2": "Urgence",
"tag3": null,
"tag4": null,
"tag5": null,
"tag6": null,
"tag7": null,
"tag8": null,
"tag9": null,
"tag10": null,
"optin": 1,
"ip_address": "192.168.1.100",
"created_at": "2025-01-15 10:30:00",
"updated_at": "2025-06-06 15:00:00"
},
"changes": {
"status": {"from": "pending", "to": "confirmed"},
"date": {"from": "2025-06-04", "to": "2025-06-05"},
"start_time": {"from": "16:00:00", "to": "09:00:00"},
"slot_id": {"from": 456, "to": 457}
}
},
"signature": "b2c3d4e5f6g789abcdef123456789..."
}
{
"event": "appointment.cancelled",
"event_id": "evt_684307a64d2ce5.41098265",
"timestamp": "2025-06-06T15:30:00+00:00",
"api_version": "2.0",
"source": "MyBooking",
"entity": {
"entity_id": 5,
"entity_name": "Cabinet Dr. Martin",
"entity_account_id": "account_abc123"
},
"data": {
"appointment": {
"appointment_id": 789,
"entity_id": 5,
"calendar_id": 15,
"slot_id": 457,
"client_id": 123,
"date": "2025-06-05",
"start_time": "09:00:00",
"end_time": "10:00:00",
"status": "cancelled",
"status_details": {
"key": "cancelled",
"label": "Annulé",
"color": "#FF0000",
"type": "cancelled",
"is_custom": false,
"scope": "default"
},
"notes": "Première consultation - reportée",
"timezone": "Europe/Paris"
},
"client": {
"client_id": 123,
"id": 123,
"entity_id": 5,
"first_name": "Marie",
"last_name": "Dupont",
"name": "Marie Dupont",
"email": "marie.dupont@example.com",
"phone": "33612345678",
"tag1": "VIP",
"tag2": "Urgence",
"tag3": null,
"tag4": null,
"tag5": null,
"tag6": null,
"tag7": null,
"tag8": null,
"tag9": null,
"tag10": null,
"optin": 1,
"ip_address": "192.168.1.100",
"created_at": "2025-01-15 10:30:00",
"updated_at": "2025-06-06 15:30:00"
},
"reason": "Cancelled by client via MyBooking"
},
"signature": "c3d4e5f6g789abcdef123456789..."
}
{
"event": "appointment.completed",
"event_id": "evt_684308a64d3ce6.42098266",
"timestamp": "2025-06-06T16:00:00+00:00",
"api_version": "2.0",
"source": "Console",
"entity": {
"entity_id": 5,
"entity_name": "Cabinet Dr. Martin",
"entity_account_id": "account_abc123"
},
"data": {
"appointment": {
"appointment_id": 789,
"entity_id": 5,
"calendar_id": 15,
"slot_id": 457,
"client_id": 123,
"date": "2025-06-05",
"start_time": "09:00:00",
"end_time": "10:00:00",
"status": "completed",
"status_details": {
"key": "completed",
"label": "Terminé",
"color": "#00FF00",
"type": "completed",
"is_custom": false,
"scope": "default"
},
"notes": "Consultation terminée avec succès",
"timezone": "Europe/Paris"
},
"client": {
"client_id": 123,
"id": 123,
"entity_id": 5,
"first_name": "Marie",
"last_name": "Dupont",
"name": "Marie Dupont",
"email": "marie.dupont@example.com",
"phone": "33612345678",
"tag1": "VIP",
"tag2": "Urgence",
"tag3": null,
"tag4": null,
"tag5": null,
"tag6": null,
"tag7": null,
"tag8": null,
"tag9": null,
"tag10": null,
"optin": 1,
"ip_address": "192.168.1.100",
"created_at": "2025-01-15 10:30:00",
"updated_at": "2025-06-06 16:00:00"
}
},
"signature": "d4e5f6g789abcdef123456789..."
}
{
"event": "appointment.deleted",
"event_id": "evt_684309a64d4ce7.43098267",
"timestamp": "2025-06-06T16:30:00+00:00",
"api_version": "2.0",
"source": "API",
"entity": {
"entity_id": 5,
"entity_name": "Cabinet Dr. Martin",
"entity_account_id": "account_abc123"
},
"data": {
"appointment": {
"appointment_id": 789,
"entity_id": 5,
"calendar_id": 15,
"slot_id": 457,
"client_id": 123,
"date": "2025-06-05",
"start_time": "09:00:00",
"end_time": "10:00:00",
"status": "deleted",
"status_details": {
"key": "deleted",
"label": "Supprimé",
"color": "#666666",
"type": null,
"is_custom": false,
"scope": "default"
},
"notes": "Consultation supprimée",
"timezone": "Europe/Paris"
},
"client": {
"client_id": 123,
"id": 123,
"entity_id": 5,
"first_name": "Marie",
"last_name": "Dupont",
"name": "Marie Dupont",
"email": "marie.dupont@example.com",
"phone": "33612345678",
"tag1": "VIP",
"tag2": "Urgence",
"tag3": null,
"tag4": null,
"tag5": null,
"tag6": null,
"tag7": null,
"tag8": null,
"tag9": null,
"tag10": null,
"optin": 1,
"ip_address": "192.168.1.100",
"created_at": "2025-01-15 10:30:00",
"updated_at": "2025-06-06 16:30:00"
},
"reason": "Deleted via API"
},
"signature": "e5f6g789abcdef123456789..."
}
{
"event": "appointment.no_show",
"event_id": "evt_684310a64d5ce8.44098268",
"timestamp": "2025-06-06T17:00:00+00:00",
"api_version": "2.0",
"source": "Console",
"entity": {
"entity_id": 5,
"entity_name": "Cabinet Dr. Martin",
"entity_account_id": "account_abc123"
},
"data": {
"appointment": {
"appointment_id": 789,
"entity_id": 5,
"calendar_id": 15,
"slot_id": 457,
"client_id": 123,
"date": "2025-06-05",
"start_time": "09:00:00",
"end_time": "10:00:00",
"status": "no_show",
"status_details": {
"key": "no_show",
"label": "Absent",
"color": "#9C27B0",
"type": null,
"is_custom": false,
"scope": "default"
},
"notes": "Client absent - consultation manquée",
"timezone": "Europe/Paris"
},
"client": {
"client_id": 123,
"id": 123,
"entity_id": 5,
"first_name": "Marie",
"last_name": "Dupont",
"name": "Marie Dupont",
"email": "marie.dupont@example.com",
"phone": "33612345678",
"tag1": "VIP",
"tag2": "Urgence",
"tag3": null,
"tag4": null,
"tag5": null,
"tag6": null,
"tag7": null,
"tag8": null,
"tag9": null,
"tag10": null,
"optin": 1,
"ip_address": "192.168.1.100",
"created_at": "2025-01-15 10:30:00",
"updated_at": "2025-06-06 17:00:00"
}
},
"signature": "f6g789abcdef123456789..."
}
{
"event": "client.created",
"event_id": "evt_684310a64d5ce8.44098268",
"timestamp": "2025-06-06T17:00:00+00:00",
"api_version": "2.0",
"source": "Widget",
"entity": {
"entity_id": 5,
"entity_name": "Cabinet Dr. Martin",
"entity_account_id": "account_abc123"
},
"data": {
"client": {
"client_id": 124,
"id": 124,
"entity_id": 5,
"first_name": "Jean",
"last_name": "Martin",
"name": "Jean Martin",
"email": "jean.martin@example.com",
"phone": "33698765432",
"tag1": "Nouveau",
"tag2": null,
"tag3": null,
"tag4": null,
"tag5": null,
"tag6": null,
"tag7": null,
"tag8": null,
"tag9": null,
"tag10": null,
"optin": 1,
"ip_address": "192.168.1.101",
"created_at": "2025-06-06 17:00:00",
"updated_at": "2025-06-06 17:00:00"
}
},
"signature": "f6g789abcdef123456789..."
}
{
"event": "widget.newvisitor",
"event_id": "evt_684311a64d6ce9.45098269",
"timestamp": "2025-06-06T17:30:00+00:00",
"api_version": "2.0",
"source": "Widget",
"entity": {
"entity_id": 5,
"entity_name": "Cabinet Dr. Martin",
"entity_account_id": "account_abc123"
},
"data": {
"visitor": {
"entity_id": 5,
"widget_id": "644660339401",
"tracking_id": 458,
"ip_address": "192.168.1.100",
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)...",
"visit_timestamp": "2025-06-06T17:30:00+00:00",
"status": "tracking",
"tag1": null,
"tag2": null,
"tag3": null,
"tag4": null,
"tag5": null,
"tag6": null,
"tag7": null,
"tag8": "external_client_123",
"tag9": "campaign_step_1",
"tag10": null
}
},
"signature": "g789abcdef123456789..."
}
{
"event": "widget.visitornoappointment",
"event_id": "evt_684312a64d7cea.46098270",
"timestamp": "2025-06-06T18:00:00+00:00",
"api_version": "2.0",
"source": "Widget",
"entity": {
"entity_id": 5,
"entity_name": "Cabinet Dr. Martin",
"entity_account_id": "account_abc123"
},
"data": {
"visitor": {
"entity_id": 5,
"widget_id": "644660339401",
"tracking_id": 458,
"ip_address": "192.168.1.100",
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)...",
"first_visit_at": "2025-06-06T17:30:00+00:00",
"timeout_at": "2025-06-06T18:00:00+00:00",
"status": "timeout_no_conversion",
"tag1": null,
"tag2": null,
"tag3": null,
"tag4": null,
"tag5": null,
"tag6": null,
"tag7": null,
"tag8": "external_client_123",
"tag9": "campaign_step_1",
"tag10": null
}
},
"signature": "h789abcdef123456789..."
}
{
"event": "widget.visitorconverted",
"event_id": "evt_684313a64d8ceb.47098271",
"timestamp": "2025-06-06T17:45:00+00:00",
"api_version": "2.0",
"source": "Widget",
"entity": {
"entity_id": 5,
"entity_name": "Cabinet Dr. Martin",
"entity_account_id": "account_abc123"
},
"data": {
"visitor": {
"entity_id": 5,
"widget_id": "644660339401",
"tracking_id": 458,
"ip_address": "192.168.1.100",
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)...",
"first_visit_at": "2025-06-06T17:30:00+00:00",
"converted_at": "2025-06-06T17:45:00+00:00",
"status": "converted",
"conversion_time_seconds": 900,
"tag1": null,
"tag2": null,
"tag3": null,
"tag4": null,
"tag5": null,
"tag6": null,
"tag7": null,
"tag8": "external_client_123",
"tag9": "campaign_step_1",
"tag10": null
},
"appointment": {
"appointment_id": 790,
"entity_id": 5,
"calendar_id": 15,
"slot_id": 459,
"client_id": 125,
"date": "2025-06-12",
"start_time": "10:00:00",
"end_time": "11:00:00",
"status": "pending",
"status_details": {
"key": "pending",
"label": "En attente",
"color": "#FFA500",
"type": "pending",
"is_custom": false,
"scope": "default"
},
"notes": "Nouveau client via widget",
"timezone": "Europe/Paris"
},
"client": {
"client_id": 125,
"id": 125,
"entity_id": 5,
"first_name": "Sophie",
"last_name": "Bernard",
"name": "Sophie Bernard",
"email": "sophie.bernard@example.com",
"phone": "33687654321",
"tag1": "Widget",
"tag2": "Conversion",
"tag3": null,
"tag4": null,
"tag5": null,
"tag6": null,
"tag7": null,
"tag8": "external_client_123",
"tag9": "campaign_step_1",
"tag10": null,
"optin": 1,
"ip_address": "192.168.1.100",
"created_at": "2025-06-06 17:45:00",
"updated_at": "2025-06-06 17:45:00"
}
},
"signature": "i789abcdef123456789..."
}
Les webhooks TAP4BOOK utilisent exclusivement la méthode HTTP POST.
application/jsonX-TAP4BOOK-SignatureChaque webhook inclut une signature HMAC-SHA256 générée avec votre entity_secret_key :
Validez toujours la signature pour vous assurer que le webhook provient bien de TAP4BOOK.
// Génération côté TAP4BOOK (méthode actuelle v2.0)
$jsonPayload = json_encode($payload, JSON_UNESCAPED_UNICODE);
$secret = $entity['entity_secret_key'];
$signature = hash_hmac('sha256', $jsonPayload, $secret);
function validateWebhookSignature($rawPayload, $receivedSignature, $secret) {
if (empty($receivedSignature) || empty($secret)) {
return false;
}
try {
// Décoder le payload pour validation
$data = json_decode($rawPayload, true);
if (!$data) {
return false;
}
// TAP4BOOK signe le payload JSON complet
$jsonPayload = json_encode($data, JSON_UNESCAPED_UNICODE);
$expectedSignature = hash_hmac('sha256', $jsonPayload, $secret);
// Comparaison sécurisée
return hash_equals($expectedSignature, $receivedSignature);
} catch (Exception $e) {
return false;
}
}
Version 2.0 : TAP4BOOK signe maintenant le payload JSON complet, plus la méthode event|data utilisée dans les versions antérieures.
hash_hmac('sha256', $event . '|' . json_encode($data), $secret)hash_hmac('sha256', json_encode($payload, JSON_UNESCAPED_UNICODE), $secret)Chaque webhook inclut des headers spécifiques :
| Header | Valeur | Description |
|---|---|---|
Content-Type |
application/json |
Type de contenu du payload |
User-Agent |
TAP4BOOK-Webhook/2.0 |
Identification du client webhook |
X-Tap4Book-Event |
appointment.created |
Type d'événement sans parsing JSON |
X-TAP4BOOK-Signature |
sha256_signature |
Signature HMAC pour validation |
TAP4BOOK implémente un système de retry automatique pour garantir la livraison des webhooks :
| Condition d'Échec | Code HTTP | Retry ? | Raison |
|---|---|---|---|
| Timeout de connexion | - | ✅ Oui | Problème réseau temporaire |
| Erreur de connexion TCP | - | ✅ Oui | Serveur indisponible temporairement |
| Erreur serveur | 500-599 | ✅ Oui | Erreur côté récepteur, peut être temporaire |
| Succès | 200-299 | ❌ Non | Webhook traité avec succès |
| Erreur client | 400-499 | ❌ Non | Erreur permanente (URL incorrecte, authentification, etc.) |
Votre endpoint DOIT implémenter la déduplication basée sur l'event_id :
// Exemple d'implémentation de déduplication
function processWebhook($webhookData) {
$eventId = $webhookData['event_id'];
// Vérifier si déjà traité
if (isEventAlreadyProcessed($eventId)) {
// Retourner succès sans retraiter
http_response_code(200);
echo json_encode(['status' => 'already_processed', 'event_id' => $eventId]);
return;
}
// Marquer comme en cours de traitement
markEventAsProcessing($eventId);
try {
// Traiter le webhook
handleWebhookEvent($webhookData);
// Marquer comme traité avec succès
markEventAsProcessed($eventId);
http_response_code(200);
echo json_encode(['status' => 'processed', 'event_id' => $eventId]);
} catch (Exception $e) {
// En cas d'erreur, ne pas marquer comme traité
markEventAsError($eventId, $e->getMessage());
http_response_code(500);
echo json_encode(['error' => 'Processing failed', 'event_id' => $eventId]);
}
}
{"error":"Method not allowed"}