---
title: "Cancel a subscription"
method: DELETE
path: "/v1/subscriptions/{subscription_id}"
tags: ["Subscriptions"]
---

# Cancel a subscription

`DELETE /v1/subscriptions/{subscription_id}`

Cancel a subscription immediately, or at the end of the current period with cancel_at_period_end. Returns the updated subscription.

## Path parameters

- `subscription_id` string, required

## Request body

- CancelSubscriptionRequest
  - `cancel_at_period_end` boolean — true = cancel at current_period_end; false = cancel immediately.
  - `reason` string, nullable — An optional free-text note recording why the subscription was canceled. Max 255 characters.

## Response `200`

The canceled (or scheduled-to-cancel) subscription

- SubscriptionResponse
  - `id` string — Unique identifier for the subscription.
  - `customer` Customer
    - `customer_id` string — Unique identifier for the customer, prefixed with `cust_`.
    - `email` string, nullable — The customer's email address.
    - `name` string, nullable — The customer's full name. `null` when not set.
    - `phone_number` string, nullable — The customer's phone number in E.164 format, e.g. `+2348012345678`.
    - `metadata` object — Your own key-value data attached to the customer.
    - `created_at` string, date-time, nullable — ISO 8601 timestamp when the customer was created.
    - `updated_at` string, date-time, nullable — ISO 8601 timestamp when the customer was last updated.
  - `payment_method_id` string, nullable — The saved payment method billed on each renewal. `null` until a payment method is attached.
  - `status` 'trialing' | 'active' | 'past_due' | 'unpaid' | 'canceled' | 'paused' — Status of the subscription. Set automatically by Bachs as payments succeed or fail. `trialing`: In a free trial. No payment has been collected yet. `trial_end` marks when billing begins. `active`: Active and paid. Bachs is billing this subscription automatically each cycle. `past_due`: A cycle payment failed. Bachs is retrying the payment while access continues. `unpaid`: Payment retries have been exhausted. Access should be restricted. `canceled`: Canceled and will not renew. This is a terminal state. `paused`: Temporarily suspended. Billing is halted until the subscription resumes.
  - `collection_method` string — How renewals are collected. `charge_automatically` bills the saved card each cycle.
  - `currency` string — The currency the subscription is billed in, as an ISO 4217 code. Subscriptions are USD only today.
  - `amount` string — Recurring amount as a decimal string
  - `billing_cycle` SubscriptionCadence
    - `interval` 'day' | 'week' | 'month' | 'year' — Unit of time for each billing cycle. `day`: billed daily. `week`: billed weekly. `month`: billed monthly. `year`: billed yearly.
    - `frequency` integer — Number of intervals per cycle. For example, `interval` `month` with `frequency` `3` bills every three months.
  - `quantity` integer — Total billable quantity across the subscription's line items.
  - `current_period_start` string, date-time — Start of the period currently being billed for, in UTC.
  - `current_period_end` string, date-time — End of the period currently being billed for, in UTC. The next charge lands at this time unless the subscription is canceled first.
  - `previously_billed_at` string, date-time, nullable — Start of the period that was last billed
  - `next_billed_at` string, date-time, nullable — Next scheduled charge date
  - `trial_end` string, date-time, nullable — When the free trial ends and billing begins, in UTC. `null` if the subscription is not trialing.
  - `cancel_at_period_end` boolean — When `true`, the subscription stays active until `current_period_end` and is not renewed. When `false`, it renews normally.
  - `canceled_at` string, date-time, nullable — When the subscription was canceled, in UTC. `null` if it has not been canceled.
  - `created_at` string, date-time — When the subscription was created, in UTC.
  - `product` SubscriptionCatalogProduct
    - `id` string — Unique identifier for the product.
    - `name` string — The product's name, shown to customers at checkout.
    - `description` string, nullable — The product's description. `null` if none was set.
    - `status` string — Whether the product is active or archived.
    - `billing_cycle` SubscriptionCadence
      - `interval` 'day' | 'week' | 'month' | 'year' — Unit of time for each billing cycle. `day`: billed daily. `week`: billed weekly. `month`: billed monthly. `year`: billed yearly.
      - `frequency` integer — Number of intervals per cycle. For example, `interval` `month` with `frequency` `3` bills every three months.
    - `trial_period` TrialPeriod — The length of the free trial before the first charge, expressed as a count of time units. For example, `{ "interval": "day", "frequency": 14 }` is a 14-day trial.
      - `interval` 'day' | 'week' | 'month' | 'year', required — The unit of time the trial is measured in: `day`, `week`, `month`, or `year`.
      - `frequency` integer, required — How many `interval` units the trial lasts. For example, `interval` `day` with `frequency` `14` is a 14-day trial.
    - `created_at` string, date-time — When the product was created, in UTC.
    - `updated_at` string, date-time — When the product was last updated, in UTC.
  - `items` SubscriptionItem[] — The line items that make up the subscription. Each item ties a product and its price to a billed quantity.
    - `id` string — Unique identifier for the line item.
    - `status` string — Lifecycle status of the item. Follows the parent subscription's status.
    - `quantity` integer — The billed quantity for this item.
    - `recurring` boolean — Whether this item recurs each billing cycle. Always `true` for subscription items.
    - `price_type` 'fixed' | 'free' | 'custom' — How this line item is priced. `fixed`: a set price per cycle, the same for every customer. `free`: no charge. `custom`: the customer chose the amount at checkout, within the product's bounds.
    - `unit_amount` string — Price for one unit of this item, as a decimal string in the item's currency.
    - `currency` string — The currency this item is billed in, as an ISO 4217 code.
    - `previously_billed_at` string, date-time, nullable — When this item was last billed, in UTC. `null` if it has not been billed yet.
    - `next_billed_at` string, date-time, nullable — When this item will next be billed, in UTC.
    - `price` SubscriptionItemPrice
      - `id` string — Unique identifier for the price.
      - `product_id` string — The product this price belongs to.
      - `price_type` 'fixed' | 'free' | 'custom' — How this line item is priced. `fixed`: a set price per cycle, the same for every customer. `free`: no charge. `custom`: the customer chose the amount at checkout, within the product's bounds.
      - `currency` string — The currency of this price, as an ISO 4217 code.
      - `unit_amount` string — Decimal string at the currency's precision
      - `billing_cycle` SubscriptionCadence
        - `interval` 'day' | 'week' | 'month' | 'year' — Unit of time for each billing cycle. `day`: billed daily. `week`: billed weekly. `month`: billed monthly. `year`: billed yearly.
        - `frequency` integer — Number of intervals per cycle. For example, `interval` `month` with `frequency` `3` bills every three months.
      - `trial_period` TrialPeriod — The length of the free trial before the first charge, expressed as a count of time units. For example, `{ "interval": "day", "frequency": 14 }` is a 14-day trial.
        - `interval` 'day' | 'week' | 'month' | 'year', required — The unit of time the trial is measured in: `day`, `week`, `month`, or `year`.
        - `frequency` integer, required — How many `interval` units the trial lasts. For example, `interval` `day` with `frequency` `14` is a 14-day trial.
      - `seat_tiers` object, nullable — Reserved for seat-based pricing. `null` for the standard pricing available today.
      - `is_archived` boolean — Whether the price has been archived. Archived prices keep billing existing subscribers but are not offered for new checkouts.
      - `created_at` string, date-time — When the price was created, in UTC.
      - `updated_at` string, date-time — When the price was last updated, in UTC.
    - `product` SubscriptionCatalogProduct
      - `id` string — Unique identifier for the product.
      - `name` string — The product's name, shown to customers at checkout.
      - `description` string, nullable — The product's description. `null` if none was set.
      - `status` string — Whether the product is active or archived.
      - `billing_cycle` SubscriptionCadence
        - `interval` 'day' | 'week' | 'month' | 'year' — Unit of time for each billing cycle. `day`: billed daily. `week`: billed weekly. `month`: billed monthly. `year`: billed yearly.
        - `frequency` integer — Number of intervals per cycle. For example, `interval` `month` with `frequency` `3` bills every three months.
      - `trial_period` TrialPeriod — The length of the free trial before the first charge, expressed as a count of time units. For example, `{ "interval": "day", "frequency": 14 }` is a 14-day trial.
        - `interval` 'day' | 'week' | 'month' | 'year', required — The unit of time the trial is measured in: `day`, `week`, `month`, or `year`.
        - `frequency` integer, required — How many `interval` units the trial lasts. For example, `interval` `day` with `frequency` `14` is a 14-day trial.
      - `created_at` string, date-time — When the product was created, in UTC.
      - `updated_at` string, date-time — When the product was last updated, in UTC.
    - `created_at` string, date-time — When the item was created, in UTC.
    - `updated_at` string, date-time — When the item was last updated, in UTC.
  - `metadata` object — Your own key-value data attached to the subscription at creation, returned unchanged.

## Other responses

- `400` — Bad Request - Validation errors or invalid request format. Check the `details` object for field-specific validation errors. Common causes: missing required fields, invalid data types, values outside allowed ranges, or invalid formats.
- `401` — Unauthorized - Invalid, missing, or expired API key. Verify your API key is correctly formatted and included in the Authorization header as `Bearer sk_sandbox_...` or `Bearer sk_live_...`. Check that your key hasn't been revoked.
- `403` — Forbidden - API key does not have permission for the requested resource. Verify you're using the correct organization's API key and that you're not trying to access another organization's data.
- `404` — Not Found - The requested resource does not exist. Verify the resource ID is correct and that it belongs to your organization.
- `429` — Too Many Requests - Rate limit exceeded. Standard tier allows 100 requests per minute per API key. Wait a few seconds before retrying. Check X-RateLimit-Reset header for when the window resets.
- `500` — Internal Server Error - An unexpected error occurred while processing the request. Retry with exponential backoff. If the issue persists, contact support with your request context.

---

[API](https://skmtc.dev/bachs/apis/bachs-api.md) · [All operations](https://skmtc.dev/bachs/apis/bachs-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/bachs/bachs-api/revisions/f29efa8a22df/schema)
