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

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.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 14:47:42