Stripe Connect退款API报no such payment_intent错误排查求助
问题:Stripe退款API返回"no such payment_intent"错误排查
我基于Firebase和FlutterFlow搭建支付系统,集成了Stripe的checkout.session.completed事件Webhook做异步处理。核心逻辑是在购买服务创建出错时自动发起退款,但现在不管是代码里调用还是用Postman测试Stripe退款API,都返回**"no such payment_intent"**错误;只有直接通过/v1/payment_intents接口处理支付时,退款API才能正常工作。已经确认令牌配置正确,也联系了Stripe支持团队,现在需要帮忙排查解决这个问题。
相关代码
const functions = require('firebase-functions'); const admin = require('firebase-admin'); // To avoid deployment errors, do not call admin.initializeApp() in your code const axios = require('axios'); const stripe = require("stripe")(functions.config().stripe.token); const stripeAccount = 'acct_1OT33cQlnlPZnFaP'; exports.stripeWebhook = functions .runWith({ timeoutSeconds: 60, memory: '256MB' }) .https.onRequest(async (req, res) => { let clientReferenceId, amountTotal, paymentIntent, serviceRef, assoRef, stableRef, session; let userDoc, servicesRef, assoRefDoc; try { const event = stripe.webhooks.constructEvent( req.rawBody, req.headers["stripe-signature"], functions.config().stripe.payments_webhook_secret ); if (event.type === 'checkout.session.completed') { const db = admin.firestore(); await db.runTransaction(async (transaction) => { const session = event.data.object; clientReferenceId = session.client_reference_id; amountTotal = session.amount_total; paymentIntent = session.payment_intent; serviceRef = session.metadata.serviceRef; assoRef = session.metadata.assoRef; stableRef = session.metadata.stableRef; userDoc = admin.firestore().collection("user").doc(clientReferenceId); servicesRef = admin.firestore().collection("stable").doc(stableRef) .collection("Services").doc(serviceRef); assoRefDoc = assoRef ? admin.firestore().collection("user").doc(clientReferenceId).collection("Associated").doc(assoRef) : null; paymentDoc = db.collection("stable").doc(stableRef).collection("Payment").doc(); const serviceSnapshot = await transaction.get(servicesRef); const serviceData = serviceSnapshot.data(); if (serviceData.IsByAssociated && !assoRef) { throw new Error('AssocRefId is required for this service.'); } throw new Error('ECCEZIONE DI TEST'); return; transaction.set(paymentDoc, { Typo: 'Payment', AssociatedRef: assoRefDoc ?? '', ServicesRef: servicesRef ?? '', UserRef: userDoc ?? '', NeedAction: false, ManualAction: 'Nessuna', PricePaid: amountTotal / 100, Status: 'PAGAMENTO CONFERMATO', CreationDay: new Date(), }); const currentDate = new Date(); const expirationDate = new Date(currentDate.getTime() + (serviceData.DurationValidityDay * 24 * 60 * 60 * 1000)); transaction.set(userDoc.collection("BuyedServices").doc(), { IsActive: true, Description: serviceData.ShortDescription, Amount: serviceData.Amout || 0, PayedPrice: amountTotal / 100, Residual: serviceData.Amout || 0, IsLezione: serviceData.IsLesson, IsByAssociated: serviceData.IsByAssociated, AssociatedId: assoRefDoc ?? '', CreationDay: new Date(), ExpirationDay: expirationDate, PaymentIntent: paymentIntent }); }); res.sendStatus(200); } else { res.status(400).send('Unhandled event type'); } } catch (err) { //session = event.data.object; clientReferenceId = session.client_reference_id; amountTotal = session.amount_total; paymentIntent = session.payment_intent; serviceRef = session.metadata.serviceRef; assoRef = session.metadata.assoRef; stableRef = session.metadata.stableRef; try { const refundResponse = await stripe.refunds.create({ payment_intent: paymentIntent, // Assicurati che paymentIntent sia un ID valido // Altri dati rilevanti per il rimborso, se necessario }, { stripeAccount: stripeAccount, // Passa l'account ID qui }); console.log(refundResponse.data); // Aggiorna il documento Firestore con le informazioni sul rimborso await admin.firestore().collection("stable").doc(stableRef) .collection("Payment").doc().set({ Typo: 'Refund', AssociatedRef: assoRefDoc ?? '', ServicesRef: servicesRef ?? '', UserRef: userDoc ?? '', NeedAction: false, ManualAction: 'None', PricePaid: amountTotal / 100, Status: 'REFUND CONFIRMED' }); console.error("Error processing webhook, Service Creation API call failed, refound done", err); res.status(500).send('Error processing webhook, Service Creation API call failed, refound done'); } catch (refundError) { await admin.firestore().collection("stable").doc(stableRef) .collection("Payment").doc().set({ Typo: 'RefundError', AssociatedRef: assoRefDoc ?? '', ServicesRef: servicesRef ?? '', UserRef: userDoc ?? '', NeedAction: true, ManualAction: 'Proceed with manual refund', PricePaid: amountTotal / 100, Status: 'ERROR DURING REFUND ATTEMPT' }); // Se si verifica un errore durante il rimborso, gestisci la situazione di conseguenza // Potresti voler registrare il problema o prendere azioni manuali // Invia una risposta al webhook indicando l'errore console.error("Error processing refund:", refundError); res.status(500).send("Error processing refund. Need Human Action"); } } });
错误说明
Postman测试时返回"no such payment_intent"错误提示。
排查方向及解决办法
- 账号上下文不匹配
代码退款时指定了stripeAccount: 'acct_1OT33cQlnlPZnFaP',但Checkout Session对应的Payment Intent可能属于主账号而非该关联账号。检查Checkout Session创建时是否使用了相同的stripeAccount参数,确保支付和退款操作的账号上下文一致。 - Payment Intent ID获取失效
Webhook的catch块中session = event.data.object;被注释,导致paymentIntent变量未从事件对象中获取有效ID,取消注释该行代码即可:session = event.data.object; - Payment Intent有效性校验缺失
部分场景下Checkout Session的payment_intent可能未生成或为临时值,退款前需校验ID格式(以pi_开头):if (!paymentIntent || !paymentIntent.startsWith('pi_')) { throw new Error('无效的Payment Intent ID'); } - API权限不足
确认调用Stripe API的令牌拥有refunds:write权限,且能访问目标账号的Payment Intent资源。
内容的提问来源于stack exchange,提问作者bakns acc
相关产品推荐
相关产品推荐

