所以我的产品是一项订阅服务,它允许用户访问我网站上的服务。我已经在 stripe 上创建了该产品,并将付款链接添加到我的网站:
<a
className="bg-red-600 text-white py-2 px-4 rounded inline-block"
target="_blank"
href={`https://buy.stripe.com/test_bIY15h1Jp5eg6409AA?prefilled_email=${session.user.email}`}
> Pay Now
我已经在我的 api 中编写了 webhook.ts 代码,在成功付款后授予用户访问权限,在未付款订阅时撤销访问权限。它在一定程度上起作用;在测试期间,我取消订阅并尝试使用同一电子邮件再次订阅(我将 customerId 添加到用户数据库),stripe 创建另一个客户而不是使用同一客户及其导致的问题
我的 webhookk.ts:
import { NextApiResponse, NextApiRequest } from "next";
import Stripe from "stripe";
import mongooseConnect from "@/lib/mongooseConnect";
import User from "@/models/User";
import Order from "@/models/Order";
import { buffer } from "micro";
const stripe = new Stripe(process.env.STRIPE_SK as string);
const webhookSecret = process.env.STRIPE_ENDPOINT_SECRET as string;
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
await mongooseConnect();
const sig = req.headers['stripe-signature'];
let event: Stripe.Event;
try {
event = stripe.webhooks.constructEvent(await buffer(req), sig!, webhookSecret);
} catch (err: any) {
console.error(`Webhook signature verification failed. ${err.message}`);
return res.status(400).json({ error: err.message });
}
const eventType = event.type;
try {
switch (eventType) {
case 'checkout.session.completed': {
const session = event.data.object as Stripe.Checkout.Session;
const email = session.customer_details?.email;
if (email) {
let user = await User.findOne({ email });
let subscription;
if (typeof session.subscription === 'string') {
subscription = await stripe.subscriptions.retrieve(session.subscription);
} else {
subscription = session.subscription as Stripe.Subscription;
}
const priceId = subscription?.items.data[0]?.price?.id || null;
if (!user) {
// Create a new user if none exists
user = await User.create({
email,
name: session.customer_details?.name || 'Unknown',
stripeCustomerId: session.customer as string,
priceId,
hasAccess: true,
});
} else {
// Update existing user with Stripe Customer ID if it doesn't exist
if (!user.stripeCustomerId) {
user.stripeCustomerId = session.customer as string;
}
// Ensure user has access
user.hasAccess = true;
user.priceId = priceId;
await user.save();
}
// Create an order record
await Order.create({
user: user._id,
name: user.name,
email: user.email,
stripeCustomerId: user.stripeCustomerId,
paid: true,
});
}
break;
}
case 'customer.subscription.deleted': {
const subscription = event.data.object as Stripe.Subscription;
const user = await User.findOne({
stripeCustomerId: subscription.customer as string,
});
if (user) {
// Revoke access
user.hasAccess = false;
await user.save();
}
break;
}
default:
console.log(`Unhandled event type ${event.type}`);
}
} catch (e: any) {
console.error(`Stripe error: ${e.message} | EVENT TYPE: ${eventType}`);
}
return res.status(200).json({ received: true });
}
export const config = {
api: {
bodyParser: false,
},
};
我的模型/用户.ts:
import mongoose, { Schema, model, models } from "mongoose";
const userSchema = new Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: false, default: null },
image: { type: String, required: false },
stripeCustomerId: { type: String, required: false, default: null },
hasAccess: {type: Boolean, required: true, default: false},
priceId: { type: String, required: false, default: null },
emailVerified: { type: Boolean, default: false },
}, {timestamps: true});
const User = models.User || model("User", userSchema);
export default User;
它可以工作,但是在取消订阅并尝试再次付款后,它会在stripe仪表板中创建一个新客户,并且它会弄乱代码,有什么解决方案来解决客户重复吗?
您应该首先创建(或检索,如果有现有客户)一个客户,然后将
customer
传递给结帐会话创建 API,以便 Stripe 将新创建的订阅与该客户关联,而不是创建新客户。请参阅 API