All docs

Events and what each one carries

Every event an endpoint can subscribe to, when each one is sent, and the payload a delivery of it carries.

Updated 8 October 2026 About 4 minutes View as Markdown

An endpoint subscribes to the events it wants, by name, on the project's webhooks screen. Each delivery's signed body names the event in event and carries the payload below in data, beside the delivery's own id: Verify a delivery shows the whole body. Every id is a public id, the same one the API answers with, so a payload can be followed up with a call.

The events

project
project.created Sent as a project is created, which is before it can have an endpoint, so no endpoint receives it today.
project.updated The project's name, timezone or currency changed.
project.deleted Sent as a project is deleted, once its endpoints are already gone, so no endpoint receives it today.
module
module.enabled A part was switched on for the project.
module.disabled A part was switched off for the project.
page
page.published A page went live, or a new version of it did.
page.unpublished A page was taken off the website, and kept as a draft.
page.deleted A page was deleted.
booking
booking.created A booking was made. It may still be waiting for payment, or for you.
booking.confirmed A booking was confirmed: paid for, accepted by hand, or confirmed on its own.
booking.cancelled A booking was cancelled, by the customer or by the business.
booking.rescheduled A booking moved to another time. The payload says where it was.
booking.expired A booking waiting for payment ran out of time, and its slot was given back.
booking.completed An appointment took place: sent once the business's day it was on is over, unless it was marked as a no-show first.
payment
payment.succeeded Money arrived.
payment.failed A payment was declined or abandoned.
payment.refunded Part or all of a payment was given back.
payment.expired A payment page ran out without being paid.
message
message.received A message from the website's contact form arrived in the inbox, or was moved there out of spam. Spam is never announced.

What a payload carries

Every event about one subject carries the same fields in data, so one handler reads them all. The values below are examples. Every time is an instant in UTC: show it on the project's timezone.

Bookings

booking.*
{
  "booking_id": "8f0c2b41-5d3e-4a7b-9c11-2e6f8a9d0b7c",
  "livemode": true,
  "service_id": "6f1c2a9e-4b7d-4e0a-9c55-2d8e1f0b7a31",
  "staff_id": "b3e04c1d-9a6f-4f2e-8d1b-5c7a0e9f3d24",
  "customer_id": "0d9e7f61-2c4b-4a8e-b5f3-71a2c6d8e9f0",
  "starts_at": "2026-10-06T07:00:00+00:00",
  "ends_at": "2026-10-06T07:45:00+00:00",
  "status": "confirmed",
  "amount_due": 2000,
  "currency": "CHF"
}

amount_due is in minor units: 2000 is CHF 20.00. livemode is false for a booking a test key made, and its events reach only your test endpoints. A few events add one or two fields of their own: booking.confirmed names who confirmed it in confirmed_by when a person did, booking.cancelled says who in cancelled_by, and booking.rescheduled adds previous_starts_at and moved_by.

Payments

payment.*
{
  "payment_id": "3c7d9e2a-1f4b-4c6d-8e0a-5b9f2d7c4e18",
  "livemode": true,
  "subject_type": "bookings.booking",
  "subject_id": "8f0c2b41-5d3e-4a7b-9c11-2e6f8a9d0b7c",
  "status": "paid",
  "amount": 2000,
  "currency": "CHF",
  "is_final": false,
  "metadata": {
    "booking_id": "8f0c2b41-5d3e-4a7b-9c11-2e6f8a9d0b7c"
  }
}

subject_type and subject_id say what the money was for, here a booking. A payment opened on its own, with POST /v1/checkouts, was for nothing but itself: its subject_type is empty and its subject_id is null. metadata is the references the checkout was given, the same ones the API returns on the payment, so a handler can find its order without a second call. livemode is false for a payment a test key asked for, which took no real money. is_final is true once nothing more can happen to the payment, so a handler can stop expecting more events about it.

Pages

page.*
{
  "event": "page.published",
  "project": "atelier-rosa",
  "page": {
    "id": "5a2e8c71-9d4f-4b3a-a6e0-1c7b9f2d8e45",
    "slug": "home",
    "locale": "en",
    "title": "Home",
    "status": "published",
    "url_path": "/home"
  },
  "cache_version": 42,
  "version": {
    "number": 7,
    "published_at": "2026-10-06T08:15:00+00:00"
  }
}

cache_version rises on every publish, so a static site can rebuild when it moves and not otherwise. version is only on page.published.

Messages

message.*
{
  "message_id": "c41f8a62-7b3d-4e9a-8f15-2d6b0e9c3a77",
  "livemode": true,
  "received_at": "2026-10-06T07:12:00+00:00"
}

Which message, and nothing anybody wrote in it: read the name, the address and the words with GET /v1/messages/{id} and a secret key. Spam is never announced, and a message moved out of spam is announced then, once.

The project

project.*
{
  "project_id": "7e4b1d93-6a2c-4f8e-9b05-3d1a7c9e2f64",
  "slug": "atelier-rosa",
  "name": "Atelier Rosa",
  "organization_id": "2b8f6e1a-4d9c-4e7b-a3f0-9c5d1e7b2a86",
  "timezone": "Europe/Zurich",
  "currency": "CHF"
}
module.*
{
  "project_id": "7e4b1d93-6a2c-4f8e-9b05-3d1a7c9e2f64",
  "module": "bookings"
}

Verifying a delivery

A payload is only worth acting on once its signature checks out. Verify a delivery shows how, with the SDK or without it.