Cancel Subscription
Cancel a subscription in your store.
The request is synchronous — the response already reflects the new status /
cancel_at / canceled_at. The customer notification (if any) is dispatched on a webhook
a few seconds later, but the cancellation itself is durable by the time you receive the
200.
Two modes
The endpoint has two behaviours, controlled by the optional immediately flag in the body:
- Omitted (or
false/null) — use the default auto-pick:- Healthy subscription: cancel at the end of the current period. The customer keeps
access until
current_period_end. past_duesubscription: cancel immediately. There is no period-end grace for an unpaid subscription.
- Healthy subscription: cancel at the end of the current period. The customer keeps
access until
immediately: true— force an immediate cancel even on a healthy subscription. The customer loses access right away.
Read the returned cancel_at / canceled_at to confirm which mode applied.
The read response includes an is_cancelable boolean — call
Get subscription first if you want to know whether a cancel request
would succeed for the subscription in its current state.
Request
POST /subscriptions/{id}/cancel
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Subscription UUID |
Request Body
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
immediately | boolean | No | false | Force an immediate cancel even on a healthy subscription. Omit (or send false/null) to use the auto-pick. |
Example Request — auto-pick (period-end or immediate for past_due)
curl -X POST "https://cart.easy.tools/api/v1/subscriptions/550e8400-e29b-41d4-a716-446655440040/cancel" \
-H "Authorization: Bearer YOUR_API_TOKEN"
Example Request — force immediate cancel
curl -X POST "https://cart.easy.tools/api/v1/subscriptions/550e8400-e29b-41d4-a716-446655440040/cancel" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"immediately": true
}'
Response
Success Response (200)
Returns the updated subscription (base fields only; no include sections).
Healthy subscription cancelled at period end
{
"id": "550e8400-e29b-41d4-a716-446655440040",
"remote_id": "sub_1QabcDEFghiJKLmn",
"provider": "stripe",
"status": "active",
"variant_name": "Monthly Plan",
"product_name": "Premium Course",
"recurring_amount": 4900,
"currency": "pln",
"interval": "month",
"interval_count": 1,
"quantity": 1,
"customer_email": "buyer@example.com",
"current_period_start": "2026-05-20T14:02:00+00:00",
"current_period_end": "2026-06-20T14:02:00+00:00",
"trial_end": null,
"cancel_at": "2026-06-20T14:02:00+00:00",
"canceled_at": "2026-05-28T12:00:00+00:00",
"active_until": null,
"active_cycles": null,
"cancel_early": false,
"keep_access_after_expiring": false,
"is_delegated": false,
"is_cancelable": false,
"created_at": "2026-01-15T10:00:00+00:00",
"customer": null,
"variant": null,
"product": null,
"order": null,
"renewals": null,
"upcoming_invoice": null
}
Immediate cancel (immediately: true or past_due)
{
"id": "550e8400-e29b-41d4-a716-446655440040",
"status": "canceled",
"cancel_at": "2026-05-28T12:00:00+00:00",
"canceled_at": "2026-05-28T12:00:00+00:00",
"is_cancelable": false,
"...": "(other fields as above)"
}
See the Get Subscription reference for a full description of each base field.
Error Responses
Bad Request (400)
Returned when the path parameter is not a valid UUID.
{
"message": "Invalid subscription ID"
}
Subscription Not Found (404)
{
"message": "Subscription with ID 550e8400-e29b-41d4-a716-446655440040 not found"
}
Subscription Cannot Be Canceled (422)
Returned when the subscription is not in a cancelable state — for example it has already
been canceled or it is a fixed-cycles plan with cancel_early=false.
{
"message": "Subscription cannot be canceled in its current state."
}
Provider Error (422)
Returned when the payment provider rejects the cancel.
{
"message": "Payment provider rejected the cancellation: <provider message>"
}
Validation Error (422)
Returned when immediately is present but not a boolean.
{
"message": "The given data was invalid.",
"errors": {
"immediately": [
"The immediately field must be true or false."
]
}
}
Unauthorized (401)
{
"message": "Unauthenticated."
}