如何通过 webhook 在 PayPal API 中确认每月订阅的账单?
How to confirm billing of a monthly subscription in PayPal API via webhook?
我正在尝试实现一个 PayPal 订阅流程,其中用户点击我通过仪表板创建的 PayPal 订阅按钮。
在后端,我监听订阅计费成功时触发的 PAYMENT.SALE.COMPLETED
webhook。不幸的是,webhook 没有向我发送太多信息,因此我无法在我的数据库中检索链接到刚刚计费订阅的用户和项目。
这将允许我安全地向该用户显示私人内容。
这里是payPal发送的webhook内容(抱歉长度):
const response = {
id: 'WH-4W487015EX264720U-32N35125TV248784B',
event_version: '1.0',
create_time: '2021-04-26T08:24:41.436Z',
resource_type: 'sale',
event_type: 'PAYMENT.SALE.COMPLETED',
summary: 'Payment completed for EUR 6.9 EUR',
resource: {
billing_agreement_id: 'I-T2HP99MJTS1T',
amount: {
total: '6.90',
currency: 'EUR',
details: {
subtotal: '6.90'
}
},
payment_mode: 'INSTANT_TRANSFER',
update_time: '2021-04-26T08:23:59Z',
create_time: '2021-04-26T08:23:59Z',
protection_eligibility_type: 'ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE',
transaction_fee: {
currency: 'EUR',
value: '0.48'
},
protection_eligibility: 'ELIGIBLE',
links: [
{
method: 'GET',
rel: 'self',
href: 'https://api.sandbox.paypal.com/v1/payments/sale/6R7481343K8159132'
},
{
method: 'POST',
rel: 'refund',
href: 'https://api.sandbox.paypal.com/v1/payments/sale/6R7481343K8159132/refund'
}
],
id: '6R7481343K8159132',
state: 'completed',
invoice_number: ''
},
links: [
{
href: 'https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-4W487015EX264720U-32N35125TV248784B',
rel: 'self',
method: 'GET'
},
{
href: 'https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-4W487015EX264720U-32N35125TV248784B/resend',
rel: 'resend',
method: 'POST'
}
],
}
我已经尝试 GET
/v1/payments/sale/:id
但它并没有给我带来太多信息。
我还检查了有关该主题的其他堆栈溢出线程,但没有任何帮助。
我也不想使用前端 SDK 中提供的成功回调,因为它们不如 webhook 安全(连接可以在触发回调之前关闭 see this gitlab issue)
我如何知道用户已为其订阅付费?
我们终于找到了 解决方法 让我们的后端检索买家和物品。
前端
在订阅按钮代码中,我们在大量 trial/errors 之后注意到 createSubscription
方法接受承诺,我们可以使用它在付款前将订阅 ID 发送到后端继续:
paypal.Buttons({
style: {...},
createSubscription: function (data, actions) {
return actions.subscription.create({
/* Creates the subscription */
plan_id: 'P-26J60279VA924454WMCBPBSA',
}).then(subscriptionId => { // subscriptionId == I-9DH5L3A3JAEB
return new Promise((res, rej) => {
// here we send the subscriptionId to the back-end
// and create a pending subscription
const body = {subscriptionId, userId, itemId};
apiCall('POST', '/subscription', body,() => {
// allow to return subscriptionId to paypal
resolve(subscriptionId);
})
});
});
},
onApprove: function (data, actions) {
// this function was of NO USE
// it is not safe to call your backend here
// as connexion can close and paypal doesn't
// wait after this function to capture payment
// thus leading to orphaned subscriptions
// (paid but not linked to your backend)
},
}).render('#paypal-button');
后端(webhook 处理程序)
后端等待确认 webhook,其中 webhookResponse.resource.billing_agreement_id
是订阅 ID 并允许验证之前创建的订阅。我不太明白为什么 billing_agreement_id
没有命名为 subscrition_id
...
让我知道是否不够清楚。在有更好的方法之前,我将其作为答案:)
我正在尝试实现一个 PayPal 订阅流程,其中用户点击我通过仪表板创建的 PayPal 订阅按钮。
在后端,我监听订阅计费成功时触发的 PAYMENT.SALE.COMPLETED
webhook。不幸的是,webhook 没有向我发送太多信息,因此我无法在我的数据库中检索链接到刚刚计费订阅的用户和项目。
这将允许我安全地向该用户显示私人内容。
这里是payPal发送的webhook内容(抱歉长度):
const response = {
id: 'WH-4W487015EX264720U-32N35125TV248784B',
event_version: '1.0',
create_time: '2021-04-26T08:24:41.436Z',
resource_type: 'sale',
event_type: 'PAYMENT.SALE.COMPLETED',
summary: 'Payment completed for EUR 6.9 EUR',
resource: {
billing_agreement_id: 'I-T2HP99MJTS1T',
amount: {
total: '6.90',
currency: 'EUR',
details: {
subtotal: '6.90'
}
},
payment_mode: 'INSTANT_TRANSFER',
update_time: '2021-04-26T08:23:59Z',
create_time: '2021-04-26T08:23:59Z',
protection_eligibility_type: 'ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE',
transaction_fee: {
currency: 'EUR',
value: '0.48'
},
protection_eligibility: 'ELIGIBLE',
links: [
{
method: 'GET',
rel: 'self',
href: 'https://api.sandbox.paypal.com/v1/payments/sale/6R7481343K8159132'
},
{
method: 'POST',
rel: 'refund',
href: 'https://api.sandbox.paypal.com/v1/payments/sale/6R7481343K8159132/refund'
}
],
id: '6R7481343K8159132',
state: 'completed',
invoice_number: ''
},
links: [
{
href: 'https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-4W487015EX264720U-32N35125TV248784B',
rel: 'self',
method: 'GET'
},
{
href: 'https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-4W487015EX264720U-32N35125TV248784B/resend',
rel: 'resend',
method: 'POST'
}
],
}
我已经尝试 GET
/v1/payments/sale/:id
但它并没有给我带来太多信息。
我还检查了有关该主题的其他堆栈溢出线程,但没有任何帮助。 我也不想使用前端 SDK 中提供的成功回调,因为它们不如 webhook 安全(连接可以在触发回调之前关闭 see this gitlab issue)
我如何知道用户已为其订阅付费?
我们终于找到了 解决方法 让我们的后端检索买家和物品。
前端
在订阅按钮代码中,我们在大量 trial/errors 之后注意到 createSubscription
方法接受承诺,我们可以使用它在付款前将订阅 ID 发送到后端继续:
paypal.Buttons({
style: {...},
createSubscription: function (data, actions) {
return actions.subscription.create({
/* Creates the subscription */
plan_id: 'P-26J60279VA924454WMCBPBSA',
}).then(subscriptionId => { // subscriptionId == I-9DH5L3A3JAEB
return new Promise((res, rej) => {
// here we send the subscriptionId to the back-end
// and create a pending subscription
const body = {subscriptionId, userId, itemId};
apiCall('POST', '/subscription', body,() => {
// allow to return subscriptionId to paypal
resolve(subscriptionId);
})
});
});
},
onApprove: function (data, actions) {
// this function was of NO USE
// it is not safe to call your backend here
// as connexion can close and paypal doesn't
// wait after this function to capture payment
// thus leading to orphaned subscriptions
// (paid but not linked to your backend)
},
}).render('#paypal-button');
后端(webhook 处理程序)
后端等待确认 webhook,其中 webhookResponse.resource.billing_agreement_id
是订阅 ID 并允许验证之前创建的订阅。我不太明白为什么 billing_agreement_id
没有命名为 subscrition_id
...
让我知道是否不够清楚。在有更好的方法之前,我将其作为答案:)