Skip to main content

Appointment Webhooks

Receive real-time event notifications when appointments are created, updated, cancelled, or completed, and when calendar windows change.

Webhook endpoints are registered and managed through the HuskyVoice Dashboard — go to Dashboard → Integrations → Webhooks → Add Endpoint and select the appointment events you want to receive.


Important: API Writes Do Not Fire Webhooks

caution

Appointment and slot events are not dispatched for writes made through the REST API. Webhooks fire only when changes originate from:

  • The HuskyVoice dashboard
  • The AI voice agent (appointments booked during a call)

If your integration creates or updates appointments via the REST API and you need those changes reflected downstream, handle that in your own application code rather than relying on webhook delivery.


Registerable Events

EventWhen it fires
appointment.createdAn appointment is booked via the dashboard or by the AI voice agent
appointment.updatedAn appointment's details are changed via the dashboard
appointment.cancelledAn appointment is cancelled via the dashboard
appointment.completedAn appointment is marked completed via the dashboard
slot.createdA calendar window is created via the dashboard
slot.updatedA calendar window is updated via the dashboard

Event Payloads

appointment.* Events

All four appointment events use the same payload shape.

{
"event_id": "evt_a1b2c3d4-...",
"event": "appointment.created",
"timestamp": "2026-05-26T10:00:00.000Z",
"appointment": {
"appointment_id": "appt_a1b2c3d4e5",
"appointment_type": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"appointment_type_name": "General Checkup",
"branch_id": "branch_uuid_here",
"date": "2026-06-15",
"start_time": "2026-06-15T04:00:00.000Z",
"session": "Morning",
"batch": "MA",
"token": null,
"patient_name": "Aadhi",
"parent_phone": "+919840XXXXXX",
"doctor_name": null,
"status": "confirmed",
"booked_via": "phone_call",
"booked_at": "2026-05-26T10:00:00.000Z"
}
}
FieldDescription
event_idUnique identifier for this event delivery
eventEvent type: appointment.created, appointment.updated, appointment.cancelled, or appointment.completed
timestampISO 8601 UTC datetime when the event was dispatched
appointment.appointment_idAppointment identifier
appointment.appointment_typeService UUID
appointment.appointment_type_nameHuman-readable service name
appointment.branch_idBranch UUID
appointment.dateAppointment date — YYYY-MM-DD
appointment.start_timeFull ISO 8601 UTC datetime of the appointment
appointment.sessionSession name
appointment.batchBatch label
appointment.tokenQueue token, if assigned
appointment.patient_namePatient name
appointment.parent_phonePatient phone number
appointment.doctor_nameAssigned doctor, if set
appointment.statusCurrent appointment status
appointment.booked_viaHow the appointment was created: "phone_call" for AI agent, "dashboard" for manual
appointment.booked_atISO 8601 UTC datetime the appointment was created

slot.* Events

Both slot events use the same payload shape.

{
"event_id": "evt_a1b2c3d4-...",
"event": "slot.updated",
"timestamp": "2026-05-26T10:00:00.000Z",
"slot": {
"slot_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890||2026-06-15",
"branch_id": "branch_uuid_here",
"appointment_type_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"appointment_type_name": "General Checkup",
"date": "2026-06-15",
"day_of_week": "monday",
"session": "Morning",
"batch": "MA",
"start_time": "09:00",
"end_time": "11:00",
"max_slots": 20,
"filled_slots": 3,
"available_slots": 17,
"status": "OPEN"
}
}

Verifying Signatures

When require_signature is true, every delivery includes two headers:

HeaderDescription
X-Webhook-TimestampUnix timestamp (seconds) when the payload was signed
X-Webhook-SignatureSignature in the format v1=<base64-encoded HMAC-SHA256>

The signature is computed as:

HMAC-SHA256(secret, "{timestamp}.{rawBody}")

encoded as base64 (not hex), and prefixed with v1=.

# Generate a signed test delivery to verify your endpoint
SECRET="YOUR_WEBHOOK_SECRET"
TIMESTAMP=$(date +%s)
PAYLOAD='{"event_id":"evt_test","event":"appointment.created","timestamp":"2026-06-01T10:00:00.000Z","appointment":{"appointment_id":"appt_test"}}'
SIG="v1=$(printf '%s.%s' "$TIMESTAMP" "$PAYLOAD" | openssl dgst -sha256 -hmac "$SECRET" -binary | base64)"

curl -X POST https://your-server.com/webhook \
-H "Content-Type: application/json" \
-H "X-Webhook-Timestamp: $TIMESTAMP" \
-H "X-Webhook-Signature: $SIG" \
-d "$PAYLOAD"
caution

Always use a timing-safe comparison (e.g. hmac.compare_digest or crypto.timingSafeEqual) to prevent timing attacks. Reject payloads where the timestamp is more than a few minutes old.


Delivery & Retries

Webhooks time out after 8 seconds. A 2xx response is required to mark a delivery as successful. Failed deliveries are retried up to 5 times with exponential backoff:

AttemptDelay
1Immediate
230 seconds
32 minutes
410 minutes
51 hour

After 50 consecutive failures, the webhook is automatically disabled. Re-enable it from Dashboard → Integrations → Webhooks.

To inspect recent delivery attempts or replay a failed delivery, use the delivery history view in Dashboard → Integrations → Webhooks → your endpoint → Deliveries.