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.
| Event | What it means |
|---|---|
| order.created an order | An 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 order | The 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 order | The seller marked it shipped. delivery.trackingNumber and delivery.trackingUrl are populated by now if they entered any. |
| order.cancelled an order | The order was cancelled. It may or may not have been paid first — read paymentStatus. |
| order.refunded an order | Money went back. Read refunded against total rather than assuming the whole order: a partial refund fires this too. |
| booking.confirmed an order | An appointment was booked and confirmed. The payload is an order — the booking details are on its booking object. |
| contact.created a contact | Somebody 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 subscription | A membership began. status says whether it started in a trial. |
| subscription.renewed a subscription | A membership renewed and was paid for. currentPeriodEnd has moved. |
| subscription.payment_failed a subscription | A 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 subscription | The member moved to a different plan or interval. price and interval are the new ones. |
| subscription.cancelled a subscription | The 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 subscription | A membership that was set to cancel is running again. cancelAtPeriodEnd is back to false. |
| subscription.ended a subscription | The membership is actually over. This is the one to revoke access on. |
| dispute.opened a dispute | A 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 dispute | The case is finished. status says how it went, and fundsReinstatedAt is set if the money came back. |
Orders
| Event | What it means |
|---|---|
| order.created | An 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 | The 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 | The seller marked it shipped. delivery.trackingNumber and delivery.trackingUrl are populated by now if they entered any. |
| order.cancelled | The order was cancelled. It may or may not have been paid first — read paymentStatus. |
| order.refunded | Money 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
| Event | What it means |
|---|---|
| booking.confirmed | An 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
| Event | What it means |
|---|---|
| contact.created | Somebody 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
| Event | What it means |
|---|---|
| subscription.created | A membership began. status says whether it started in a trial. |
| subscription.renewed | A membership renewed and was paid for. currentPeriodEnd has moved. |
| subscription.payment_failed | A 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 | The member moved to a different plan or interval. price and interval are the new ones. |
| subscription.cancelled | The 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 membership that was set to cancel is running again. cancelAtPeriodEnd is back to false. |
| subscription.ended | The 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
| Event | What it means |
|---|---|
| dispute.opened | A 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 | The 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 building | Subscribe to |
|---|---|
| Fulfilment or accounting | order.paid, order.refunded |
| A CRM sync | contact.created, order.paid |
| Access control for a paid community | subscription.created, subscription.ended, subscription.resumed |
| Dunning email | subscription.payment_failed, subscription.ended |
| Chargeback response | dispute.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.