partner
POST /v1/partner/customers/{externalId}/subscriptions/{subscriptionId}/cancel
Cancel a linked customer's subscription at the end of its paid period.
Authentication
Send an API key as a bearer token. The key must carry the partner.domains permission; a key without it is refused with 403, not 404.
This endpoint takes no organisation id. Your key already identifies the organisation it belongs to, and the response is scoped to it.
Try it
Replace anything in angle brackets with your own values, and the key placeholder with a key from your dashboard.
curl -X POST https://api.zinndigital.com/v1/partner/customers/{externalId}/subscriptions/{subscriptionId}/cancel \
-H "Authorization: Bearer zdk_live_…" \
-H "Content-Type: application/json" \
-d '{ }'Signed in? The API console in your dashboard fills in your real organisation id and your own key, and runs the request against the live API so you can see the actual response. Open this endpoint in the API console
Details
Turns renewal off for a subscription you sold the customer. It is exactly the customer's own renewal switch in our dashboard (setSubscriptionAutoRenew with auto_renew: false): the plan stays active until current_period_end, keeps every entitlement until then, and then ends on its own. Nothing is torn down by this call. Requires partner.domains. It never moves money. No refund is issued. A body carrying refund: true is refused with refund_not_offered and nothing is changed — ask us about a refund separately. It is idempotent. Cancelling a subscription whose renewal is already off is a 200 carrying the current state, not a refusal, so a retry after a timeout is safe. Refusals are machine-readable under error.details[].code — error.code is the HTTP class and is not what you branch on. The set is published live as subscriptions.cancel_refusal_codes on getPartnerCapabilities: - not_yours — the subscription is in your linked customer's org, but it was not bought through you (the customer bought it themselves, or through another partner). The customer can stop it from their own dashboard. - already_ended — the subscription is canceled or expired; there is nothing to cancel. - renews_on_paypal — the customer moved this subscription onto a PayPal agreement, and PayPal, not us, takes the next payment. Turning our flag off would not stop PayPal charging, so we refuse rather than answer 200. The customer cancels the agreement in PayPal; the subscription then ends at the end of its period. - refund_not_offered — you asked for a refund. Nothing was changed. - not_applied — the cancellation could not be recorded and nothing was changed. Safe to retry. A customer, subscription or link that does not exist, is not active, or is out of your reach is a 404 carrying details[].code = unknown_reference. The cases are deliberately indistinguishable: telling them apart would report on other tenants' data.
Parameters
| Name | Type | Required | What it is |
|---|---|---|---|
externalId (path) | string | Yes | Your own id for the customer, as linked with createPartnerCustomer. |
subscriptionId (path) | string | Yes | Our subscription id — the subscription_id a fulfilled hosting order reports on getPartnerHostingOrder. |
Request body
| Name | Type | Required | What it is |
|---|---|---|---|
refund | boolean | No | Must be false or absent. true is refused with refund_not_offered and nothing is changed — this route never moves money. |
Response
| Name | Type | Required | What it is |
|---|---|---|---|
subscription_id | string | Yes | — |
org_id | string | Yes | — |
plan_code | string | Yes | — |
status | string<trialing, active, past_due, canceled, expired> | Yes | Unchanged by a cancel — the subscription stays active until its period ends. |
auto_renew | boolean | Yes | Whether it charges again at current_period_end. false after a cancel. |
current_period_end | string | Yes | — |
ends_at | object | Yes | When service stops: current_period_end while renewal is off, null while it renews. |
refunded | boolean | Yes | Always false. This route never moves money. |
Errors this endpoint can return
401 · 403 · 404 · 422 · 429