我正在使用 Express 将 PayPal 订阅集成到我的 Node.js 应用程序中,并遇到了将从 PayPal 的 /create-subscription 路由获取的订阅 ID 与 /execute-subscription 路由共享时遇到的问题。
目标是从 /create-subscription 路由的响应中捕获
subscriptionId
:
const response = await axios.post("https://api-m.sandbox.paypal.com/v1/billing/subscriptions", subscriptionDetails, {
headers: {
Authorization: `Bearer ${access_token}`,
},
});
并在 /execute-subscription 路由中使用它来激活订阅:
const subscriptionId = response.data.id;
但是,我不确定如何在这两条路线之间正确通过
subscriptionId
。在 /execute-subscription 路由中直接访问 response.data.id
会导致未定义的错误,可能是因为 response
不在范围内。
paypalRouter.post("/create-subscription", async (req,res) => {
try {
const subscriptionDetails = {
plan_id: process.env.PAYPAL_SANDBOX_BUSSINESS_SUBSCRIPTION_PLAN_ID,
application_context: {
brand_name: "brand",
return_url: "http://localhost:3001/paypal/execute-subscription",
cancel_url: "http://localhost:3001/paypal/cancel-subscription",
}
};
// Generar un token de acceso
const params = new URLSearchParams();
params.append("grant_type", "client_credentials");
const authResponse = await axios.post(
"https://api-m.sandbox.paypal.com/v1/oauth2/token",
params,
{
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
auth: {
username: process.env.PAYPAL_CLIENT_ID,
password: process.env.PAYPAL_SECRET,
},
}
);
const access_token = authResponse.data.access_token;
const response = await axios.post(
"https://api-m.sandbox.paypal.com/v1/billing/subscriptions",
subscriptionDetails,
{
headers: {
Authorization: `Bearer ${access_token}`,
},
}
);
console.log(response.data.id);
console.error();
return res.json({ subscriptionId: response.data.id, ...response.data });
} catch (error) {
console.log(error);
return res.status(500).json("Something goes wrong");
}
});
paypalRouter.get("/execute-subscription", async (req, res) => {
const { token } = req.query; // El token de la suscripción que PayPal envía de vuelta
try {
// Paso 1: Obtener el Token de Acceso
const params = new URLSearchParams();
params.append("grant_type", "client_credentials");
const authResponse = await axios.post("https://api-m.sandbox.paypal.com/v1/oauth2/token", params, {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
auth: {
username: process.env.PAYPAL_CLIENT_ID,
password: process.env.PAYPAL_SECRET,
},
});
const access_token = authResponse.data.access_token;
const subscriptionId = response.data.id;
const executeResponse =
await axios.post(`https://api-m.sandbox.paypal.com/v1/billing/subscriptions/${subscriptionId}/activate`, {}, {
headers: {
Authorization: `Bearer ${access_token}`,
'Content-Type': 'application/json'
},
});
console.log("Subscription confirmed:", executeResponse.data);
console.error();
res.send("Subscription successful!");
} catch (error) {
console.error("Error executing subscription:", error.response ? error.response.data : error.message);
res.status(500).send("An error occurred while executing the subscription.");
}
});
订阅不需要激活除非您指定
application_context.user_action = 'CONTINUE'
。这样做还需要您在激活之前显示订单审核页面,否则会误导付款人。
SUBSCRIBE_NOW 的默认行为避免了在激活之前需要审核页面,因此通常是更可取的。但是,通过该默认行为,订阅将在 PayPal 激活。解决方案是为事件
PAYMENT.SALE.COMPLETED
创建一个 Webhook URL 侦听器。所有订阅逻辑都可以仅基于该事件构建,以刷新订阅的有效日期(无论您如何跟踪它),其他事件名称既不必要也不重要。
此外,对于旧网站来说,从您的网站重定向回 return_url 的行为是一种旧的集成模式。相反,请使用 JS SDK 进行订阅审批。可以仅使用 plan_id 从 JS 创建订阅,或者
createSubscription
函数可以从后端获取已创建订阅的 ID,调用实现问题中逻辑的路由。这种获取 API 调用结果(而不是使用 JS 创建)通常是不必要的,但如果您愿意,也可以这样做。
获得有效的 JS 订阅按钮的一个简单方法是通过 http://www.sandbox.paypal.com/billing/plans ,然后可以根据您的需求进行调整。确保您最终使用的 plan_id 是使用加载 JS SDK 的 client_id 创建的。