BillKit/DocsConsole
Subscriptions

Cancel a subscription

Stops a subscription renewing at the end of the current period, so the customer keeps the access they have already paid for.

POST/v1/subscriptions/{subscription_id}/cancel
Operation cancel_subscription·Scope subscriptions:cancel·OpenAPI v1.1.0

Parameters

ParameterDescription
subscription_idstring · pathrequiredId of the subscription, which starts sub_.

Returns

The subscription with renewal_state: canceling and cancel_at_period_end: true. status stays active until the period is over. Gate access on serves_customer, which turns false at current_period_end. Once the period is over and no charge is still in progress, the subscription becomes canceled with cancellation_reason: “period_end” and canceled_at set to the period end, and subscription.canceled fires. There is no immediate-cancel option.

If the period has already ended and its renewal was never charged, the call ends the subscription at once: status: canceled, cancellation_reason: “period_end”, canceled_at at the old period end, and nothing is charged for the unpaid period. While a renewal payment is still settling, the call returns 409 operation_pending with reason: “renewal_processing”.

The one exception is a price with refund_on_cancel set. When the cancellation issues that refund, the subscription is canceled at once and subscription.canceled fires. See Refunding on cancellation.

Until the boundary passes the customer can change their mind: reactivate clears the pending cancellation with no new checkout. Cancelling an already-cancelling or cancelled subscription returns it unchanged, so a retried call converges on one state. The exception is an already-cancelling subscription while a plan change or payment-method update is in flight for the customer, which returns 409 operation_pending.

Test it

Cancel in test mode, then advance the test clock past current_period_end: no renewal is charged, no further invoice appears, serves_customer reads false, and the subscription becomes canceled with canceled_at at the period end.

Errors

StatusCause
400The request was refused (type: invalid_request_error): a required parameter is missing (parameter_missing), one failed validation (parameter_invalid) or is not one the operation takes (parameter_unknown), and param names it.
401No credential, or one that does not authenticate.
402The account is suspended (tenant_suspended), or the payment provider refused a charge or refund the call made (type: payment_error, code: payment_refused).
403Authenticated, but not allowed: missing scope (insufficient_scope), a key of the wrong mode (mode_mismatch), or a refused origin. Needs the subscriptions:cancel scope.
404No such object in this account and mode.
409Conflicts with the object's current state (state_conflict, or a more specific code), or an operation still in flight (operation_pending).
413The request body is larger than the API accepts.
429Rate limited. Retry-After says when to try again.
500Something failed on BillKit's side (type: api_error). Retry with the same Idempotency-Key.
502The payment provider failed or did not answer.
503Temporarily unable to serve. reason says whether the request was attempted.
Request · curl
curl -X POST https://api.billkit.eu/v1/subscriptions/sub_9XKp2vQ1/cancel \
  -H "Authorization: Bearer $BILLKIT_API_KEY"
Response · 200 OK
{
  "cancel_at_period_end": false,
  "canceled_at": 1789392000,
  "cancellation_reason": "refund_issued",
  "created": 1789392000,
  "current_period_end": 0,
  "current_period_start": 0,
  "customer": {
    "country_code": "NL",
    "email": "ada@example.com",
    "id": "obj_9XKp2vQ1",
    "name": "Ada Lovelace",
    "object": "customer.summary"
  },
  "customer_id": "cus_9XKp2vQ1",
  "discount": {
    "coupon_id": "coup_9XKp2vQ1",
    "ends_at": 1789392000,
    "object": "discount"
  },
  "dunning_attempts_notified": 0,
  "dunning_last_notified_at": 1789392000,
  "id": "sub_9XKp2vQ1",
  "last_payment_at": 1789392000,
  "last_payment_id": "pay_9XKp2vQ1",
  "livemode": false,
  "mrr_cents": 1900,
  "next_charge_amount_cents": 1900,
  "next_payment_attempt": 0,
  "object": "subscription",
  "payment_count": 0,
  "payment_method": {
    "brand": "string",
    "exp_month": 0,
    "exp_year": 0,
    "last4": "string",
    "type": "creditcard"
  },
  "price": {
    "active": false,
    "amount_cents": 1900,
    "billing_scheme": "per_unit",
    "currency": "EUR",
    "id": "obj_9XKp2vQ1",
    "interval": "month",
    "object": "price.summary",
    "payment_methods": [
      "creditcard"
    ],
    "payment_methods_from_account": false,
    "product_id": "prod_9XKp2vQ1",
    "product_name": "Ada Lovelace",
    "tax_behavior": "inclusive",
    "tiers_mode": "graduated",
    "trial_days": 0,
    "unit_amount_decimal": "string",
    "usage_type": "licensed"
  },
  "price_id": "price_9XKp2vQ1",
  "refund_eligibility": {
    "amount_cents": 1900,
    "currency": "EUR",
    "days_remaining": 0,
    "eligible": false,
    "object": "refund_eligibility",
    "reason": "no_charge",
    "window_ends_at": 1789392000
  },
  "renewal_state": "auto_renew",
  "serves_customer": false,
  "status": "incomplete",
  "trial_end": 0,
  "trial_start": 0
}