Skip to main content
The field is called cancelImmediately. An unknown name — cancelAtPeriodEnd, cancel_immediately — is silently ignored and the call takes the “period end” branch, answering 200 without changing the status. The symptom reads as “cancellation does not work”.

At period end (default)

  • cancelAt is set to currentPeriodEnd. The status does not change: the customer has paid until then, they keep access.
  • A daily cron (03:00 UTC) moves the subscription to canceled once the date is reached, whatever its status at that point — including paused or past_due.
  • No further invoice or reminder goes out for the next cycle. If its anticipated invoice had already been issued at D-3, it is voided when the cancellation executes.
200
There is no route to revoke a scheduled cancellation. A second cancel reschedules it (same date), it does not undo it. To keep the customer, you will have to recreate a subscription at the due date.

Immediately

  • status: "canceled", canceledAt set, cancelAt reset to null.
  • The anticipated invoice for the next cycle is voided in the same transaction: if that void fails, nothing is cancelled and the call returns 500 — retry.
  • No refund is triggered.

The subscription.canceled event goes out twice

This is the trap of this route. On a scheduled cancellation: An immediate cancellation emits it only once, with status: "canceled".
Never cut off access on the event name alone. Read data.status: cutting off at the first emission takes away weeks the customer has paid for.

During a trial

Prefer cancelImmediately: true: see Trials.

Errors