智能支付按钮为 IPN 传递自定义变量

Smart Payment Buttons passing custom variable for IPN

我的网站上有两个用于按月订阅的智能按钮(运行良好)。我成功收到了 IPN 响应,其中的付款信息已准备好添加到数据库中。但是我需要通过 IPN 响应获取我的应用程序的 UserID。

我如何通过我的智能支付按钮传递自定义变量,以便它可以传递到 IPN(用于购买交易和 refund/cancellation 如果可能的话?)

这是我的智能按钮代码:

<div id="paypal_button"></div>

<script src="https://www.paypal.com/sdk/js?client-id=[ID]...></script>

<script>
paypal.Buttons({
    style:{
        color:"blue",
        shape:"rect",
        label:"paypal",
        tagline:false
    },
    createSubscription: function(data, actions) {
        return actions.subscription.create({'plan_id': 'P-02S33....'});
    },
    onApprove: function(data, actions) {
        alert('You have successfully created subscription ENTERPRISE' + data.subscriptionID);
    }
}).render('#paypal_button');
</script>

当他完成付款时,我混合使用了 Paypal IPN 和客户重定向响应。

当客户端完成支付后,会调用JS函数onApprove。如果需要,我使用此函数从我的应用程序中收集 data.subscriptionID 和 UserID 以及其他信息。然后我将这些信息发送到我的数据库中( paypal SubscriptionID 和我的案例的 UserID)。

然后我等待贝宝 IPN 呼叫我的路由之一。 IPN 会发送很多关于付款的信息。其中之一是我之前存储的 SubscriptionID。所以我只需要用我拥有的匹配 SubscriptionID 更新我的数据库条目。

为了更安全,如果 Subscription_ID 与我的数据库中的任何条目都不匹配(如果 IPN 在客户端之前触发),我的客户端调用和 IPN 调用都将创建一个新的数据库条目,或者如果客户在拨打客户电话之前关闭了我的网站页面)。

createOrder: function(data, actions) {
   return actions.order.create({
      purchase_units: [{
         invoice_id: 'your_value_1',
         custom_id: 'your_value_2',
         amount: {
            value: '10'
         }
      }]
   });
},

IPN 将包括这些 POST 变量:

$_POST['invoice']; // your_value_1
$_POST['custom']   // your_value_2

更多信息:https://developer.paypal.com/docs/api-basics/notifications/ipn/IPNandPDTVariables/#ipn-transaction-types

您可以像这样将自定义数据传递给订阅按钮:

   <script>
    paypal.Buttons({
        style: {
            shape: 'rect',
            color: 'black',
            layout: 'horizontal',
            label: 'subscribe'
        },
        createSubscription: function(data, actions) {
            let plan = $("#frequency").data("paypal");
          
            return actions.subscription.create({
                'custom_id' : JSON.stringify( {'u': app.session.User_ID } ),
                'plan_id': plan
            });
        },
        onApprove: function(data, actions) {
            console.log(data);
            console.log(actions);
            alert(data.subscriptionID);
        }
    }).render('#paypal-button-container');
</script>

我使用 JSON.stringify 因为它不需要复杂的对象。然后在你的 hook listener 上你将得到以下 json 返回:

{
"id": "...",
"event_version": "1.0",
"create_time": "2021-01-31T15:17:07.379Z",
"resource_type": "subscription",
"resource_version": "2.0",
"event_type": "BILLING.SUBSCRIPTION.ACTIVATED",
"summary": "Subscription activated",
"resource": {
    "quantity": "1",
    "subscriber": {
        "name": {
            "given_name": "John",
            "surname": "Doe"
        },
        "email_address": "...",
        "payer_id": "...",
        "shipping_address": {
            "address": {
                "address_line_1": "1 Main St",
                "admin_area_2": "San Jose",
                "admin_area_1": "CA",
                "postal_code": "95131",
                "country_code": "US"
            }
        }
    },
    "create_time": "2021-01-31T15:16:32Z",
    "custom_id": "{\"u\":1,\"v\":\"yolo\"}",

...

从 2020 年 6 月起,您可以通过 paypal 订阅按钮传递 custom_id,如下所示:

  createSubscription: function(data, actions) {
    return actions.subscription.create({
      plan_id: "P-1234567897897AAA",
      custom_id: "1344", // for example your internal userid
    });
  },

现在使用 webhook(如果您使用 PHP):

// get data from Paypal Webhook POST
$data = json_decode(file_get_contents("php://input"));

error_log('custom_id: '.$data->resource->custom_id);

// also helpful for debugging
error_log(print_r($data, true));

如上所述包含 custom_id 的事件:

  • BILLING.SUBSCRIPTION.CREATED
  • BILLING.SUBSCRIPTION.ACTIVATED

对于事件:

  • PAYMENT.SALE.COMPLETED

您需要使用:

error_log('custom_id: '.$data->resource->custom);

最后没有_id


注意:我写了一个综合教程,希望能帮助开发人员完成工作。 Tutorial: How to integrate Paypal Subscription API with PHP and Javascript (2021) - Complete Guide