From c421a66fa594f99ad820002cdb3fe7235e717128 Mon Sep 17 00:00:00 2001
From: majdyz
Date: Wed, 15 Apr 2026 13:25:42 +0700
Subject: [PATCH] fix(platform): fix Stripe customer creation on FREE downgrade
and dialog display issues
- Guard cancel_stripe_subscription with stripe_customer_id check to prevent
creating orphaned Stripe customers for users who never had a paid subscription
- Fix upgrade dialog showing raw tier key (PRO) instead of human-readable label (Pro)
- Fix misleading footer text that contradicted downgrade-to-FREE behaviour
(downgrades to Free are scheduled at period end, not immediate)
---
autogpt_platform/backend/backend/data/credit.py | 10 +++++++++-
.../SubscriptionTierSection.tsx | 9 ++++++---
2 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/autogpt_platform/backend/backend/data/credit.py b/autogpt_platform/backend/backend/data/credit.py
index cc77df8d3d..633dd13837 100644
--- a/autogpt_platform/backend/backend/data/credit.py
+++ b/autogpt_platform/backend/backend/data/credit.py
@@ -1353,7 +1353,15 @@ async def cancel_stripe_subscription(user_id: str) -> bool:
Raises stripe.StripeError if any modification fails, so the caller can avoid
updating the DB tier when Stripe is inconsistent.
"""
- customer_id = await get_stripe_customer_id(user_id)
+ # Guard: only proceed if the user already has a Stripe customer ID. Calling
+ # get_stripe_customer_id for a user who has never had a paid subscription would
+ # create an orphaned, potentially-billable Stripe Customer object — we avoid that
+ # by returning False early so the caller can downgrade the DB tier directly.
+ user = await get_user_by_id(user_id)
+ if not user.stripe_customer_id:
+ return False
+
+ customer_id = user.stripe_customer_id
try:
cancelled_count = await _cancel_customer_subscriptions(
customer_id, at_period_end=True
diff --git a/autogpt_platform/frontend/src/app/(platform)/profile/(user)/credits/components/SubscriptionTierSection/SubscriptionTierSection.tsx b/autogpt_platform/frontend/src/app/(platform)/profile/(user)/credits/components/SubscriptionTierSection/SubscriptionTierSection.tsx
index 6246c37e36..555e00bd5a 100644
--- a/autogpt_platform/frontend/src/app/(platform)/profile/(user)/credits/components/SubscriptionTierSection/SubscriptionTierSection.tsx
+++ b/autogpt_platform/frontend/src/app/(platform)/profile/(user)/credits/components/SubscriptionTierSection/SubscriptionTierSection.tsx
@@ -196,8 +196,9 @@ export function SubscriptionTierSection() {
{currentTier !== "FREE" && isPaymentEnabled && (
- Your subscription is managed through Stripe. Changes take effect
- immediately.
+ Your subscription is managed through Stripe. Upgrades and paid-tier
+ changes take effect immediately; downgrades to Free are scheduled for
+ the end of the current billing period.
)}
@@ -249,7 +250,9 @@ export function SubscriptionTierSection() {
subscription.proration_credit_cents > 0 &&
`Your unused ${currentTier.charAt(0) + currentTier.slice(1).toLowerCase()} subscription ($${(subscription.proration_credit_cents / 100).toFixed(2)}) will be added to your account balance. `}
You will be redirected to Stripe to complete your upgrade to{" "}
- {pendingUpgradeTier}.
+ {TIERS.find((t) => t.key === pendingUpgradeTier)?.label ??
+ pendingUpgradeTier}
+ .