Kadens sends an HTTPS request to your endpoint each time something happens in your account. Every request is signed, retried until it succeeds and listed in your delivery log.
A webhook is a message Kadens sends to a web address you choose whenever something happens in your account: an order is paid, a ticket is issued, someone checks in. Your system receives it and does the rest, for example adding the buyer to your mailing list or updating a spreadsheet.
Using Zapier, Make, n8n or your own code? They can create and remove endpoints for you with an API key, through the REST API.
Kadens can host a test receiver for you. Choose Try with a test receiver on the Webhooks page: Kadens creates a private test address, connects an endpoint that receives every event and sends it a test event. Each request shows up on that endpoint's page within seconds, with its headers, its body and whether the signature matched.
The test receiver keeps the last 50 requests for 7 days, and the first 64 KB of each body.
Every event arrives in the same JSON envelope, version 2026-10-07. The event itself is in data.
| Field | Type | Description |
|---|---|---|
id | string | Unique id of the event, starting with evt_. The same value arrives in the webhook-id header and stays the same on every retry, resend and replay. |
type | string | The event type, for example order.paid. The event catalog lists them all. |
version | string | The contract version the payload follows. Today it is 2026-10-07. |
occurred_at | string | When it happened, as an ISO 8601 date and time. |
account | { id, name } | The Kadens account the event belongs to: its id and its name. |
subject.type | string | The kind of record the event is about, for example order, booking or subscription. |
subject.id | string | The id of that record. Every event about the same record carries the same id. |
subject.sequence | integer | null | A number that grows with each change to the same record, so you can tell which event is newer. null when the record has no order of changes. |
correlation_id | string | null | Links events that come from the same action, when there is one. Otherwise null. |
livemode | boolean | true for real activity. false for test events, whose ids are also marked as test ids. |
data | object | The event itself. Its fields depend on the type: open a sample in the event catalog. |
{
"id": "evt_2f8a1c7e9b3d4e5fa6c7d8e9f0a1b2c3",
"type": "order.paid",
"version": "2026-10-07",
"occurred_at": "2026-10-01T10:00:00Z",
"account": {
"id": "ent_1a0f",
"name": "Barcelona Salsa Studio"
},
"subject": {
"type": "order",
"id": "ord_91ac04",
"sequence": 2
},
"correlation_id": null,
"livemode": true,
"data": {
"order": {
"id": "ord_91ac04",
"status": "paid",
"created_at": "2026-10-01T09:58:02Z",
"paid_at": "2026-10-01T10:00:00Z",
"event": {
"id": "evt_7f3c2a",
"name": "Salsa Congress Barcelona 2026"
},
"totals": {
"gross": {
"amount": 12000,
"currency": "EUR"
},
"fees": {
"amount": 600,
"currency": "EUR"
},
"net": {
"amount": 11400,
"currency": "EUR"
},
"tax": {
"amount": 2083,
"currency": "EUR"
}
},
"buyer": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
},
"lines": [
{
"ticket_type_id": "tt_full_pass",
"name": "Full pass",
"quantity": 1,
"unit_price": {
"amount": 12000,
"currency": "EUR"
}
}
]
}
}
}Requests follow the Standard Webhooks specification, so the official libraries verify them with no Kadens-specific code. Always verify against the raw body.
| Header | Description |
|---|---|
webhook-id | Unique per event. Use it to ignore a request you already processed. |
webhook-timestamp | Unix seconds when the request was signed. Reject requests more than 300 seconds old. |
webhook-signature | One or more v1 signatures separated by spaces. For 24 hours after you rotate a secret, both the old and the new secret sign. |
// npm install standardwebhooks
import { Webhook } from 'standardwebhooks';
const wh = new Webhook(process.env.KADENS_WEBHOOK_SECRET);
// Use the RAW request body, exactly as received (not re-serialized JSON).
app.post('/webhooks/kadens', express.raw({ type: 'application/json' }), (req, res) => {
try {
const event = wh.verify(req.body.toString('utf8'), req.headers);
// event.type, event.data
res.sendStatus(200);
} catch {
res.sendStatus(400);
}
});The same event can arrive twice, late or out of order. Three habits make your receiver safe.
Store the webhook-id of every event you handle. If the same one arrives again after a retry, a resend or a replay, answer 2xx and skip it.
A retry can make an older event arrive after a newer one. When subject.sequence is set, keep the highest one you handled for each subject.id and ignore anything lower.
Reply 2xx as soon as the event is safely stored, then do the slow work in the background. A reply that takes longer than 10 seconds counts as a failure and is retried.
Answer with any 2xx status to confirm a delivery. Any other status, or no answer, counts as a failure.
A failed delivery is retried 10 more times with growing delays, over about 3 days. You can also resend it or replay a time range from your dashboard.
If your endpoint answers 410 Gone, it is disabled at once and receives nothing more until you enable it.
An endpoint that fails for 5 days without a single success is disabled, and you are notified.
Events and deliveries are kept for 30 days.
Each account can have up to 10 endpoints of its own. Endpoints that Zapier, Make or n8n create do not count toward that limit and have their own ceiling of 50.
| Retry | When |
|---|---|
Retry 1 | 30 seconds after the previous attempt |
Retry 2 | 2 minutes after the previous attempt |
Retry 3 | 10 minutes after the previous attempt |
Retry 4 | 30 minutes after the previous attempt |
Retry 5 | 1 hour after the previous attempt |
Retry 6 | 3 hours after the previous attempt |
Retry 7 | 6 hours after the previous attempt |
Retry 8 | 12 hours after the previous attempt |
Retry 9 | 24 hours after the previous attempt |
Retry 10 | 24 hours after the previous attempt |
Names and email addresses of buyers, ticket holders and attendees are personal data. By default Kadens removes those fields from data before sending, so the endpoint receives the event without them.
To receive them, edit the endpoint and turn on Include personal data. Once the data leaves Kadens, protecting it on your side is your responsibility.
| Action | Description |
|---|---|
Rotate secret | Creates a new signing secret. The old one keeps signing for 24 hours, so you can update your server without missing an event. |
Replay | Sends again every event from a date range that the endpoint missed or failed to receive, up to 30 days back. |
Resend | Sends one delivery again, from the endpoint's delivery log. |
Send test event | Sends a sample of any event type to this endpoint only, marked as a test. |
Disable / Enable | Stops deliveries until you enable the endpoint again. After enabling it, replay the range it missed. |
An endpoint that fails for 5 days without a single success is disabled automatically, and you are notified.
Subscribe an endpoint to the events it needs. Each one shows the data it carries.
order.paidAn order was paid.
{
"order": {
"id": "ord_91ac04",
"status": "paid",
"created_at": "2026-10-01T09:58:02Z",
"paid_at": "2026-10-01T10:00:00Z",
"event": {
"id": "evt_7f3c2a",
"name": "Salsa Congress Barcelona 2026"
},
"totals": {
"gross": {
"amount": 12000,
"currency": "EUR"
},
"fees": {
"amount": 600,
"currency": "EUR"
},
"net": {
"amount": 11400,
"currency": "EUR"
},
"tax": {
"amount": 2083,
"currency": "EUR"
}
},
"buyer": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
},
"lines": [
{
"ticket_type_id": "tt_full_pass",
"name": "Full pass",
"quantity": 1,
"unit_price": {
"amount": 12000,
"currency": "EUR"
}
}
]
}
}order.refundedAn order was refunded, in full or in part.
{
"order": {
"id": "ord_91ac04",
"status": "refunded",
"created_at": "2026-10-01T09:58:02Z",
"paid_at": "2026-10-01T10:00:00Z",
"event": {
"id": "evt_7f3c2a",
"name": "Salsa Congress Barcelona 2026"
},
"totals": {
"gross": {
"amount": 12000,
"currency": "EUR"
},
"fees": {
"amount": 600,
"currency": "EUR"
},
"net": {
"amount": 11400,
"currency": "EUR"
},
"tax": {
"amount": 2083,
"currency": "EUR"
}
},
"buyer": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
},
"lines": [
{
"ticket_type_id": "tt_full_pass",
"name": "Full pass",
"quantity": 1,
"unit_price": {
"amount": 12000,
"currency": "EUR"
}
}
]
},
"refund": {
"id": "ref_0c7d",
"amount": {
"amount": 12000,
"currency": "EUR"
},
"refunded_at": "2026-10-03T08:12:40Z"
}
}checkout.abandonedA buyer started a checkout and left without paying.
{
"checkout": {
"id": "pin_3c8e21",
"item": {
"kind": "course",
"id": "crs_9a20",
"name": "Bachata Foundations"
},
"buyer": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
},
"amount": {
"amount": 9900,
"currency": "EUR"
},
"started_at": "2026-10-01T09:40:00Z"
},
"abandoned_at": "2026-10-01T10:40:00Z"
}ticket.issuedA ticket was issued to its holder.
{
"ticket": {
"id": "tkt_33d0e1",
"order_id": "ord_91ac04",
"status": "active",
"event": {
"id": "evt_7f3c2a",
"name": "Salsa Congress Barcelona 2026"
},
"ticket_type": {
"id": "tt_full_pass",
"name": "Full pass"
},
"holder": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
},
"issued_at": "2026-10-01T10:00:01Z"
}
}ticket.reassignedA ticket was passed to another holder.
{
"ticket": {
"id": "tkt_33d0e1",
"order_id": "ord_91ac04",
"status": "active",
"event": {
"id": "evt_7f3c2a",
"name": "Salsa Congress Barcelona 2026"
},
"ticket_type": {
"id": "tt_full_pass",
"name": "Full pass"
},
"holder": {
"entity_id": "ent_8e40",
"name": "Marco Rossi",
"email": "marco@example.com"
},
"issued_at": "2026-10-01T10:00:01Z"
},
"previous_holder": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
},
"reassigned_at": "2026-10-02T17:30:00Z"
}ticket.canceledA ticket was canceled.
{
"ticket": {
"id": "tkt_33d0e1",
"order_id": "ord_91ac04",
"status": "canceled",
"event": {
"id": "evt_7f3c2a",
"name": "Salsa Congress Barcelona 2026"
},
"ticket_type": {
"id": "tt_full_pass",
"name": "Full pass"
},
"holder": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
},
"issued_at": "2026-10-01T10:00:01Z"
},
"canceled_at": "2026-10-04T12:00:00Z"
}attendee.registeredAn attendee was registered for an event.
{
"attendee": {
"ticket_id": "tkt_33d0e1",
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com",
"event": {
"id": "evt_7f3c2a",
"name": "Salsa Congress Barcelona 2026"
}
},
"registered_at": "2026-10-01T10:05:00Z"
}attendee.checked_inAn attendee was checked in at the door.
{
"attendee": {
"ticket_id": "tkt_33d0e1",
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com",
"event": {
"id": "evt_7f3c2a",
"name": "Salsa Congress Barcelona 2026"
}
},
"checked_in_at": "2026-10-10T19:02:11Z"
}attendee.check_in_revertedA check-in was undone.
{
"attendee": {
"ticket_id": "tkt_33d0e1",
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com",
"event": {
"id": "evt_7f3c2a",
"name": "Salsa Congress Barcelona 2026"
}
},
"reverted_at": "2026-10-10T19:04:30Z"
}attendee.no_showA ticket holder did not check in before the occurrence ended.
{
"attendee": {
"ticket_id": "tkt_33d0e1",
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com",
"event": {
"id": "evt_7f3c2a",
"name": "Salsa Congress Barcelona 2026"
}
},
"finalized_at": "2026-10-10T23:30:00Z"
}event.endedOne of your events finished.
{
"edition": {
"id": "eed_2b71",
"name": "Salsa Congress Barcelona 2026",
"event": {
"id": "evt_7f3c2a",
"name": "Salsa Congress Barcelona"
},
"starts_at": "2026-10-09T16:00:00Z",
"ends_at": "2026-10-11T22:00:00Z",
"timezone": "Europe/Madrid"
},
"ended_at": "2026-10-11T22:00:00Z"
}booking.confirmedA booking for a session was confirmed.
{
"booking": {
"id": "reg_8e17c3",
"status": "reserved",
"session": {
"id": "ses_62f1a8",
"status": "scheduled",
"program": {
"id": "prg_0c4e",
"name": "Contemporary Technique, Level 2"
},
"starts_at": "2026-10-08T17:00:00Z",
"ends_at": "2026-10-08T18:30:00Z",
"timezone": "Europe/Madrid",
"location": {
"delivery_mode": "in_person",
"room": {
"id": "room_a1",
"name": "Studio A"
}
}
},
"attendee": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
}
},
"confirmed_at": "2026-10-01T10:00:00Z"
}booking.declinedA booking request was declined.
{
"booking": {
"id": "reg_8e17c3",
"status": "cancelled",
"session": {
"id": "ses_62f1a8",
"status": "scheduled",
"program": {
"id": "prg_0c4e",
"name": "Contemporary Technique, Level 2"
},
"starts_at": "2026-10-08T17:00:00Z",
"ends_at": "2026-10-08T18:30:00Z",
"timezone": "Europe/Madrid",
"location": {
"delivery_mode": "in_person",
"room": {
"id": "room_a1",
"name": "Studio A"
}
}
},
"attendee": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
}
},
"declined_at": "2026-10-01T10:00:00Z"
}booking.canceledA booking was canceled or expired.
{
"booking": {
"id": "reg_8e17c3",
"status": "cancelled",
"session": {
"id": "ses_62f1a8",
"status": "scheduled",
"program": {
"id": "prg_0c4e",
"name": "Contemporary Technique, Level 2"
},
"starts_at": "2026-10-08T17:00:00Z",
"ends_at": "2026-10-08T18:30:00Z",
"timezone": "Europe/Madrid",
"location": {
"delivery_mode": "in_person",
"room": {
"id": "room_a1",
"name": "Studio A"
}
}
},
"attendee": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
}
},
"reason": "canceled",
"canceled_at": "2026-10-03T09:12:00Z"
}booking.movedA booking was moved to another session.
{
"booking": {
"id": "reg_8e17c3",
"status": "reserved",
"session": {
"id": "ses_7b90d2",
"status": "scheduled",
"program": {
"id": "prg_0c4e",
"name": "Contemporary Technique, Level 2"
},
"starts_at": "2026-10-15T17:00:00Z",
"ends_at": "2026-10-15T18:30:00Z",
"timezone": "Europe/Madrid",
"location": {
"delivery_mode": "in_person",
"room": {
"id": "room_a1",
"name": "Studio A"
}
}
},
"attendee": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
}
},
"previous_session": {
"id": "ses_62f1a8",
"status": "scheduled",
"program": {
"id": "prg_0c4e",
"name": "Contemporary Technique, Level 2"
},
"starts_at": "2026-10-08T17:00:00Z",
"ends_at": "2026-10-08T18:30:00Z",
"timezone": "Europe/Madrid",
"location": {
"delivery_mode": "in_person",
"room": {
"id": "room_a1",
"name": "Studio A"
}
}
},
"moved_at": "2026-10-04T11:40:00Z"
}booking.no_showA booked attendee did not check in before the session ended.
{
"booking": {
"id": "reg_8e17c3",
"status": "reserved",
"session": {
"id": "ses_62f1a8",
"status": "scheduled",
"program": {
"id": "prg_0c4e",
"name": "Contemporary Technique, Level 2"
},
"starts_at": "2026-10-08T17:00:00Z",
"ends_at": "2026-10-08T18:30:00Z",
"timezone": "Europe/Madrid",
"location": {
"delivery_mode": "in_person",
"room": {
"id": "room_a1",
"name": "Studio A"
}
}
},
"attendee": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
}
},
"finalized_at": "2026-10-08T19:30:00Z"
}session.canceledA scheduled session was canceled.
{
"session": {
"id": "ses_62f1a8",
"status": "cancelled",
"program": {
"id": "prg_0c4e",
"name": "Contemporary Technique, Level 2"
},
"starts_at": "2026-10-08T17:00:00Z",
"ends_at": "2026-10-08T18:30:00Z",
"timezone": "Europe/Madrid",
"location": {
"delivery_mode": "in_person",
"room": {
"id": "room_a1",
"name": "Studio A"
}
}
},
"cancellation_reason": "Teacher unwell",
"canceled_at": "2026-10-07T08:00:00Z"
}session.rescheduledA scheduled session was moved to a new time.
{
"session": {
"id": "ses_62f1a8",
"status": "scheduled",
"program": {
"id": "prg_0c4e",
"name": "Contemporary Technique, Level 2"
},
"starts_at": "2026-10-08T18:00:00Z",
"ends_at": "2026-10-08T19:30:00Z",
"timezone": "Europe/Madrid",
"location": {
"delivery_mode": "in_person",
"room": {
"id": "room_a1",
"name": "Studio A"
}
}
},
"previous_starts_at": "2026-10-08T17:00:00Z",
"previous_ends_at": "2026-10-08T18:30:00Z",
"rescheduled_at": "2026-10-06T15:20:00Z"
}pack.credits_lowA class pack fell to its low credit threshold.
{
"pack": {
"id": "pkp_1e90",
"product": {
"id": "pck_10cls",
"name": "10 class pack"
},
"holder": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
},
"credits_remaining": 2,
"credits_total": 10,
"expires_at": "2027-01-31T23:59:59Z"
},
"threshold": 2,
"crossed_at": "2026-10-08T17:00:05Z"
}enrollment.createdA student was enrolled in a course.
{
"enrollment": {
"id": "crs_9a20:ent_31c7",
"course": {
"id": "crs_9a20",
"name": "Bachata Foundations"
},
"edition": {
"id": "ced_4b1e",
"name": "January 2027",
"starts_at": "2027-01-11T18:00:00Z",
"ends_at": "2027-03-29T20:00:00Z",
"timezone": "Europe/Madrid"
},
"student": {
"entity_id": "ent_31c7",
"name": "Lucia Fernandez",
"email": "lucia@example.com"
},
"source": "subscription"
},
"enrolled_at": "2026-12-02T10:15:00Z"
}enrollment.endedA student's enrollment in a course ended.
{
"enrollment": {
"id": "crs_9a20:ent_31c7",
"course": {
"id": "crs_9a20",
"name": "Bachata Foundations"
},
"edition": {
"id": "ced_4b1e",
"name": "January 2027",
"starts_at": "2027-01-11T18:00:00Z",
"ends_at": "2027-03-29T20:00:00Z",
"timezone": "Europe/Madrid"
},
"student": {
"entity_id": "ent_31c7",
"name": "Lucia Fernandez",
"email": "lucia@example.com"
},
"source": "subscription"
},
"ended_at": "2027-02-02T10:15:00Z"
}enrollment.movedA student was moved to another cohort of the course.
{
"enrollment": {
"id": "crs_9a20:ent_31c7",
"course": {
"id": "crs_9a20",
"name": "Bachata Foundations"
},
"edition": {
"id": "ced_7d02",
"name": "April 2027",
"starts_at": "2027-04-12T17:00:00Z",
"ends_at": "2027-06-28T19:00:00Z",
"timezone": "Europe/Madrid"
},
"student": {
"entity_id": "ent_31c7",
"name": "Lucia Fernandez",
"email": "lucia@example.com"
},
"source": "subscription"
},
"previous_edition": {
"id": "ced_4b1e",
"name": "January 2027",
"starts_at": "2027-01-11T18:00:00Z",
"ends_at": "2027-03-29T20:00:00Z",
"timezone": "Europe/Madrid"
},
"moved_at": "2026-12-20T09:00:00Z"
}lesson.completedA student completed a lesson of your course.
{
"enrollment": {
"id": "crs_9a20:ent_31c7",
"course": {
"id": "crs_9a20",
"name": "Bachata Foundations"
},
"edition": {
"id": "ced_4b1e",
"name": "January 2027",
"starts_at": "2027-01-11T18:00:00Z",
"ends_at": "2027-03-29T20:00:00Z",
"timezone": "Europe/Madrid"
},
"student": {
"entity_id": "ent_31c7",
"name": "Lucia Fernandez",
"email": "lucia@example.com"
},
"source": "subscription"
},
"lesson": {
"id": "itm_2f81",
"name": "Basic step and timing"
},
"completed_at": "2026-12-05T19:40:00Z"
}course.completedA student completed your course.
{
"enrollment": {
"id": "crs_9a20:ent_31c7",
"course": {
"id": "crs_9a20",
"name": "Bachata Foundations"
},
"edition": {
"id": "ced_4b1e",
"name": "January 2027",
"starts_at": "2027-01-11T18:00:00Z",
"ends_at": "2027-03-29T20:00:00Z",
"timezone": "Europe/Madrid"
},
"student": {
"entity_id": "ent_31c7",
"name": "Lucia Fernandez",
"email": "lucia@example.com"
},
"source": "subscription"
},
"completed_at": "2027-03-29T20:10:00Z"
}subscription.createdA customer subscribed to a plan.
{
"subscription": {
"id": "sub_4d2e9a",
"status": "active",
"plan": {
"id": "plan_7a10",
"name": "Monthly membership"
},
"price": {
"id": "price_2c3b",
"amount": {
"amount": 4900,
"currency": "EUR"
},
"interval": "month",
"interval_count": 1
},
"current_period_start": "2026-10-01T00:00:00Z",
"current_period_end": "2026-11-01T00:00:00Z",
"cancel_at_period_end": false,
"canceled_at": null,
"customer": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
}
}
}subscription.renewedA subscription renewed and its payment went through.
{
"subscription": {
"id": "sub_4d2e9a",
"status": "active",
"plan": {
"id": "plan_7a10",
"name": "Monthly membership"
},
"price": {
"id": "price_2c3b",
"amount": {
"amount": 4900,
"currency": "EUR"
},
"interval": "month",
"interval_count": 1
},
"current_period_start": "2026-11-01T00:00:00Z",
"current_period_end": "2026-12-01T00:00:00Z",
"cancel_at_period_end": false,
"canceled_at": null,
"customer": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
}
},
"invoice": {
"id": "in_1Q2w3E",
"amount": {
"amount": 4900,
"currency": "EUR"
}
},
"renewed_at": "2026-11-01T00:04:12Z"
}subscription.payment_failedA subscription payment failed.
{
"subscription": {
"id": "sub_4d2e9a",
"status": "past_due",
"plan": {
"id": "plan_7a10",
"name": "Monthly membership"
},
"price": {
"id": "price_2c3b",
"amount": {
"amount": 4900,
"currency": "EUR"
},
"interval": "month",
"interval_count": 1
},
"current_period_start": "2026-10-01T00:00:00Z",
"current_period_end": "2026-11-01T00:00:00Z",
"cancel_at_period_end": false,
"canceled_at": null,
"customer": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
}
},
"access_ends_at": "2026-11-08T00:04:12Z",
"failure_code": "card_declined",
"failed_at": "2026-11-01T00:04:12Z"
}subscription.canceledA subscription was canceled.
{
"subscription": {
"id": "sub_4d2e9a",
"status": "active",
"plan": {
"id": "plan_7a10",
"name": "Monthly membership"
},
"price": {
"id": "price_2c3b",
"amount": {
"amount": 4900,
"currency": "EUR"
},
"interval": "month",
"interval_count": 1
},
"current_period_start": "2026-10-01T00:00:00Z",
"current_period_end": "2026-11-01T00:00:00Z",
"cancel_at_period_end": true,
"canceled_at": null,
"customer": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
}
},
"cancel_at_period_end": true,
"ends_at": "2026-11-01T00:00:00Z",
"canceled_at": "2026-10-15T09:30:00Z"
}subscription.reactivatedA canceled subscription was reactivated.
{
"subscription": {
"id": "sub_4d2e9a",
"status": "active",
"plan": {
"id": "plan_7a10",
"name": "Monthly membership"
},
"price": {
"id": "price_2c3b",
"amount": {
"amount": 4900,
"currency": "EUR"
},
"interval": "month",
"interval_count": 1
},
"current_period_start": "2026-10-01T00:00:00Z",
"current_period_end": "2026-11-01T00:00:00Z",
"cancel_at_period_end": false,
"canceled_at": null,
"customer": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
}
},
"reactivated_at": "2026-10-20T18:00:00Z"
}subscription.plan_changedA customer switched to another plan.
{
"subscription": {
"id": "sub_8f01bc",
"status": "active",
"plan": {
"id": "plan_9b22",
"name": "Full bundle"
},
"price": {
"id": "price_5d6e",
"amount": {
"amount": 8900,
"currency": "EUR"
},
"interval": "month",
"interval_count": 1
},
"current_period_start": "2026-10-01T00:00:00Z",
"current_period_end": "2026-11-01T00:00:00Z",
"cancel_at_period_end": false,
"canceled_at": null,
"customer": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
}
},
"previous_subscription_ids": [
"sub_4d2e9a"
],
"credit_applied": {
"amount": 2450,
"currency": "EUR"
},
"next_billing_at": "2026-11-15T00:00:00Z",
"changed_at": "2026-10-15T12:00:00Z"
}subscription.endedA subscription ended and its access stopped.
{
"subscription": {
"id": "sub_4d2e9a",
"status": "canceled",
"plan": {
"id": "plan_7a10",
"name": "Monthly membership"
},
"price": {
"id": "price_2c3b",
"amount": {
"amount": 4900,
"currency": "EUR"
},
"interval": "month",
"interval_count": 1
},
"current_period_start": "2026-10-01T00:00:00Z",
"current_period_end": "2026-11-01T00:00:00Z",
"cancel_at_period_end": false,
"canceled_at": "2026-11-01T00:00:00Z",
"customer": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
}
},
"reason": "cancellation_requested",
"ended_at": "2026-11-01T00:00:00Z"
}subscription.trial_endingA subscriber's free trial ends in a few days.
{
"subscription": {
"id": "sub_4d2e9a",
"status": "trialing",
"plan": {
"id": "plan_7a10",
"name": "Monthly membership"
},
"price": {
"id": "price_2c3b",
"amount": {
"amount": 4900,
"currency": "EUR"
},
"interval": "month",
"interval_count": 1
},
"current_period_start": "2026-10-01T00:00:00Z",
"current_period_end": "2026-11-01T00:00:00Z",
"cancel_at_period_end": false,
"canceled_at": null,
"customer": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
}
},
"trial_ends_at": "2026-10-15T00:00:00Z"
}certificate.issuedA certificate was issued to its holder.
{
"certificate": {
"id": "icrt_4d19b2",
"number": "KD-2026-000142",
"status": "active",
"certificate": {
"id": "crt_7a02",
"name": "Contemporary Foundations"
},
"template": {
"id": "tpl_31c8",
"name": "2026 cohort"
},
"recipient": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
},
"issued_at": "2026-10-01T10:00:00Z",
"expires_at": null,
"revoked_at": null,
"verification_url": "https://kadens.io/verify-certificate/KD-2026-000142"
}
}certificate.revokedA certificate was revoked.
{
"certificate": {
"id": "icrt_4d19b2",
"number": "KD-2026-000142",
"status": "revoked",
"certificate": {
"id": "crt_7a02",
"name": "Contemporary Foundations"
},
"template": {
"id": "tpl_31c8",
"name": "2026 cohort"
},
"recipient": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
},
"issued_at": "2026-10-01T10:00:00Z",
"expires_at": null,
"revoked_at": "2026-11-12T08:30:00Z",
"verification_url": "https://kadens.io/verify-certificate/KD-2026-000142"
},
"reason": "Issued to the wrong student",
"revoked_at": "2026-11-12T08:30:00Z"
}payout.paidA payout reached your bank account.
{
"payout": {
"id": "po_1Q2w3E4r",
"status": "paid",
"amount": {
"amount": 113400,
"currency": "EUR"
},
"arrival_date": "2026-10-06T00:00:00Z"
},
"paid_at": "2026-10-06T06:14:09Z"
}payout.failedA payout failed and the money did not move.
{
"payout": {
"id": "po_1Q2w3E4r",
"status": "failed",
"amount": {
"amount": 113400,
"currency": "EUR"
},
"arrival_date": "2026-10-06T00:00:00Z"
},
"failure": {
"code": "account_closed",
"message": "The bank account has been closed."
},
"failed_at": "2026-10-06T06:14:09Z"
}lead.capturedA new lead was captured.
{
"lead": {
"id": "lead_4a90",
"audience_id": "aud_12f0",
"email": "lucia@example.com",
"first_name": "Lucia",
"last_name": "Martin",
"consent_at": "2026-10-01T09:12:00Z",
"source": {
"site_id": "site_77a1",
"page_id": "page_home",
"block_id": "blk_newsletter",
"widget_id": null,
"url": "https://salsa.example.com/"
}
},
"captured_at": "2026-10-01T09:12:00Z"
}form.submittedA form was submitted.
{
"submission": {
"id": "sub_61c2",
"form": {
"id": "frm_0d3e",
"title": "Audition application",
"type": "application"
},
"target": {
"scope": "course",
"id": "crs_19ab"
},
"submitter": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
},
"answers": [
{
"field_id": "b2c1e8f0-3a4d-4c5e-9f60-1a2b3c4d5e6f",
"label": "Dance experience",
"type": "textarea",
"value": "Five years of salsa",
"display": "Five years of salsa"
},
{
"field_id": "c3d2f9a1-4b5e-4d6f-8a71-2b3c4d5e6f70",
"label": "Preferred role",
"type": "select",
"value": "follower",
"display": "Follower"
}
],
"submitted_at": "2026-10-02T11:40:00Z"
}
}application.decidedYou approved, rejected or waitlisted an application.
{
"submission": {
"id": "sub_61c2",
"form": {
"id": "frm_0d3e",
"title": "Audition application",
"type": "application"
},
"target": {
"scope": "course",
"id": "crs_19ab"
},
"submitter": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
},
"submitted_at": "2026-10-02T11:40:00Z"
},
"decision": "approved",
"decided_at": "2026-10-06T09:00:00Z"
}exam.results_releasedA candidate can now see their exam results.
{
"submission": {
"id": "sub_61c2",
"form": {
"id": "frm_0d3e",
"title": "Audition application",
"type": "exam"
},
"target": {
"scope": "course",
"id": "crs_19ab"
},
"submitter": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
},
"submitted_at": "2026-10-02T11:40:00Z"
},
"result": {
"passed": true,
"score_percent": 86
},
"released_at": "2026-10-09T12:00:00Z"
}follower.addedSomeone started following you.
{
"follower": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
},
"followed_at": "2026-10-01T08:00:00Z"
}community.member.joinedA member joined one of your communities.
{
"membership": {
"member": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
},
"source": "ticket_holder"
},
"joined_at": "2026-10-01T10:00:02Z"
}community.member.leftA member left one of your communities.
{
"membership": {
"member": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
},
"source": "ticket_holder"
},
"reason": "ticket_released",
"left_at": "2026-10-05T08:00:00Z"
}channel_automation.webhookAn automation reached a Send webhook step for a contact.
{
"automation": {
"id": "aut_2c81f0",
"step_id": "step_send_webhook",
"run_id": "run_8e41d7"
},
"contact": {
"id": "con_51a9e2",
"entity_id": null,
"username": "lucia.dances",
"email": "lucia@example.com",
"tag_ids": [
"tag_vip"
]
},
"channel": {
"type": "instagram",
"account_id": "cha_7d02b1"
},
"fired_at": "2026-10-01T10:00:00Z"
}review.submittedSomeone left a review.
{
"review": {
"id": "rev_8d02",
"rating": 5,
"comment": "Clear, patient and fun.",
"target": {
"kind": "course",
"id": "crs_9a20",
"name": "Bachata Foundations"
},
"author": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
}
},
"submitted_at": "2026-10-12T20:15:00Z"
}feedback.completedYou answered a student's feedback request.
{
"request": {
"id": "fbr_51a7",
"offering": {
"id": "mnt_33c0",
"name": "Video feedback on your solo"
},
"student": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
}
},
"completed_at": "2026-10-14T10:30:00Z"
}reward.expiringA reward you gave someone expires soon.
{
"reward": {
"id": "grw_0a4f",
"name": "Free drop-in class",
"kind": "free_class",
"holder": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
},
"expires_at": "2026-11-01T00:00:00Z"
}
}automation.step_reachedA sequence reached a webhook step for a person.
{
"automation": {
"id": "aut_3c81"
},
"run": {
"id": "run_9d42"
},
"step": {
"id": "s_hotlead",
"key": "hot_lead"
},
"person": {
"entity_id": "ent_5b21",
"name": "Lucia Martin",
"email": "lucia@example.com"
},
"reached_at": "2026-10-03T08:15:00Z"
}webhook.testA test event you sent from Kadens.
{
"message": "This is a test event sent from Kadens."
}Check that the endpoint is enabled and subscribed to the event, and that its address is public and uses HTTPS. Then send a test event and open the delivery to see what your server answered.
Verify against the raw request body, before any JSON parsing. Use the secret of this endpoint, and check your server clock: requests older than 300 seconds are rejected.
That is expected after a retry, a resend or a replay. Skip any webhook-id you already handled.
It failed for 5 days without a success, answered 410 Gone, or someone disabled it. Fix the server, enable the endpoint and replay the range it missed.
Personal data is removed unless the endpoint includes it. See Personal data above.
Was this helpful?