Search code examples
paypalpaypal-sandboxpaypal-ipn

Where to enter paypal IPN url and how to pass custom data?


This seems a very naive set of questions, but I really couldn't find it.

Question 1) I am trying to implement IPN for PayPal. I want to enter The listener URL, but I couldn't find where. I've searched the internet and all the responses are old. Where could I put it?

Question 2) I am using the following code and I want to pass custom data so that when IPN sends me back the transaction message, It will have that custom data in it. I need to pass 2 custom data. How is this possible for the following code? I really couldn't find this one in the docs too.

<template>
  <div id="paypal-button-container"></div>
</template>

<script>
export default {
  props: ["amount"],
  mounted() {
    let self = this;
    paypal
      .Buttons({
        createOrder: function(data, actions) {
          // Set up the transaction
          return actions.order.create({
            purchase_units: [
              {
                amount: {
                  value: self.amount,
                }
              }
            ],
          });
        },
        onApprove: function(data, actions) {
          // Capture the funds from the transaction
          return actions.order.capture().then(function(details) {
            // Show a success message to your buyer
            console.log(details);
            self.$emit("paypalPaySuccess", {
              order_id: details.id,
            })
            alert("Transaction completed by " + details.payer.name.given_name);
          }).catch((err)=>{
          })
        }
      })
      .render("#paypal-button-container");
  }
};
</script>

Addition of some questions

I am using all the events in dashboard.

I need to add some more questions, because I can't find the information I need.

Question 3) In client-side, I make action.orders.capture().then . which means that I capture funds immediatelly. When webhooks come to my back-end, there're 2 webhooks that come for single payment . (PAYMENT.CAPTURE.PENDING and CHECKOUT.ORDER.APPROVED) . a) why doesn't PAYMENT.CAPTURE.COMPLETED arrive as webhook event? b) what if I want to get DENIED events? If PAYMENT.CAPTURE.COMPLETED doesn't arrive, PAYMENT.CAPTURE.DENIED won't arrive too.

Question 4) As I said, there're 2 webhook events appearing for single payment on my back-end. The first one has id in it. Let's say I store this in my database as id and status(PENDING). Then another event came which is CHECKOUT.ORDER.APPROVED. Now, this one has different id then the previous one. So I can't really go back to database and update the status as this has different id. What should I do? One thing I noted is that the second came event has also another id (the previous came event) somewhere in captured object. is this what i should use it? which one is the final transaction_id?

Question 5) Turns out invoice_id should be unique each time. So I wanted to pass user_id but i guess i also should generate random string and append it to user_id something like this: invoice_id: '7,randomstring'. right?

Question 6) Same event sometimes comes twice. Why is that? Should I return status 200 in order for that same event not to come again? When will it be good to return that status? I guess after I update the database, right?


Solution

  • Q1: IPN is deprecated. You should be using webhooks, such as CHECKOUT.ORDER.APPROVED

    Q2: There does not appear to be any specific way to pass custom data.

    Option 1:

    What I ended up doing was using the invoice_id field in purchase_units. I tested and found that I could pass a reasonably long string of characters and they did not have to be unique. It seems a bit of a hack but it works.

    When you implement the CHECKOUT.ORDER.APPROVED webhook, you can then parse the data in purchase_unit invoice_id.

    Option 2:

    Another idea I considered which doesn't need to hack the invoice_id, is to send data to the server using the details from the capture event in the javascript, store that custom information, along with the order id in the database, and then when the webhook occurs, cross-match the order id to the saved one to retrieve the information.

    I prefer option 1, but your needs may vary.

    It's pretty indicative though of how poorly designed the whole PayPal API is. There are huge gaps in the implementation, very little documentation, and zero support.

    I had to implement Stripe as well. The entire implementation took me 3 days. The same PayPal implementation took me over 3 weeks! The lack of documentation, having to constantly just try things out, and the inconsistency of the sandbox implementation were real time killers.