6

I have two Smart button on my website for a monthly subscription (working well). I successfully receive the IPN response with the payment information ready to be added to the Database. But I need to get the UserID of my application with the IPN response.

How can I pass custom variable with my Smart payment button so it can be passed to the IPN (for buying transaction and refund/cancellation ones if possible?)

Here is my Smart button code :

<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>
Tryall
  • 640
  • 12
  • 22

4 Answers4

5

From June 2020 you can pass a custom_id with the paypal subscription button like this:

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

Now with the webhook (if you use 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));

Events that have the custom_id included as described above:

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

For event:

  • PAYMENT.SALE.COMPLETED

You need to use:

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

Without the _id in the end.


Note: I have written a comprehensive tutorial that hopefully will help developers to get things done. Tutorial: How to integrate Paypal Subscription API with PHP and Javascript (2021) - Complete Guide

Avatar
  • 14,622
  • 9
  • 119
  • 198
4
createOrder: function(data, actions) {
   return actions.order.create({
      purchase_units: [{
         invoice_id: 'your_value_1',
         custom_id: 'your_value_2',
         amount: {
            value: '10'
         }
      }]
   });
},

IPN will include these POST variables:

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

More info: https://developer.paypal.com/docs/api-basics/notifications/ipn/IPNandPDTVariables/#ipn-transaction-types

TomoMiha
  • 1,218
  • 1
  • 14
  • 12
0

I used a mix between the Paypal IPN and the Client redirection response when he finished the payment.

When the client finish his payment, It will call the JS function onApprove. I use this function to gather the data.subscriptionID with the UserID and other information from my application if needed. I then send thoses information inside my Database (The paypal SubscriptionID and my UserID for my case).

I then wait for the paypal IPN to call one of my routes. The IPN will sent a lot of information about the payment. One of them is the SubscriptionID i stored earlier. So I just need to update my Database entry with the matching SubscriptionID I have.

For more security, both of my Client Call and the IPN Call will create a new DB entry if the Subscription_ID is not matching any entry in my Database (in case of the IPN is triggered before the Client, or if the client closed my Website page before making the client Call).

Tryall
  • 640
  • 12
  • 22
  • This is not a good idea, because if the connection get lost in any point between the call to Paypal, and the call to your own server after the postback of Paypal, then you will never correlate the subscription id with the user id. It's better the solution in which a custom id is passed directly in the payload. – freesoul Jul 30 '21 at 19:26
0

You can pass in custom data to a subscribe button like this:

   <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>

I use JSON.stringify because its not expecting a complex object. Then on your hook listener you will get the following json back:

{
"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\"}",

...

Todd Horst
  • 853
  • 10
  • 22