A valid request URL is required to generate request examples{
"cancellation": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"subscription_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"reason": "too_expensive",
"comment": "<string>",
"offer_shown": "",
"offer_taken": "",
"at_period_end": true,
"confirmed_at": "2023-11-07T05:31:56Z",
"created_at": "2023-11-07T05:31:56Z"
},
"subscription": {}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}Take the save offer instead
Accepts the offer that was made when the reason was recorded, and the subscription lives. Owner-only.
The body names nothing. The offer is the one already on the record, which is what keeps a caller from asking for a discount it was never shown — the tenant’s configuration would otherwise be a suggestion. It also makes “which offer works for which reason” a question the data can answer.
The three offers are the three acts this system can perform: a downgrade (a plan change at the end of the period, never prorated — the person is leaving over what they pay, and a charge today is not what was offered), a pause (the billing stops and the gateway starts it again on a date, so there is no state to be stranded in), and a discount (one of the tenant’s own coupons, applied to the running subscription).
Accepting the same offer twice performs it once. Accepting after the cancellation was confirmed answers 409 — coming back is a new checkout.
A valid request URL is required to generate request examples{
"cancellation": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"subscription_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"reason": "too_expensive",
"comment": "<string>",
"offer_shown": "",
"offer_taken": "",
"at_period_end": true,
"confirmed_at": "2023-11-07T05:31:56Z",
"created_at": "2023-11-07T05:31:56Z"
},
"subscription": {}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}Authorizations
A contact session token, uk_ct_…. Belongs to one of the developer's own users, and reads only that user's data.
Headers
The customer this call is acting inside — the same arrangement as X-Organization-Id, one plane down. Switching customers is navigation, not a mutation: nothing is stored, you send a different header, and the membership JOIN behind it decides what you may do there. An id you are not a member of matches no row and answers 404. Absent, the contact's oldest membership answers.
Forwarded to the payment gateway as its idempotency key, so a retry of this call does not charge twice or move a subscription twice.
This is not the guarantee Idempotency-Key carries on the API-key surface: nothing is stored here and a replay is not answered with the original response. It is passed through, and what it buys is whatever the gateway does with it — for Stripe, the original result is replayed for 24 hours.
Send a fresh key per act you mean to perform, and the same key with the same body when you are retrying one. The gateway compares the parameters, so a key reused for a different act is refused there rather than replayed.
255Path Parameters
The cancellation record's id, from the POST that recorded the reason. It identifies; the caller's membership is what authorizes — another team's id answers 404.
Response
The record with offer_taken set, and the subscription re-read from the gateway.
One person's answer to "why are you leaving", and what happened next.
It is recorded before any gateway is asked anything, so a record exists whether or not the cancellation was ever carried out — and a record nobody carried out is the only churn signal that arrives while the customer is still a customer.
Show child attributes
Show child attributes