如何自定义PayPal订阅审批流程(无需使用默认批准链接)
问题描述
我已通过以下NodeJS代码成功创建PayPal订阅:
const createSubscription = async () => { const accessToken = await getAccessToken(); const response = await axios.post( `${PAYPAL_API}/v1/billing/subscriptions`, { plan_id: subscriptionPlanId, application_context: { brand_name: "test", locale: "en-US", user_action: "SUBSCRIBE_NOW", return_url: "https://test.test/", cancel_url: "https://test.test/", shipping_preference: "NO_SHIPPING", }, }, { headers: { "Content-Type": "application/json", Authorization: `Bearer ${accessToken}`, }, } ); return response.data; };
返回结果如下:
{ status: 'APPROVAL_PENDING', id: 'I-YUSWK0P891TV', create_time: '2024-02-03T15:03:29Z', links: [ { href: 'https://www.sandbox.paypal.com/webapps/billing/subscriptions?ba_token=BA-97806019K4147340Y', rel: 'approve', method: 'GET' }, { href: 'https://api.sandbox.paypal.com/v1/billing/subscriptions/I-YUSWK0P891TV', rel: 'edit', method: 'PATCH' }, { href: 'https://api.sandbox.paypal.com/v1/billing/subscriptions/I-YUSWK0P891TV', rel: 'self', method: 'GET' } ] }
我希望不使用生成的approve链接,自定义整个订阅审批流程,请问PayPal是否支持该需求?若支持,能否提供相关实现指引?
我曾尝试使用@paypal/react-paypal-js SDK,但发现其主要适用于一次性支付场景。
回答
PayPal支持自定义订阅审批流程,你之前对@paypal/react-paypal-js SDK的认知有误——它完全支持订阅场景,是实现自定义审批流程的首选方案。以下是具体实现指引:
一、使用PayPal JS SDK的订阅组件实现自定义流程
1. 配置并加载PayPal JS SDK
在React项目中,通过PayPalScriptProvider加载SDK时,指定components为buttons,subscription,确保订阅功能可用:
import { PayPalScriptProvider } from "@paypal/react-paypal-js"; function App() { return ( <PayPalScriptProvider options={{ "client-id": "你的PayPal客户端ID", components: "buttons,subscription", currency: "USD" }} > {/* 你的订阅组件 */} <CustomSubscriptionButton /> </PayPalScriptProvider> ); }
2. 渲染自定义订阅按钮并处理审批逻辑
使用usePayPalScriptReducer获取SDK加载状态,渲染自定义按钮(或自定义UI),并通过PayPal的订阅API触发审批流程,而非依赖创建订阅后返回的approve链接:
import { usePayPalScriptReducer } from "@paypal/react-paypal-js"; import { useEffect, useRef } from "react"; function CustomSubscriptionButton() { const [{ isPending }] = usePayPalScriptReducer(); const paypalRef = useRef(null); useEffect(() => { if (!isPending && window.paypal) { // 初始化订阅按钮(可自定义样式) window.paypal.Buttons({ createSubscription: async (data, actions) => { // 调用你的后端接口创建订阅(即你已有的createSubscription函数) const subscription = await fetch("/api/create-subscription", { method: "POST", headers: { "Content-Type": "application/json" } }).then(res => res.json()); return subscription.id; // 返回订阅ID给PayPal SDK }, onApprove: async (data, actions) => { // 订阅审批成功后的逻辑:验证订阅状态、更新数据库等 const subscriptionDetails = await fetch(`/api/subscription/${data.subscriptionID}`, { method: "GET", headers: { Authorization: `Bearer ${你的AccessToken}` } }).then(res => res.json()); if (subscriptionDetails.status === "ACTIVE") { // 处理订阅激活后的业务逻辑 console.log("订阅已激活"); } }, onCancel: () => { // 用户取消订阅的逻辑 console.log("用户取消订阅"); }, onError: (err) => { // 错误处理 console.error("订阅出错", err); } }).render(paypalRef.current); } }, [isPending]); return <div ref={paypalRef} />; }
3. 后端验证订阅状态
在onApprove回调中,必须调用PayPal的REST API验证订阅状态,避免前端篡改数据:
// 后端验证订阅状态的示例代码 const verifySubscription = async (subscriptionId) => { const accessToken = await getAccessToken(); const response = await axios.get( `${PAYPAL_API}/v1/billing/subscriptions/${subscriptionId}`, { headers: { Authorization: `Bearer ${accessToken}` } } ); return response.data; };
二、完全自定义UI(不使用PayPal按钮)的实现方式
如果需要完全脱离PayPal的默认按钮样式,可通过以下步骤实现:
- 前端收集用户支付信息(注意:PayPal不允许直接收集信用卡信息,必须使用PayPal的Hosted Fields或Vault API)
- 调用PayPal的
vault/credit-cardsAPI存储支付方式(需获得用户授权) - 创建订阅时,在请求体中指定
payment_source为存储的支付方式ID:
{ plan_id: subscriptionPlanId, payment_source: { card: { id: "存储的信用卡ID" } }, application_context: { /* 你的上下文配置 */ } }
- 订阅创建后,状态会直接变为
ACTIVE(无需用户跳转审批),但需确保用户已授权使用该支付方式。
⚠️ 注意:这种方式需要严格遵守PayPal的PCI合规要求,建议优先使用第一种SDK方案,降低合规风险。
内容的提问来源于stack exchange,提问作者Kariey Zah
相关产品推荐
相关产品推荐

