Skip to Content
WebhooksEvents

Events

16 events, in five families. Every event sharing a prefix carries the same object, so subscribing to a second event in a family you already handle costs you no remapping.

Every webhook event, what it means, and the object it carries
EventWhat it means
order.created an orderAn order exists. On a card sale this arrives together with order.paid, at the moment the payment lands — not when the buyer opened the checkout, because about a third of those are abandoned. On bank transfer, cash or any other manual rail it fires at checkout, before any money has moved.
order.paid an orderThe money arrived. On a manual rail this is the seller confirming it, which can be days after order.created. This is the event to fulfil on.
order.shipped an orderThe seller marked it shipped. delivery.trackingNumber and delivery.trackingUrl are populated by now if they entered any.
order.cancelled an orderThe order was cancelled. It may or may not have been paid first — read paymentStatus.
order.refunded an orderMoney went back. Read refunded against total rather than assuming the whole order: a partial refund fires this too.
booking.confirmed an orderAn appointment was booked and confirmed. The payload is an order — the booking details are on its booking object.
contact.created a contactSomebody new joined the shop's list. Not evidence of marketing consent: read marketingConsentAt, which is null unless they went through a double opt-in.
subscription.created a subscriptionA membership began. status says whether it started in a trial.
subscription.renewed a subscriptionA membership renewed and was paid for. currentPeriodEnd has moved.
subscription.payment_failed a subscriptionA renewal payment did not go through. This is not an ending. Stripe retries for a few days and most of them recover, so treat it as a reason to email rather than a reason to revoke — subscription.ended arrives if it never clears.
subscription.plan_changed a subscriptionThe member moved to a different plan or interval. price and interval are the new ones.
subscription.cancelled a subscriptionThe member asked to stop. They have paid through currentPeriodEnd and keep their access until it — revoking here takes away a month they already bought.
subscription.resumed a subscriptionA membership that was set to cancel is running again. cancelAtPeriodEnd is back to false.
subscription.ended a subscriptionThe membership is actually over. This is the one to revoke access on.
dispute.opened a disputeA buyer charged back one of the seller's sales. dueBy is the response deadline — usually about twenty days — and caseType says whether any money has moved yet. Only ever a buyer's chargeback against a seller's sale; a seller disputing their own Sailo subscription is Sailo's problem and never appears here.
dispute.closed a disputeThe case is finished. status says how it went, and fundsReinstatedAt is set if the money came back.

Orders

The order.* events
EventWhat it means
order.createdAn order exists. On a card sale this arrives together with order.paid, at the moment the payment lands — not when the buyer opened the checkout, because about a third of those are abandoned. On bank transfer, cash or any other manual rail it fires at checkout, before any money has moved.
order.paidThe money arrived. On a manual rail this is the seller confirming it, which can be days after order.created. This is the event to fulfil on.
order.shippedThe seller marked it shipped. delivery.trackingNumber and delivery.trackingUrl are populated by now if they entered any.
order.cancelledThe order was cancelled. It may or may not have been paid first — read paymentStatus.
order.refundedMoney went back. Read refunded against total rather than assuming the whole order: a partial refund fires this too.

order.created and order.paid arrive together on a card sale, at the moment the payment lands — not when the buyer opened the checkout, because about a third of those are abandoned and an integration that fired on each would report three times the real order count.

On bank transfer, cash or any other manual rail they are days apart: order.created at checkout, order.paid when the seller confirms the money arrived.

So: fulfil on order.paid, not on order.created.

order.refunded fires on a partial refund too. Read refunded against total rather than assuming the whole sale went back.

Bookings

The booking.* events
EventWhat it means
booking.confirmedAn appointment was booked and confirmed. The payload is an order — the booking details are on its booking object.

The payload is an order — the appointment is on its booking object. It is not a separate resource, because a booking is a sale of a service and everything else about it is an order.

Contacts

The contact.* events
EventWhat it means
contact.createdSomebody new joined the shop's list. Not evidence of marketing consent: read marketingConsentAt, which is null unless they went through a double opt-in.

contact.created is not consent to email that person. Read marketingConsentAt on the payload: it is null unless they went through a double opt-in and clicked the link, and null means no.

Memberships

The subscription.* events
EventWhat it means
subscription.createdA membership began. status says whether it started in a trial.
subscription.renewedA membership renewed and was paid for. currentPeriodEnd has moved.
subscription.payment_failedA renewal payment did not go through. This is not an ending. Stripe retries for a few days and most of them recover, so treat it as a reason to email rather than a reason to revoke — subscription.ended arrives if it never clears.
subscription.plan_changedThe member moved to a different plan or interval. price and interval are the new ones.
subscription.cancelledThe member asked to stop. They have paid through currentPeriodEnd and keep their access until it — revoking here takes away a month they already bought.
subscription.resumedA membership that was set to cancel is running again. cancelAtPeriodEnd is back to false.
subscription.endedThe membership is actually over. This is the one to revoke access on.

Three distinctions here, and each one is a real support ticket:

cancelled is not ended. The first is the member asking to stop; they have paid through currentPeriodEnd and keep their access until it. The second is the arrangement actually being over. Revoke on ended. Cutting somebody off at the cancellation takes away a month they already bought.

payment_failed is not an ending either. Stripe retries for several days and most recover. Email them; do not revoke. If it never clears, subscription.ended arrives.

A manual membership will never send you a card renewal. Read billingMode: manual means Sailo raises a renewal order that a human settles, so nothing arrives from Stripe about it. An integration waiting for one waits forever.

The membership access guide turns all of this into a working state machine.

Chargebacks

The dispute.* events
EventWhat it means
dispute.openedA buyer charged back one of the seller's sales. dueBy is the response deadline — usually about twenty days — and caseType says whether any money has moved yet. Only ever a buyer's chargeback against a seller's sale; a seller disputing their own Sailo subscription is Sailo's problem and never appears here.
dispute.closedThe case is finished. status says how it went, and fundsReinstatedAt is set if the money came back.

dispute.opened fires when a buyer charges back one of the seller’s sales, with the deadline in dueBy — usually around twenty days.

It is the event to hang evidence-gathering off, because what wins a case normally lives in a helpdesk or a shipping account rather than in Sailo.

Check caseType before telling anybody they have lost a sale. An inquiry is a question from the issuer and has taken no money; a chargeback has.

Only ever emitted for a buyer’s chargeback against a seller’s sale. A seller disputing their own Sailo subscription is Sailo’s problem and never appears here.

Choosing which to subscribe to

Tick what you will act on and nothing else. Every extra event is a delivery row per endpoint per occurrence, and a consumer that receives events it ignores is one whose logs are mostly noise on the day something goes wrong.

A reasonable starting set for most integrations:

If you are buildingSubscribe to
Fulfilment or accountingorder.paid, order.refunded
A CRM synccontact.created, order.paid
Access control for a paid communitysubscription.created, subscription.ended, subscription.resumed
Dunning emailsubscription.payment_failed, subscription.ended
Chargeback responsedispute.opened, dispute.closed

Adding an event later

Nothing about the events you already receive changes. New fields may appear inside data without the payload version changing — see versioning — so build your mapping to ignore fields it does not recognise, and adding a subscription is a change on Sailo’s side only.

Last updated on