Stripe-node问题:获取Checkout Session订单项时metadata为空
问题:Stripe Checkout Session产品Metadata在Webhook中无法获取
场景复现
创建Stripe Checkout Session时,在line_items的price_data.product_data.metadata中传入了自定义产品ID,但在监听checkout.session.completed事件的Webhook里,调用stripe.checkout.sessions.listLineItems获取订单项后,item.price?.metadata?.id返回undefined。
创建Checkout Session的代码:
try { const cart: ICart[] = req.body.cart; const accountEmail: string = req.body.account; const tax: number = req.body.tax; const discountId: string = req.body.discount; const cartItems: Stripe.Checkout.SessionCreateParams.LineItem[] = cart.map((item): Stripe.Checkout.SessionCreateParams.LineItem => { return { price_data: { currency: "mad", product_data: { name: item?.name, description: item?.description, images: item?.images, metadata: { id: item?._id }, }, unit_amount: item?.amount * 100, }, quantity: item?.quantity, }; }); // create the checkout session const session = await stripe.checkout.sessions.create({ currency: "mad", ui_mode: "hosted", line_items: [ ...(cartItems as Stripe.Checkout.SessionCreateParams.LineItem[]), ], billing_address_collection: "required", mode: "payment", customer_email: accountEmail, metadata: { email: accountEmail, tax: tax, discount: discountId, }, success_url: `${env.APP_URL}/success?session_id={CHECKOUT_SESSION_ID}`, cancel_url: `${env.APP_URL}/success?session_id={CHECKOUT_SESSION_ID}`, }); res.status(200).json({ status: "success", session, clientSecret: session.client_secret, }); } catch (err) { console.log(err); }
Webhook代码片段:
// in the webhook's switch case // retrieving the line items case "checkout.session.completed": const checkoutSessionCompleted = event.data.object; // Retrieve the session's line items const lineItems = (await stripe.checkout.sessions.listLineItems(checkoutSessionCompleted.id)).data.map((item) => { return { _id: item.price?.metadata?.id, // returns undefined quantity: item.quantity, // returns the quantity } });
解决方案
问题根源:你把自定义metadata添加到了product_data层级,但通过price_data创建临时价格时,产品的metadata不会自动同步到对应的price对象上。Webhook中获取的line item里的price.metadata是价格对象自身的metadata,而非产品的。
方案一:将metadata直接添加到price_data层级(推荐)
修改创建Session时的cartItems映射,把metadata从product_data移到price_data下:
const cartItems: Stripe.Checkout.SessionCreateParams.LineItem[] = cart.map((item): Stripe.Checkout.SessionCreateParams.LineItem => { return { price_data: { currency: "mad", product_data: { name: item?.name, description: item?.description, images: item?.images, }, unit_amount: item?.amount * 100, metadata: { id: item?._id }, // 移至price_data层级 }, quantity: item?.quantity, }; });
修改后,Webhook中item.price?.metadata?.id即可正确获取到产品ID。
方案二:通过产品ID单独获取产品metadata(不推荐,多API请求)
如果必须将metadata存在产品对象上,Webhook中需要先通过price关联的产品ID获取产品对象,再读取其metadata:
// in the webhook's switch case case "checkout.session.completed": const checkoutSessionCompleted = event.data.object; // 用Promise.all并行获取产品metadata const lineItems = await Promise.all( (await stripe.checkout.sessions.listLineItems(checkoutSessionCompleted.id)).data.map(async (item) => { if (!item.price?.product) return null; const product = await stripe.products.retrieve(item.price.product as string); return { _id: product.metadata.id, quantity: item.quantity, }; }) ); // 过滤掉null项 const validLineItems = lineItems.filter(Boolean);
内容的提问来源于stack exchange,提问作者Simo D.
相关产品推荐
相关产品推荐

