DoloresDocs
Webhooks

Event types

Every Dolores webhook event with its trigger and payload shape.

Dolores v1 emits five appointment-status events. Each one carries a full snapshot of the appointment plus a previous_attributes diff on updates.

Envelope (shared by every event)

{
  "id": "evt_01HXY...",
  "object": "event",
  "type": "appointment.confirmed",
  "created": 1717685011,
  "livemode": true,
  "api_version": "2026-06-01",
  "data": {
    "object": { /* full appointment resource */ },
    "previous_attributes": { /* present on updates */ }
  }
}
  • created is Unix seconds, not milliseconds.
  • livemode matches the registered endpoint's livemode flag. Test deliveries never reach live endpoints; live deliveries never reach test endpoints.
  • data.object is the appointment as it exists at the moment the event fires.
  • data.previous_attributes is only present on update-shaped events (confirmed, rescheduled, cancelled, failed). It contains just the fields that changed and their old values.

appointment.created

Fires when a new appointment row lands with status = pending or status = reserved. Typically triggered by the voice agent during a live booking flow.

{
  "id": "evt_01HXY...",
  "object": "event",
  "type": "appointment.created",
  "created": 1717685011,
  "livemode": true,
  "data": {
    "object": {
      "id": "appt_01HXY...",
      "object": "appointment",
      "customer_id": "cust_01HXY...",
      "session_id": "sess_01HXY...",
      "appointment_at": "2026-06-10T15:00:00Z",
      "status": "pending",
      "notes": null,
      "metadata": {},
      "error_message": null,
      "created_at": "2026-06-06T14:23:11Z",
      "updated_at": "2026-06-06T14:23:11Z",
      "livemode": true
    }
  }
}

No previous_attributes — it's a creation.


appointment.confirmed

Fires when an appointment's status transitions from pending (or reserved) to confirmed. This is the most actionable event — at this point the customer has agreed to the booking and you should write it to your operational system.

{
  "type": "appointment.confirmed",
  "created": 1717685042,
  "livemode": true,
  "data": {
    "object": {
      "id": "appt_01HXY...",
      "object": "appointment",
      "customer_id": "cust_01HXY...",
      "session_id": "sess_01HXY...",
      "appointment_at": "2026-06-10T15:00:00Z",
      "status": "confirmed",
      "metadata": {},
      "created_at": "2026-06-06T14:23:11Z",
      "updated_at": "2026-06-06T14:23:42Z",
      "livemode": true
    },
    "previous_attributes": { "status": "pending" }
  }
}

appointment.rescheduled

Fires when appointment_at changes via PATCH /v1/appointments/{id}. The old time appears in previous_attributes.appointment_at.

{
  "type": "appointment.rescheduled",
  "data": {
    "object": {
      "id": "appt_01HXY...",
      "appointment_at": "2026-06-11T15:00:00Z",
      "status": "confirmed",
      ...
    },
    "previous_attributes": { "appointment_at": "2026-06-10T15:00:00Z" }
  }
}

appointment.cancelled

Fires when status flips to cancelled via POST /v1/appointments/{id}/cancel or via the admin UI.

{
  "type": "appointment.cancelled",
  "data": {
    "object": {
      "id": "appt_01HXY...",
      "status": "cancelled",
      "error_message": "customer requested cancellation",
      ...
    },
    "previous_attributes": { "status": "confirmed" }
  }
}

error_message carries the cancellation reason if one was supplied.


appointment.failed

Fires when the workflow's confirmation step reports a downstream error (typically because an external scheduling integration rejected the booking). The appointment is left with status = failed — operationally treat it like a cancelled booking, but with a payload hint pointing at the failure.

{
  "type": "appointment.failed",
  "data": {
    "object": {
      "id": "appt_01HXY...",
      "status": "failed",
      "error_message": "external scheduler returned 503",
      ...
    },
    "previous_attributes": { "status": "pending" }
  }
}

Filtering events

When registering an endpoint, pass event_filters to subscribe to a subset:

{
  "url": "https://api.example.com/dolores/webhook",
  "event_filters": ["appointment.confirmed", "appointment.cancelled"]
}

Wildcards are supported — appointment.* matches all five event types in this section. An empty event_filters array (or omitting it entirely) subscribes to every event Dolores currently emits.

What's not (yet) emitted

These are on the roadmap but not in v1:

  • appointment.completed — appointment time elapsed without cancellation
  • appointment.no_show — heuristic detection of customer no-shows
  • customer.* — created / updated / deleted
  • session.* — call lifecycle

If you need any of these, let us know.