From ee110db735bcde08302b458e158e6e46f6449a18 Mon Sep 17 00:00:00 2001 From: Taesu Date: Sat, 19 Sep 2026 17:23:40 +0900 Subject: [PATCH] fix(stripe): set billing anchor for scheduled plan changes --- packages/stripe/src/routes.ts | 1 + packages/stripe/test/subscription.test.ts | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/stripe/src/routes.ts b/packages/stripe/src/routes.ts index fcc2a23198..57c9cb20c4 100644 --- a/packages/stripe/src/routes.ts +++ b/packages/stripe/src/routes.ts @@ -861,6 +861,7 @@ export const upgradeSubscription = (options: StripeOptions) => { { items: newPhaseItems, start_date: currentPhase.end_date, + billing_cycle_anchor: "phase_start", proration_behavior: "none", }, ], diff --git a/packages/stripe/test/subscription.test.ts b/packages/stripe/test/subscription.test.ts index 6642313ac7..6ef07971c2 100644 --- a/packages/stripe/test/subscription.test.ts +++ b/packages/stripe/test/subscription.test.ts @@ -2551,7 +2551,10 @@ describe("stripe subscription", () => { expect(stripeMock.checkout.sessions.create).not.toHaveBeenCalled(); }); - test("should schedule plan change at period end when scheduleAtPeriodEnd is true", async ({ + /** + * @see https://github.com/better-auth/better-auth/issues/11336 + */ + test("should reset the billing cycle anchor for a scheduled plan change", async ({ stripeMock, memory, stripeOptions, @@ -2638,11 +2641,13 @@ describe("stripe subscription", () => { expect.objectContaining({ metadata: { source: "@better-auth/stripe" }, end_behavior: "release", - phases: expect.arrayContaining([ + phases: [ + expect.anything(), expect.objectContaining({ + billing_cycle_anchor: "phase_start", proration_behavior: "none", }), - ]), + ], }), ); expect(stripeMock.billingPortal.sessions.create).not.toHaveBeenCalled();