Webhook Events
Complete list of available webhook events with their payloads.
Event Types
appointment.created
Triggered when a new appointment is created.
Payload:
{
"id": "evt_abc123",
"type": "appointment.created",
"created": "2026-01-21T14:30:00Z",
"data": {
"object": {
"id": 12345,
"departmentId": 5,
"department": {
"id": 5,
"name": "Passport Service",
"organization": {
"id": 1,
"name": "Ministry of Interior"
}
},
"dateTime": "2026-01-25T14:30:00",
"status": "SCHEDULED",
"name": "Jean Dupont",
"phone": "+224621234567",
"email": "jean.dupont@example.gn",
"qrCode": "https://moncreneau.gn/qr/12345",
"createdAt": "2026-01-21T14:30:00Z",
"creditsUsed": 1
}
}
}
Use Cases:
- Send confirmation SMS
- Create entry in your CRM
- Notify team of new appointment
appointment.updated
Triggered when an appointment is modified (date, time, information).
Payload:
{
"id": "evt_def456",
"type": "appointment.updated",
"created": "2026-01-22T10:15:00Z",
"data": {
"object": {
"id": 12345,
"departmentId": 5,
"dateTime": "2026-01-26T10:00:00",
"status": "SCHEDULED",
"name": "Jean Dupont",
"phone": "+224621234567",
"updatedAt": "2026-01-22T10:15:00Z",
"changes": {
"dateTime": {
"from": "2026-01-25T14:30:00",
"to": "2026-01-26T10:00:00"
}
}
}
}
}
Use Cases:
- Send change notification
- Update calendars
- Log modifications
appointment.cancelled
Triggered when an appointment is cancelled.
Payload:
{
"id": "evt_ghi789",
"type": "appointment.cancelled",
"created": "2026-01-23T16:45:00Z",
"data": {
"object": {
"id": 12345,
"departmentId": 5,
"dateTime": "2026-01-25T14:30:00",
"status": "CANCELLED",
"name": "Jean Dupont",
"phone": "+224621234567",
"cancelledAt": "2026-01-23T16:45:00Z",
"cancelledBy": "user",
"cancelReason": "Last minute impediment",
"creditsRefunded": 1
}
}
}
Use Cases:
- Notify user of cancellation
- Free up the slot
- Refund/credit user
appointment.validated
Triggered when an appointment is validated by staff (presence confirmed).
Payload:
{
"id": "evt_jkl012",
"type": "appointment.validated",
"created": "2026-01-25T14:35:00Z",
"data": {
"object": {
"id": 12345,
"departmentId": 5,
"dateTime": "2026-01-25T14:30:00",
"status": "VALIDATED",
"name": "Jean Dupont",
"phone": "+224621234567",
"validatedAt": "2026-01-25T14:35:00Z",
"validatedBy": {
"id": 42,
"name": "Agent Martin"
}
}
}
}
Use Cases:
- Mark appointment as honored
- Generate invoice
- Update statistics
appointment.completed
Triggered when an appointment is marked as completed.
Payload:
{
"id": "evt_mno345",
"type": "appointment.completed",
"created": "2026-01-25T15:00:00Z",
"data": {
"object": {
"id": 12345,
"departmentId": 5,
"dateTime": "2026-01-25T14:30:00",
"status": "COMPLETED",
"name": "Jean Dupont",
"phone": "+224621234567",
"completedAt": "2026-01-25T15:00:00Z",
"duration": 30,
"notes": "Document issued"
}
}
}
Use Cases:
- Send satisfaction email
- Archive file
- Request feedback
Filter Events
When creating a webhook from the web interface, select only necessary events:
- Go to Settings → Webhooks
- Select only the events relevant to your integration
- This reduces unnecessary traffic and improves performance
Event Handling
Route by Type
function handleWebhook(event) {
switch (event.type) {
case 'appointment.created':
return handleAppointmentCreated(event.data.object);
case 'appointment.cancelled':
return handleAppointmentCancelled(event.data.object);
case 'appointment.validated':
return handleAppointmentValidated(event.data.object);
default:
console.log(`Unhandled event: ${event.type}`);
}
}
Idempotence
Use event ID to avoid duplicates:
async function processWebhook(event) {
// Check if already processed
const exists = await db.webhookEvents.findOne({
eventId: event.id
});
if (exists) {
console.log(`Event ${event.id} already processed`);
return;
}
// Process event
await processEvent(event);
// Mark as processed
await db.webhookEvents.create({
eventId: event.id,
processedAt: new Date()
});
}