Skip to main content
Le champ s’appelle cancelImmediately. Un nom inconnu — cancelAtPeriodEnd, cancel_immediately — est ignoré en silence et l’appel part sur la branche « fin de période », en répondant 200 sans changer le statut. Le symptôme se lit « l’annulation ne marche pas ».

En fin de période (défaut)

  • cancelAt est posé à currentPeriodEnd. Le statut ne change pas : le client a payé jusque-là, il garde l’accès.
  • Un cron quotidien (3 h UTC) passe l’abonnement canceled une fois la date atteinte, quel que soit son statut à ce moment — y compris paused ou past_due.
  • Plus aucune facture ni rappel ne part pour le cycle suivant. Si sa facture anticipée avait déjà été émise à J-3, elle est annulée (void) au moment où l’annulation s’exécute.
200
Il n’existe pas de route pour révoquer une annulation programmée. Un second cancel la reprogramme (même date), il ne l’annule pas. Pour garder le client, il faudra recréer un abonnement à l’échéance.

Immédiatement

  • status: "canceled", canceledAt posé, cancelAt remis à null.
  • La facture anticipée du cycle suivant est annulée dans la même transaction : si cette annulation échoue, rien n’est annulé et l’appel rend 500 — réessayez.
  • Aucun remboursement n’est déclenché.

L’événement subscription.canceled part deux fois

C’est le piège de cette route. Sur une annulation programmée : Une annulation immédiate n’en émet qu’un, avec status: "canceled".
Ne coupez jamais un accès sur le seul nom de l’événement. Lisez data.status : couper à la première émission retire au client des semaines qu’il a payées.

Pendant un essai

Préférez cancelImmediately: true : voir Essais.

Erreurs