Webhooks
In this guide, we'll walk you through the process of integrating webhooks from Start Booking.
Registering Webhooks
To register a new webhook, you need to provide us with a webhook URL that Start Booking can call. You can configure a new webhook URL directly within your Start Booking account > Integrations > Webhooks.
Now, whenever specific events occur within your Start Booking account, we'll send a POST
request to your webhook URL. In the next section, we'll look at how to consume webhooks.
Consuming Webhooks
When your app receives a webhook request from Start Booking, check the action
attribute to see what event caused it.
Example Customer Created Webhook
{
"action": "customer.created",
"changes": null,
"data": {
"url_string": "74f62f7a-044f-4647-8ca8-fff5557a95a9",
"first_name": "John",
"last_name": "Doe",
// ...
}
}
In the example above, a Customer was Created
, and the payload data is a Customer
. It's worth noting that the payload data will vary depending on the event action. For example, if the event action is customer.created
, the payload data will be a Customer
. If the event action is appointment.created
, the payload data will be an Appointment
. Below is an example of a webhook payload for an appointment.created
event.
Notice how there are multiple objects within the Appointment object.
Example Appointment Created Webhook
{
"action": "appointment.created",
"changes": null,
"data": {
"url_string": "74f62f7a-044f-4647-8ca8-fff5557a87yj",
"customer_tz": null,
"status": "active",
"start_date": "2023-05-10 13:00:00",
"end_date": "2023-05-10 13:30:00",
"buffer": 0,
"account_tz": "America/Denver",
"booking_origin": "create_appointment",
"type": "appointment",
"hash_group": "13c96a0dbf62bc37c009536e9371b05c",
"updated_at": "2023-05-10T12:49:49.000000Z",
"created_at": "2023-05-10T12:49:49.000000Z",
"customer": {
"url_string": "74f62f7a-044f-4647-8ca8-fff5557a95a9",
"account_url_string": "p5ni2f7a-044f-4647-8ca8-fff5557a87yj",
"first_name": "John",
"last_name": "Doe",
"email": "[email protected]",
"image_url": null,
"is_valid_email": false,
"home_phone": null,
"mobile_phone": null,
"work_phone": null,
"preferred_contact_method": "mobile",
"is_valid_mobile_phone": false,
"country_code": null,
"timezone": "America/Denver",
"language": "english",
"birthday": null,
"occupation": null,
"gender": null,
"receive_emails": true,
"receive_sms": true,
"emergency_contact": null,
"emergency_phone": null,
"is_guest": false,
"created_at": "2021-07-22T23:37:47.000000Z",
"updated_at": "2022-06-09T01:06:29.000000Z",
"deleted_at": null,
},
"user": {
"url_string": "74f62f7a-044f-4647-8ca8-fff555724kb7",
"sort_order": null,
"status": "active",
"first_name": "Rick",
"last_name": "Smith",
"email": "[email protected]",
"is_valid_email": true,
"home_phone": null,
"mobile_phone": "+18018082909",
"work_phone": null,
"is_valid_mobile_phone": true,
"color": "#8ed1fc",
"country_code": "US",
"language": null,
"bio": null,
"created_at": "2018-04-16T06:42:04.000000Z",
"updated_at": "2022-12-18T22:16:11.000000Z",
"deleted_at": null,
"media": [
{
"url_string": null,
"url": "https://www....com",
"file_type": null,
"created_at": null,
"updated_at": null,
"deleted_at": null
}
],
"image_url": "https://www....com"
}
}
}
Event Actions
- Name
appointment.created
- Type
- Description
A new appointment was created.
- Name
appointment.updated
- Type
- Description
An existing appointment was updated.
- Name
appointment.cancelled
- Type
- Description
An existing appointment was cancelled.
- Name
appointment.service.changed
- Type
- Description
An existing appointment's service was changed.
- Name
service.created
- Type
- Description
A new service was created.
- Name
service.updated
- Type
- Description
An existing service was updated.
- Name
service.deleted
- Type
- Description
An existing service was deleted.
- Name
customer.created
- Type
- Description
A new customer was created.
- Name
customer.updated
- Type
- Description
An existing customer was updated.
- Name
customer.deleted
- Type
- Description
An existing customer was deleted.
- Name
customer.joined.class
- Type
- Description
A customer joined a class.
- Name
customer.removed.from.class
- Type
- Description
A customer was removed from a class.
- Name
class.created
- Type
- Description
A new class was created.
- Name
class.updated
- Type
- Description
An existing class was updated.
- Name
class.deleted
- Type
- Description
An existing class was deleted.
- Name
class.schedule.created
- Type
- Description
A new class schedule was created.
- Name
class.schedule.updated
- Type
- Description
An existing class schedule was updated.
- Name
class.schedule.deleted
- Type
- Description
An existing class schedule was deleted.
- Name
user.created
- Type
- Description
A new user was created.
- Name
user.updated
- Type
- Description
An existing user was updated.
- Name
user.deleted
- Type
- Description
An existing user was deleted.
Security
To know for sure that a webhook was, in fact, sent by Start Booking instead of a malicious actor, you can verify the request signature. Each webhook request contains a header named x-startbooking-signature
, and you can verify this signature by using your signing secret key located in your webhooks settings of your Start Booking account.
The signature is an HMAC hash of the request payload hashed using your signing secret key. Here is an example of how to verify the signature in your app:
Verifying a request
const signature = req.headers['x-startbooking-signature']
const hash = crypto.createHmac('sha256', secret).update(payload).digest('hex')
if (hash === signature) {
// Request is verified
} else {
// Request could not be verified
}
If your generated signature matches the x-startbooking-signature
header, you can be sure that the request was truly coming from Start Booking. It's essential to keep your secret webhook signing secret key safe — otherwise, you can no longer be sure that a given webhook was sent by Start Booking. Don't commit your secret webhook key to GitHub!
If you feel your secret webhook key has been compromised, you can refresh it in your Webhook settings. This will immediately invalidate the previous key, and you will need to use the new key to verify any subsequent webhook requests.