我在为订阅流程集成 Stripe 时遇到集成错误。我收到的错误消息是:
IntegrationError:elements.submit() 必须在 stripe.confirmPayment() 之前调用。一旦客户按下付款键,在任何异步工作之前,立即调用 elements.submit() 。集成指南:https://stripe.com/docs/ payments/accept-a- payment-deferred
上下文:
SetupIntent:我在服务器上创建一个SetupIntent并将clientSecret传递给客户端。
PaymentIntent:我还创建了一个 PaymentIntent 作为订阅创建过程的一部分,并从最新发票的付款意图中接收 client_secret。
流量:
SetupIntent:在服务器端创建SetupIntent。将 client_secret 传递给客户端。
Setup Elements:使用 clientSecret 创建一个选项对象并将其传递给 Elements 标签。
订阅生成器:用户构建其订阅详细信息
表单提交:用户填写并提交付款表单。
表单验证:我调用 elements.submit() 来验证表单字段。
确认SetupIntent:我使用SetupIntent中的clientSecret调用stripe.confirmSetup()。
获取订阅:我调用服务器端并传递用户选择的产品的产品/定价 ID。服务器返回带有 PaymentIntent 的条带订阅对象。
Confirm PaymentIntent:我使用附加到返回的 Stripe Subscription 对象的 PaymentIntent 中的 client_secret 调用 stripe.confirmPayment()。
代码片段:
const handleSubscriptionSubmit = async (e) => {
e.preventDefault();
if (!stripe || !elements) {
toast.error('Error making payment!');
return;
}
//disable loading for now
//setLoading(true);
// Validate the form fields
const { error: submitError } = await elements.submit();
if (submitError) {
setLoading(false);
console.error(submitError);
return;
}
const address = await elements.getElement('address').getValue();
if (!address.complete || !email.complete) {
toast.error('Missing required Email or Address field(s)!');
setLoading(false);
return;
}
// Confirm the SetupIntent
const { setupError } = await stripe.confirmSetup({
elements,
clientSecret: setupIntentOptions.clientSecret,
redirect: 'if_required',
});
if (setupError) {
toast.error('Error making payment setup!');
setLoading(false);
return;
}
formik.setFieldValue('phone', address.value.phone);
formik.setFieldValue('email', email.value.email);
formik.setFieldValue('payer', address.value.name);
formik.setFieldValue('address', address.value.address.line1);
formik.setFieldValue('city', address.value.address.city);
formik.setFieldValue('state', address.value.address.state);
formik.setFieldValue('zip', address.value.address.postal_code);
// Get the subscription intent
const subscriptionIntent = await getSubscriptionIntent();
console.log(subscriptionIntent);
if (!subscriptionIntent) {
setLoading(false);
return;
}
// Confirm the PaymentIntent
const secret = subscriptionIntent.latest_invoice.payment_intent.client_secret;
const { error } = await stripe.confirmPayment({
elements,
clientSecret: secret,
redirect: 'if_required',
});
if (error) {
toast.error(error.message);
setLoading(false);
return;
}
setTimeout(async () => {
await submitOrder();
});
setLoading(false);
};
问题: 尽管在 stripe.confirmPayment() 之前调用 elements.submit(),我仍然收到 IntegrationError 指示 elements.submit() 必须在 stripe.confirmPayment() 之前调用。这表明我的设置可能会被解释为延迟设置,即使我有一个 SetupIntent。
要求: 您能帮我理解为什么会出现此错误以及如何解决它吗?具体来说,我需要有关我的流程是否正确处理订阅设置中的 SetupIntent 和 PaymentIntent 的指导,以及是否需要任何其他步骤或调整来避免此错误。
看起来您在拨打
elements.submit()
后正在确认两个不同的意图。对于 Stripe API 来说这不是必需的,因此 elements.submit()
可能只希望您在提交付款元素后进行一次确认调用。由订阅的第一个发票创建的 PaymentIntent 会将 setup_future_usage
设置为 true
,这将告诉 Stripe 在付款时保存付款方式[1]。如果您删除 SetupIntent 并仅确认订阅的第一次付款意图,则应自动保存 PaymentMethod 并将其附加到订阅的客户。
[1] https://docs.stripe.com/api/ payment_intents/object# payment_intent_object-setup_future_usage