You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Stripe Webhooks测试模式下支付后用户订阅未升级的排查修复

Stripe订阅支付后用户未升级至Pro版本排查方案

问题背景

使用Stripe Webhooks实现订阅功能,已开启测试模式。用户完成Pro Plan支付后流程显示正常,但返回网站后仍处于免费计划,未升级到Pro版本。

排查与解决步骤

1. 检查Stripe Webhook配置与触发状态

  • 登录Stripe测试后台,进入Developers > Webhooks,确认监听的checkout.session.completed或customer.subscription.updated事件已正确配置,且Webhook端点能正常接收Stripe的请求。
  • 查看Webhook的Events列表,确认支付完成后对应事件是否已成功发送到你的后端,没有出现失败(比如返回非2xx状态码)。

2. 验证后端Webhook处理逻辑

  • 检查处理Stripe Webhook的后端代码,确认在收到订阅成功事件时,是否正确更新了用户数据库中的订阅状态(比如将isPro字段设为true)。
  • 确保Webhook签名验证通过,Stripe会对请求签名,若验证失败,后端应拒绝处理该事件,这是常见的遗漏点。

3. 检查checkSubscription函数逻辑

  • 查看@/lib/subscription中的checkSubscription函数,确认它是从数据库(或已缓存的用户会话)中读取最新的订阅状态,而不是依赖旧的缓存值或未更新的会话数据。
  • 若使用服务器组件(如SettingsPage是Server Component),确认每次页面渲染时都会重新调用checkSubscription获取最新状态,而非使用静态生成的数据。

4. 确认支付会话的返回路径与用户状态刷新

  • 检查Stripe支付会话创建时的success_url配置,确认用户支付完成后返回网站时,是否触发了用户状态的刷新(比如重新获取用户信息或订阅状态)。
  • 可以在前端返回后手动调用一次订阅状态检查接口,确保页面能实时更新。

5. 测试模式下的事件验证

  • 使用Stripe测试卡号(如4242 4242 4242 4242)完成支付后,在Stripe后台查看对应的订阅记录,确认用户已成功创建Pro Plan订阅。
  • 若Stripe后台显示订阅已创建,但网站未更新,问题大概率出在Webhook处理或后端状态更新环节。

相关代码

ProModal组件代码

"use client";

import { useEffect, useState } from "react";
import axios from "axios";

import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog"
import { useProModal } from "@/hooks/use-pro-modal";
import { Button } from "@/components/ui/button";
import { Separator } from "@/components/ui/separator";
import { useToast } from "@/components/ui/use-toast";

export const ProModal = () => {
  const proModal = useProModal();
  const [isMounted, setIsMounted] = useState(false);
  const [loading, setLoading] = useState(false);
  const { toast } = useToast();

  useEffect(() => {
    setIsMounted(true);
  }, []);


  const onSubscribe = async () => {
    try {
      setLoading(true);
      const response = await axios.get("/api/stripe");

      window.location.href = response.data.url;
    } catch (error) {
      toast({
        description: "Something went wrong",
        variant: "destructive",
      });
    } finally {
      setLoading(false);
    }
  }

  if (!isMounted) {
    return null;
  }

  return (
    <Dialog open={proModal.isOpen} onOpenChange={proModal.onClose}>
      <DialogContent>
        <DialogHeader className="space-y-4">
          <DialogTitle className="text-center">
            Upgrade to Pro
          </DialogTitle>
          <DialogDescription className="text-center space-y-2">
            Create
            <span className="text-sky-500 mx-1 font-medium">Custom AI</span>
            Companions!
          </DialogDescription>
        </DialogHeader>
        <Separator />
        <div className="flex justify-between">
          <p className="text-2xl font-medium">
            $9<span className="text-sm font-normal">.99 / mo</span>
          </p>
          <Button onClick={onSubscribe} disabled={loading} variant="premium">
            Subscribe
          </Button>
        </div>
      </DialogContent>
    </Dialog>
  );
};

SettingsPage页面代码

import { SubscriptionButton } from "@/components/subscription-button";
import { checkSubscription } from "@/lib/subscription";

const SettingsPage = async () => {
  const isPro = await checkSubscription();

  return ( 
    <div className="h-full p-4 space-y-2">
      <h3 className="text-lg font-medium">Settings</h3>
      <div className="text-muted-foreground text-sm">
        {isPro ? "You are currently on a Pro plan." : "You are currently on a free plan."}
      </div>
      <SubscriptionButton isPro={isPro} />
    </div>
   );
}
 
export default SettingsPage;

内容的提问来源于stack exchange,提问作者xchangecode

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 01:03:10