Skip to main content

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_due subscription: cancel immediately. There is no period-end grace for an unpaid subscription.
  • 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

ParameterTypeRequiredDescription
idstringYesSubscription UUID

Request Body

ParameterTypeRequiredDefaultDescription
immediatelybooleanNofalseForce 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."
}