Skip to content

Cancel a subscription

The subscriptions.cancel operation: POST /api/v1/subscriptions/{id}/cancel in the REST API and the subscriptions_cancel tool in the MCP server.

POST/api/v1/subscriptions/{id}/cancel

Ends a subscription.

  • mode: at_period_end (default): it stays active until the current period ends (cancelAt), then ends; subscriptions.reactivate withdraws the cancellation until then. Emits subscription.cancel_scheduled.
  • mode: now: it ends at once. With prorate: true the unused time of the current period goes to the customer's credit balance (at the prices' amounts, discounts taken into account). With invoiceNow (default) the metered usage up to now and any pending items are invoiced in a final invoice, which the credit balance reduces. An incomplete subscription's unpaid first invoice is voided. Emits subscription.canceled.

mode: now with refund: true refunds the unused time of the current period to the customer's card instead: every paid invoice of the subscription with time left gets a credit note at its original tax rates and a refund (refunds.create with subscription_prorated; you need the refund permission, and support's refund limit applies). An invoice paid by bank transfer or from the credit balance can't be refunded that way (subscription_refund_not_supported: cancel with prorate: true instead).

feedback and comment record why the customer left. The customer's entitlements are recomputed.

The customer is emailed that the subscription is set to end or has ended. reason: replaced says another subscription of the same customer takes its place (for example an upgrade bought through a new checkout): it is recorded as cancellation.reason: replaced, the webhook events go out as usual, and the customer gets no cancellation email, since the new subscription's own emails tell them what runs.

At a glance

  • REST: POST /api/v1/subscriptions/{id}/cancel
  • MCP tool: subscriptions_cancel
  • Operation ID: subscriptions.cancel
  • Scope: Brand
  • Permission: subscriptions:write
  • Risk tier: financial
  • Dry run: Supported (send Ownrecord-Dry-Run: true)
  • Idempotency: Idempotency-Key required
  • Modes: Test and live
  • Authentication: API key with the subscriptions:write scope
  • Since: M5

Request

Path parameters

FieldTypeDescription
idsub_… ID

Body

A JSON object (Content-Type: application/json):

FieldTypeRequiredDescription
expectedVersioninteger (at least 1)No
modeone of at_period_end, nowNoat_period_end (default; it can be reactivated until then) or now.
proratebooleanNonow: credit the unused time of the current period to the customer's credit balance.
refundbooleanNonow: refund the unused time of the current period to the customer's card, with a credit note (needs the refund permission).
invoiceNowbooleanNonow: invoice the metered usage and pending items up to now in a final invoice.
feedbackone of too_expensive, missing_features, switched_service, unused, customer_service, too_complex, low_quality, otherNoWhy the customer is leaving.
commentstringNo
byone of customer, operator, systemNoWho asked: customer or operator (default operator).
reasonone of cancellation_requested, replacedNocancellation_requested (default; the customer is emailed that it ends) or replaced: another subscription of the same customer takes its place (an upgrade bought through a new checkout), so the customer isn't emailed about this one ending.

Response

200 OK with a JSON object:

FieldTypeDescription
idsub_… ID
object"subscription"
livemodeboolean
entityIdent_… ID
brandIdbrd_… ID
customerIdcus_… ID
statusone of incomplete, incomplete_expired, trialing, active, past_due, unpaid, paused, canceledincomplete (waiting for the first payment, 23 hours), trialing, active, past_due, unpaid, paused, canceled or incomplete_expired (spec §16.1).
itemsarray of object
items[].idsi_… ID
items[].priceIdprice_… ID
items[].productIdprod_… ID
items[].quantityinteger
items[].createdAtdate-time
currencystring
mrrmoney or nullThe items' monthly recurring amount (licensed items, before discounts and tax).
collectionMethodone of charge_automatically, send_invoice
daysUntilDueinteger or null
defaultPaymentMethodIdpm_… ID or null
billingCycleAnchordate-time
currentPeriodStartdate-time
currentPeriodEnddate-time
trialStartdate-time or null
trialEnddate-time or null
trialEndBehaviorone of convert, cancel_if_no_payment_method, pause_if_no_payment_method
cancelAtPeriodEndboolean
cancelAtdate-time or null
canceledAtdate-time or null
endedAtdate-time or null
cancellationobject or null
pauseobject or null
discountIdsarray of disc_… ID
pendingUpdateobject or null
latestInvoiceIdinv_… ID or null
incompleteExpiresAtdate-time or null
testClockIdclk_… ID or null
dunningobject or nullDunning (§16.10) while past due or unpaid; null otherwise.
usageThresholdmoney or nullUnbilled metered usage worth this much is invoiced at once (spec §16.7).
entitlementGraceUntildate-time or null
metadataobject
versioninteger
createdAtdate-time
updatedAtdate-time

Examples

Cancel at the end of the period

HTTP
POST /api/v1/subscriptions/sub_01m4tx5nj8emwbyf7y9vcf47z5/cancel
Authorization: Bearer or_test_…
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Content-Type: application/json

{
  "feedback": "too_expensive"
}

Response (200):

JSON
{
  "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "object": "subscription",
  "livemode": false,
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47z4",
  "status": "active",
  "items": [
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47za",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y2",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y0",
      "quantity": 3,
      "createdAt": "2026-10-13T12:00:00.000Z"
    },
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47zb",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y9",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y1",
      "quantity": 1,
      "createdAt": "2026-10-13T12:00:00.000Z"
    }
  ],
  "currency": "EUR",
  "mrr": {
    "amount": "87000000",
    "currency": "EUR"
  },
  "collectionMethod": "charge_automatically",
  "daysUntilDue": null,
  "defaultPaymentMethodId": "pm_01m4tx5nj8emwbyf7y9vcf47zd",
  "billingCycleAnchor": "2026-10-13T12:00:00.000Z",
  "currentPeriodStart": "2026-10-13T12:00:00.000Z",
  "currentPeriodEnd": "2026-11-13T12:00:00.000Z",
  "trialStart": null,
  "trialEnd": null,
  "trialEndBehavior": "convert",
  "cancelAtPeriodEnd": true,
  "cancelAt": "2026-11-13T12:00:00.000Z",
  "canceledAt": null,
  "endedAt": null,
  "cancellation": {
    "reason": "cancellation_requested",
    "feedback": "too_expensive",
    "comment": null,
    "by": "operator"
  },
  "pause": null,
  "discountIds": [],
  "pendingUpdate": null,
  "latestInvoiceId": "inv_01m4tx5nj8emwbyf7y9vcf47zn",
  "incompleteExpiresAt": null,
  "testClockId": null,
  "dunning": null,
  "usageThreshold": null,
  "entitlementGraceUntil": null,
  "metadata": {
    "crm_account": "A-1042"
  },
  "version": 3,
  "createdAt": "2026-10-13T12:00:00.000Z",
  "updatedAt": "2026-10-20T09:00:00.000Z"
}

Cancel now and credit the unused time

HTTP
POST /api/v1/subscriptions/sub_01m4tx5nj8emwbyf7y9vcf47z5/cancel
Authorization: Bearer or_test_…
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Content-Type: application/json

{
  "mode": "now",
  "prorate": true
}

Response (200):

JSON
{
  "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "object": "subscription",
  "livemode": false,
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47z4",
  "status": "canceled",
  "items": [
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47za",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y2",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y0",
      "quantity": 3,
      "createdAt": "2026-10-13T12:00:00.000Z"
    },
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47zb",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y9",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y1",
      "quantity": 1,
      "createdAt": "2026-10-13T12:00:00.000Z"
    }
  ],
  "currency": "EUR",
  "mrr": {
    "amount": "87000000",
    "currency": "EUR"
  },
  "collectionMethod": "charge_automatically",
  "daysUntilDue": null,
  "defaultPaymentMethodId": "pm_01m4tx5nj8emwbyf7y9vcf47zd",
  "billingCycleAnchor": "2026-10-13T12:00:00.000Z",
  "currentPeriodStart": "2026-10-13T12:00:00.000Z",
  "currentPeriodEnd": "2026-11-13T12:00:00.000Z",
  "trialStart": null,
  "trialEnd": null,
  "trialEndBehavior": "convert",
  "cancelAtPeriodEnd": false,
  "cancelAt": null,
  "canceledAt": "2026-10-20T09:00:00.000Z",
  "endedAt": "2026-10-20T09:00:00.000Z",
  "cancellation": {
    "reason": "cancellation_requested",
    "feedback": null,
    "comment": null,
    "by": "operator"
  },
  "pause": null,
  "discountIds": [],
  "pendingUpdate": null,
  "latestInvoiceId": "inv_01m4tx5nj8emwbyf7y9vcf47zn",
  "incompleteExpiresAt": null,
  "testClockId": null,
  "dunning": null,
  "usageThreshold": null,
  "entitlementGraceUntil": null,
  "metadata": {
    "crm_account": "A-1042"
  },
  "version": 3,
  "createdAt": "2026-10-13T12:00:00.000Z",
  "updatedAt": "2026-10-20T09:00:00.000Z"
}

End a subscription another one replaced

The customer upgraded through a new checkout: the old plan ends now, without an email.

HTTP
POST /api/v1/subscriptions/sub_01m4tx5nj8emwbyf7y9vcf47z5/cancel
Authorization: Bearer or_test_…
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Content-Type: application/json

{
  "mode": "now",
  "reason": "replaced"
}

Response (200):

JSON
{
  "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "object": "subscription",
  "livemode": false,
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47z4",
  "status": "canceled",
  "items": [
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47za",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y2",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y0",
      "quantity": 3,
      "createdAt": "2026-10-13T12:00:00.000Z"
    },
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47zb",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y9",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y1",
      "quantity": 1,
      "createdAt": "2026-10-13T12:00:00.000Z"
    }
  ],
  "currency": "EUR",
  "mrr": {
    "amount": "87000000",
    "currency": "EUR"
  },
  "collectionMethod": "charge_automatically",
  "daysUntilDue": null,
  "defaultPaymentMethodId": "pm_01m4tx5nj8emwbyf7y9vcf47zd",
  "billingCycleAnchor": "2026-10-13T12:00:00.000Z",
  "currentPeriodStart": "2026-10-13T12:00:00.000Z",
  "currentPeriodEnd": "2026-11-13T12:00:00.000Z",
  "trialStart": null,
  "trialEnd": null,
  "trialEndBehavior": "convert",
  "cancelAtPeriodEnd": false,
  "cancelAt": null,
  "canceledAt": "2026-10-20T09:00:00.000Z",
  "endedAt": "2026-10-20T09:00:00.000Z",
  "cancellation": {
    "reason": "replaced",
    "feedback": null,
    "comment": null,
    "by": "operator"
  },
  "pause": null,
  "discountIds": [],
  "pendingUpdate": null,
  "latestInvoiceId": "inv_01m4tx5nj8emwbyf7y9vcf47zn",
  "incompleteExpiresAt": null,
  "testClockId": null,
  "dunning": null,
  "usageThreshold": null,
  "entitlementGraceUntil": null,
  "metadata": {
    "crm_account": "A-1042"
  },
  "version": 3,
  "createdAt": "2026-10-13T12:00:00.000Z",
  "updatedAt": "2026-10-20T09:00:00.000Z"
}

Errors

CodeHTTP statusWhenWhat to do
validation_failed400A field is malformed or out of range.Fix the fields listed in details.issues and send the request again.
resource_not_found404No subscription (or customer, price, coupon) with this ID is visible to the request.Check the ID and that your credentials are scoped to the right organization, entity, brand and mode.
version_conflict409The subscription changed since you read it (expectedVersion), or at the same time; read it and retry.Fetch the object again and retry the change.
subscription_status_invalid409The subscription's status doesn't allow this (spec §16.1): see details.reason.Check details.status: items change only while trialing, active or past due; pausing needs an active subscription and resuming a paused one; reactivating needs a cancellation scheduled for the period end; canceled and expired subscriptions don't change.
subscription_refund_not_supported400refund: true, and an invoice with time left wasn't paid by card (bank transfer or credit balance): use prorate: true.An invoice of the current period wasn't paid by card (bank transfer or the credit balance; details.invoice_id). Cancel with prorate: true to credit the unused time to the customer's credit balance, or without it.
refund_limit_exceeded403refund: true by the support role, above the brand's refund limit: finance cancels it.Ask a member with the finance role (or an API key with refunds:admin) to make it, or refund at most details.limit. The limit is the brand's (brands.policies.supportRefundLimits).
registration_required422An invoice issued now can't be taxed: the seller isn't registered where the customer is (a new sale).Register the entity for the regime named in details.regime (see its prerequisites and deadline), or arm the jurisdiction once the prerequisites are done. The customer can join the waitlist meanwhile.
jurisdiction_blocked422The customer's location is blocked for new sales.This jurisdiction isn't covered by usable tax knowledge for this seller. Contact support if you need to sell there.
evidence_conflict422The customer's stored location evidence isn't enough to tax an invoice issued now (§13.3).Collect another piece of location evidence (billing address, card country, or the customer's confirmation of their country) and quote again.
permission_denied403The credentials can't change this brand's subscriptions (subscriptions:write).Ask an organization owner or admin for a role or scope that allows this action.

It can also return these common errors: api_version_unsupported, invalid_json, unsupported_media_type, authentication_required, api_key_invalid, scope_required, idempotency_key_required, idempotency_key_reused, idempotency_in_progress, approval_required, approval_rejected, approval_expired, stale_approval, approval_policy_denied, rate_limited, internal_error.