Webhooks
Events we POST to your endpoints when data changes, so you can react without polling. Each event shares an envelope (id, type, createdAt, data); data is a compact set of the affected record's key fields — fetch the full object via the REST API. Deliveries are signed per Standard Webhooks; see the Webhooks guide for verification, retries and setup.
project.created
A new project was created for one of your customers.
project.updated
A project's fields changed. Re-fetch the project to get the current state.
offer.accepted
A customer accepted an offer — a good trigger to start fulfilment or invoicing.
offer.state_changed
An offer moved between states (e.g. DRAFT → PUBLISHED → ACCEPTED/DECLINED). Includes both the previous and the new state.
project.deleted
A project was deleted. Its offers go with it, so this is the last event you will see for any of them.
customer.created
A customer was added.
customer.updated
A customer's details changed. Only fields the API exposes count as a change — the offer and project counters do not raise this event.
customer.deleted
A customer was deleted.
offer.created
An offer was created. It starts as a DRAFT and is not visible to the customer yet.
offer.updated
An offer was edited. State transitions are reported by offer.state_changed instead, and a price recalculated from its line items does not raise this event.
offer.published
An offer became visible to the customer. Fires alongside offer.state_changed for the transition to PUBLISHED.
offer.deleted
An offer was deleted. Not sent when the offer disappears because its project was deleted — project.deleted covers that.
material.created
A product was added to your catalog. `materialType` says which catalog.
material.updated
A product was renamed, archived or moved to another manufacturer. A new purchase price alone does not raise this event.
material.deleted
A product was removed from your catalog. Products in use by an offer cannot be deleted, only archived.
booking.created
An appointment became a real booking. A free type and a manually entered one fire this the moment they are made; a paid one only once the payment clears. A checkout the customer abandons never fires it at all, so you never have to retract a booking. `source` says where it came from, and `offerRequestId` links a configurator booking to the offer request it produced.
booking.rescheduled
A confirmed appointment moved to another slot, by the customer or by your team. Carries `previousStartsAt` so you can update an existing calendar entry rather than creating a second one.
booking.cancelled
An appointment was cancelled and its slot released. `refunded` says whether money went back; the amount arrives with booking.payment_refunded.
booking.completed
An appointment was marked as having taken place.
booking.no_show
The customer did not turn up for their appointment.
booking.payment_paid
A paid appointment was settled — through Stripe, or marked paid by your team for a booking settled outside it (`paymentMethod: manual`).
booking.payment_refunded
A paid appointment was refunded, usually alongside a cancellation.