SchedulinqDocs
Go to Schedulinq

Webhook events

Every event, when it is sent, and an example payload of each.

These are the events an endpoint can receive. You choose them per endpoint under Integrations → API → Webhooks; how deliveries, signatures and retries work is in Webhooks. Every example payload below comes from Schedulinq's own test of the payloads, so it has exactly the shape your endpoint receives.

The payload

Every message is an envelope:

  • type — the event, such as appointment.created;
  • timestamp — when the change happened, in UTC;
  • data — the appointment, invitation or team member as it is after the change, in the same shape the API reads it (see the reference).

data also carries:

  • metadata — your metadata, {} when there are none;
  • version — a number that increases per appointment, invitation or team member. Keep the highest one you processed, and drop an event with a lower one. Versions can skip numbers;
  • changedBy — who made the change. type is USER (a team member, with userId), API_KEY (your own system, with apiKeyId), CUSTOMER, SYSTEM (Schedulinq itself), INTEGRATION (Teamleader) or CALENDAR_SYNC (a connected calendar);
  • on appointment.rescheduled only, previous: the start, end and userIds before the change;
  • on colleague.activated, the invitationId of the accepted invitation and that invitation's metadata.

A payload never holds a customer's name, e-mail address or phone number, and never a booking link.

Appointments

appointment.created

An appointment was booked: in the dashboard (also from a planning link), by the customer on the booking page or from an invitation, or from Teamleader or a connected calendar.

Example payload
{
  "type": "appointment.created",
  "timestamp": "2026-10-01T08:30:00Z",
  "data": {
    "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e09",
    "status": "CONFIRMED",
    "start": "2026-10-14T10:00:00+02:00",
    "end": "2026-10-14T11:00:00+02:00",
    "timeZone": "Europe/Amsterdam",
    "service": {
      "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e01",
      "name": "Offertebezoek"
    },
    "colleagues": [
      {
        "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e03",
        "name": "Sanne de Vries"
      }
    ],
    "customerId": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e06",
    "locationMode": "AT_CUSTOMER",
    "address": {
      "line1": "Keizersgracht 100",
      "postalCode": "1015 AA",
      "city": "Amsterdam",
      "country": "NL"
    },
    "metadata": {
      "campaignId": "C-42",
      "dealId": "D-123"
    },
    "createdAt": "2026-10-01T10:30:00+02:00",
    "updatedAt": "2026-10-01T10:30:00+02:00",
    "version": 1,
    "changedBy": {
      "type": "API_KEY",
      "apiKeyId": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e0a"
    }
  }
}

appointment.rescheduled

The start, the end or the team members changed. A customer who moves their own appointment gets a new appointment: this event then arrives on the new id, with rescheduledFromId naming the old one and previous its times. No separate appointment.cancelled is sent for the old one.

Example payload
{
  "type": "appointment.rescheduled",
  "timestamp": "2026-10-01T08:30:00Z",
  "data": {
    "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e09",
    "status": "CONFIRMED",
    "start": "2026-10-14T10:00:00+02:00",
    "end": "2026-10-14T11:00:00+02:00",
    "timeZone": "Europe/Amsterdam",
    "service": {
      "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e01",
      "name": "Offertebezoek"
    },
    "colleagues": [
      {
        "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e03",
        "name": "Sanne de Vries"
      }
    ],
    "customerId": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e06",
    "locationMode": "AT_CUSTOMER",
    "address": {
      "line1": "Keizersgracht 100",
      "postalCode": "1015 AA",
      "city": "Amsterdam",
      "country": "NL"
    },
    "metadata": {
      "campaignId": "C-42",
      "dealId": "D-123"
    },
    "rescheduledFromId": "00000000-0000-0000-0000-000000000001",
    "lineageRootId": "00000000-0000-0000-0000-000000000001",
    "createdAt": "2026-10-01T10:30:00+02:00",
    "updatedAt": "2026-10-01T10:30:00+02:00",
    "version": 1,
    "changedBy": {
      "type": "CUSTOMER"
    },
    "previous": {
      "start": "2026-10-13T14:00:00+02:00",
      "end": "2026-10-13T15:00:00+02:00",
      "userIds": [
        "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e03"
      ]
    }
  }
}

appointment.updated

Something else on the appointment changed, such as the service, the place or the meeting link.

Example payload
{
  "type": "appointment.updated",
  "timestamp": "2026-10-01T08:30:00Z",
  "data": {
    "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e09",
    "status": "CONFIRMED",
    "start": "2026-10-14T10:00:00+02:00",
    "end": "2026-10-14T11:00:00+02:00",
    "timeZone": "Europe/Amsterdam",
    "service": {
      "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e01",
      "name": "Offertebezoek"
    },
    "colleagues": [
      {
        "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e03",
        "name": "Sanne de Vries"
      }
    ],
    "customerId": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e06",
    "locationMode": "AT_CUSTOMER",
    "address": {
      "line1": "Keizersgracht 100",
      "postalCode": "1015 AA",
      "city": "Amsterdam",
      "country": "NL"
    },
    "metadata": {
      "campaignId": "C-42",
      "dealId": "D-123"
    },
    "createdAt": "2026-10-01T10:30:00+02:00",
    "updatedAt": "2026-10-01T10:30:00+02:00",
    "version": 2,
    "changedBy": {
      "type": "USER",
      "userId": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e03"
    }
  }
}

appointment.cancelled

Cancelled by the customer, a team member, a connected calendar or Teamleader, or because the customer was deleted. cancelledBy says by whom.

Example payload
{
  "type": "appointment.cancelled",
  "timestamp": "2026-10-01T08:30:00Z",
  "data": {
    "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e09",
    "status": "CANCELLED",
    "cancelledAt": "2026-10-01T10:30:00+02:00",
    "cancelledBy": "STAFF",
    "cancellationReason": "De klant heeft telefonisch afgezegd.",
    "start": "2026-10-14T10:00:00+02:00",
    "end": "2026-10-14T11:00:00+02:00",
    "timeZone": "Europe/Amsterdam",
    "service": {
      "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e01",
      "name": "Offertebezoek"
    },
    "colleagues": [
      {
        "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e03",
        "name": "Sanne de Vries"
      }
    ],
    "customerId": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e06",
    "locationMode": "AT_CUSTOMER",
    "address": {
      "line1": "Keizersgracht 100",
      "postalCode": "1015 AA",
      "city": "Amsterdam",
      "country": "NL"
    },
    "metadata": {
      "campaignId": "C-42",
      "dealId": "D-123"
    },
    "createdAt": "2026-10-01T10:30:00+02:00",
    "updatedAt": "2026-10-01T10:30:00+02:00",
    "version": 2,
    "changedBy": {
      "type": "USER",
      "userId": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e03"
    }
  }
}

appointment.completed

Finished, also when its invoice was issued.

Example payload
{
  "type": "appointment.completed",
  "timestamp": "2026-10-01T08:30:00Z",
  "data": {
    "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e09",
    "status": "COMPLETED",
    "start": "2026-10-14T10:00:00+02:00",
    "end": "2026-10-14T11:00:00+02:00",
    "timeZone": "Europe/Amsterdam",
    "service": {
      "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e01",
      "name": "Offertebezoek"
    },
    "colleagues": [
      {
        "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e03",
        "name": "Sanne de Vries"
      }
    ],
    "customerId": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e06",
    "locationMode": "AT_CUSTOMER",
    "address": {
      "line1": "Keizersgracht 100",
      "postalCode": "1015 AA",
      "city": "Amsterdam",
      "country": "NL"
    },
    "metadata": {
      "campaignId": "C-42",
      "dealId": "D-123"
    },
    "createdAt": "2026-10-01T10:30:00+02:00",
    "updatedAt": "2026-10-01T10:30:00+02:00",
    "version": 2,
    "changedBy": {
      "type": "USER",
      "userId": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e03"
    }
  }
}

appointment.deleted

Archived. A read of the appointment answers 404 from then on.

Example payload
{
  "type": "appointment.deleted",
  "timestamp": "2026-10-01T08:30:00Z",
  "data": {
    "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e09",
    "status": "COMPLETED",
    "start": "2026-10-14T10:00:00+02:00",
    "end": "2026-10-14T11:00:00+02:00",
    "timeZone": "Europe/Amsterdam",
    "service": {
      "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e01",
      "name": "Offertebezoek"
    },
    "colleagues": [
      {
        "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e03",
        "name": "Sanne de Vries"
      }
    ],
    "customerId": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e06",
    "locationMode": "AT_CUSTOMER",
    "address": {
      "line1": "Keizersgracht 100",
      "postalCode": "1015 AA",
      "city": "Amsterdam",
      "country": "NL"
    },
    "metadata": {
      "campaignId": "C-42",
      "dealId": "D-123"
    },
    "createdAt": "2026-10-01T10:30:00+02:00",
    "updatedAt": "2026-10-01T10:30:00+02:00",
    "version": 2,
    "changedBy": {
      "type": "USER",
      "userId": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e03"
    }
  }
}

When a team member uses Reschedule, the appointment is cancelled with cancelledBy: STAFF_RESCHEDULE and an invitation.created follows: the customer gets an invitation to pick a new time. Their booking later sends invitation.booked and appointment.created, and the new appointment carries rescheduledFromId.

There is no appointment.no_show: nothing in Schedulinq marks an appointment as a no-show.

Invitations

invitation.created

An invitation to book was sent: from the dashboard, through the API, after a Reschedule, or by a subscription.

Example payload
{
  "type": "invitation.created",
  "timestamp": "2026-10-01T08:30:00Z",
  "data": {
    "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e08",
    "status": "PENDING",
    "service": {
      "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e01",
      "name": "Offertebezoek"
    },
    "colleagues": [
      {
        "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e03",
        "name": "Sanne de Vries"
      }
    ],
    "customerId": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e06",
    "metadata": {
      "campaignId": "C-42",
      "dealId": "D-123"
    },
    "appointmentIds": [],
    "createdAt": "2026-10-01T10:30:00+02:00",
    "updatedAt": "2026-10-01T10:30:00+02:00",
    "version": 1,
    "changedBy": {
      "type": "API_KEY",
      "apiKeyId": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e0a"
    }
  }
}

invitation.booked

The customer booked through the invitation. appointmentIds lists the appointments, earliest first.

Example payload
{
  "type": "invitation.booked",
  "timestamp": "2026-10-01T08:30:00Z",
  "data": {
    "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e08",
    "status": "USED",
    "service": {
      "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e01",
      "name": "Offertebezoek"
    },
    "colleagues": [
      {
        "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e03",
        "name": "Sanne de Vries"
      }
    ],
    "customerId": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e06",
    "metadata": {
      "campaignId": "C-42",
      "dealId": "D-123"
    },
    "appointmentIds": [
      "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e09"
    ],
    "createdAt": "2026-10-01T10:30:00+02:00",
    "updatedAt": "2026-10-01T10:30:00+02:00",
    "version": 1,
    "changedBy": {
      "type": "CUSTOMER"
    }
  }
}

invitation.expired

The invitation passed its end date without a booking.

Example payload
{
  "type": "invitation.expired",
  "timestamp": "2026-10-01T08:30:00Z",
  "data": {
    "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e08",
    "status": "EXPIRED",
    "service": {
      "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e01",
      "name": "Offertebezoek"
    },
    "colleagues": [
      {
        "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e03",
        "name": "Sanne de Vries"
      }
    ],
    "customerId": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e06",
    "metadata": {
      "campaignId": "C-42",
      "dealId": "D-123"
    },
    "appointmentIds": [],
    "createdAt": "2026-10-01T10:30:00+02:00",
    "updatedAt": "2026-10-01T10:30:00+02:00",
    "version": 1,
    "changedBy": {
      "type": "SYSTEM"
    }
  }
}

invitation.cancelled

The invitation was withdrawn in the dashboard, or its customer was deleted.

Example payload
{
  "type": "invitation.cancelled",
  "timestamp": "2026-10-01T08:30:00Z",
  "data": {
    "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e08",
    "status": "CANCELLED",
    "service": {
      "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e01",
      "name": "Offertebezoek"
    },
    "colleagues": [
      {
        "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e03",
        "name": "Sanne de Vries"
      }
    ],
    "customerId": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e06",
    "metadata": {
      "campaignId": "C-42",
      "dealId": "D-123"
    },
    "appointmentIds": [],
    "createdAt": "2026-10-01T10:30:00+02:00",
    "updatedAt": "2026-10-01T10:30:00+02:00",
    "version": 1,
    "changedBy": {
      "type": "USER",
      "userId": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e03"
    }
  }
}

invitation.deleted

The invitation was archived. A read of it answers 404 from then on.

Example payload
{
  "type": "invitation.deleted",
  "timestamp": "2026-10-01T08:30:00Z",
  "data": {
    "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e08",
    "status": "PENDING",
    "service": {
      "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e01",
      "name": "Offertebezoek"
    },
    "colleagues": [
      {
        "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e03",
        "name": "Sanne de Vries"
      }
    ],
    "customerId": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e06",
    "metadata": {
      "campaignId": "C-42",
      "dealId": "D-123"
    },
    "appointmentIds": [],
    "createdAt": "2026-10-01T10:30:00+02:00",
    "updatedAt": "2026-10-01T10:30:00+02:00",
    "version": 1,
    "changedBy": {
      "type": "USER",
      "userId": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e03"
    }
  }
}

Changing an open invitation in the dashboard sends no event.

Team members

These fire for every team member, not only for the ones your system invited. For the others, metadata is {}.

colleague.activated

Someone accepted their invitation and is now a team member. invitationId and metadata are those of the invitation, so you can match them to the request that created it.

Example payload
{
  "type": "colleague.activated",
  "timestamp": "2026-10-01T08:30:00Z",
  "data": {
    "id": "00000000-0000-0000-0000-000000000001",
    "status": "ACTIVE",
    "firstName": "Piet",
    "lastName": "Bakker",
    "name": "Piet Bakker",
    "email": "piet+ov@loodgieter-bakker.example",
    "admin": false,
    "schedulable": true,
    "calendarConnected": false,
    "customFields": {},
    "createdAt": "2026-10-01T08:30:00Z",
    "version": 1,
    "changedBy": {
      "type": "USER",
      "userId": "00000000-0000-0000-0000-000000000001"
    },
    "invitationId": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e05",
    "metadata": {
      "campaignId": "C-42",
      "dealId": "D-123"
    }
  }
}

colleague.calendar_connected

The team member now has a connected calendar whose busy times Schedulinq reads: calendarConnected changed to true.

Example payload
{
  "type": "colleague.calendar_connected",
  "timestamp": "2026-10-01T08:30:00Z",
  "data": {
    "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e03",
    "status": "ACTIVE",
    "firstName": "Sanne",
    "lastName": "de Vries",
    "name": "Sanne de Vries",
    "email": "sanne@installatiebedrijf-jansen.example",
    "admin": true,
    "schedulable": true,
    "calendarConnected": true,
    "customFields": {},
    "createdAt": "2026-10-01T08:30:00Z",
    "version": 1,
    "changedBy": {
      "type": "USER",
      "userId": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e03"
    }
  }
}

colleague.calendar_disconnected

The team member no longer has such a calendar. When Schedulinq lost access by itself, changedBy is SYSTEM; that is noticed within a few hours.

Example payload
{
  "type": "colleague.calendar_disconnected",
  "timestamp": "2026-10-01T08:30:00Z",
  "data": {
    "id": "3f0c8a52-6b1e-4d7a-9c3e-1a2b3c4d5e03",
    "status": "ACTIVE",
    "firstName": "Sanne",
    "lastName": "de Vries",
    "name": "Sanne de Vries",
    "email": "sanne@installatiebedrijf-jansen.example",
    "admin": true,
    "schedulable": true,
    "calendarConnected": false,
    "customFields": {},
    "createdAt": "2026-10-01T08:30:00Z",
    "version": 2,
    "changedBy": {
      "type": "SYSTEM"
    }
  }
}

Test message

ping

Sent only by Send test message on the endpoint's page. You cannot subscribe to it.

Example payload
{
  "type": "ping",
  "timestamp": "2026-10-01T08:30:00Z",
  "data": {
    "endpointId": "00000000-0000-0000-0000-000000000001"
  }
}

Who triggers what

Where it happensEvents
Dashboard: create an appointmentappointment.created
Dashboard: edit an appointmentappointment.rescheduled when the start, end or team members change, otherwise appointment.updated
Dashboard: drag in the calendarappointment.rescheduled
Dashboard: finishappointment.completed
Dashboard: cancelappointment.cancelled
Dashboard: Rescheduleappointment.cancelled and invitation.created
Dashboard: archive an appointmentappointment.deleted
Dashboard: set, change or clear a meeting linkappointment.updated
Dashboard: send an invitationinvitation.created
Dashboard: withdraw an invitationinvitation.cancelled
Dashboard: archive an invitationinvitation.deleted
Dashboard: delete a customerappointment.cancelled per future appointment, invitation.cancelled per open invitation
Dashboard: merge two customersappointment.updated per moved appointment
Dashboard: issue an invoiceappointment.completed per appointment it completes
API: send an invitationinvitation.created
Customer: book on the booking pageappointment.created
Customer: book an invitationinvitation.booked and appointment.created per appointment
Customer: cancel through their linkappointment.cancelled
Customer: reschedule through their linkappointment.rescheduled on the new appointment
A subscription's next invitationinvitation.created
An invitation's end date passesinvitation.expired
A cancel moves the later visits of a booking upappointment.rescheduled per visit, changedBy SYSTEM
Dashboard: book several appointmentsappointment.created per appointment
Teamleaderappointment.created; appointment.rescheduled when the time or team members change, otherwise appointment.updated; appointment.cancelled
Connected calendar: the meeting link is created or removedappointment.updated
Connected calendar: the event is movedappointment.rescheduled
Connected calendar: one of several team members is removedappointment.rescheduled
Connected calendar: the last team member is removed, or the event is deletedappointment.cancelled
Someone accepts a team invitationcolleague.activated
A team member's calendar is connected or lostcolleague.calendar_connected or colleague.calendar_disconnected
Last updated October 2, 2026