6

I've been working on a project for over 2 years and I am finally ready to launch, but first I have to integrate a subscription based payment option so I can actually make some money off of this thing. I've been trying to integrate paypal subscriptions for like 2 months now and it's a major hold up. Also, this is causing me to go bald. Please help!

I think it would be really helpful to have a kind of overview explanation describing the definate process that I need to follow in order to accept subscription based payments. The level of detail would include where each of the steps should occure; frontend or backend (server), and any intermediate steps necessary to understand what data is flowing where. Second to that, the actual code for the smart button with some comments indicating what part of the process the code is addressing. Maybe that's a lot to ask, but it would be greatly appreciated and I believe a great resource for others looking to do the same as I am currently.

At the moment, my primary issue is that when I set the URL pointing to the paypal SDK in my script take to include &intent=authorize, I am told in the error message that I need to set intent=capture, but when I set intent=capture I'm told I need to set intent=authorize. So now I'm confused as to what I am supposed to do; authorize the transaction or capture the transaction. I've been provided links to 2 different guides on the paypal developer website from paypal technical support which seem to contradict each other - the first link said nothing about capture or authorizing payments, the 2nd link does. But I don't understand the context on the second link. The first link is all client side, the second link is on client side and server side. Why would these intent=ca[ture/authorize be needed? I thought that once someone agrees to and completes signing up for a subscription, and I've captured their subscription id, that I don't need to do anything else in order to receive funds on the monthly basis setup in my plan, I would only have to query the paypal APIs to find out if they've paid up upon the customer signing in to my service.

I have setup a sandbox account and I've created a product and a plan. I've got the smart button rendering with my plan ID after the customer logs in.

If I set intent=capture in the paypal SDK script URL, the paypal window opens, you select payment and agree, and then I get this error in my console:

env: "sandbox"
err: "Error: Use intent=authorize to use client-side authorize"
referer: "localhost:88"
timestamp: "1589939180937"
uid: "fad5852fa3_mde6ndq6mdu"

But if I set intent=authorize, I click the smart button, the paypal window shows up and disappears quickly and then I get this error:

buttonSessionID: "e3bf3c6c3d_mdi6mdi6mzq"
env: "sandbox"
err: "Uncaught Error: Expected intent from order api call to be authorize, got capture. Please ensure you are passing intent=capture to the sdk url"
referer: "www.sandbox.paypal.com"
sessionID: "fad5852fa3_mde6ndq6mdu"
timestamp: "1589940160835"

Here is my code:

<!DOCTYPE html>

<head>
  <!-- Add meta tags for mobile and IE -->
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
</head>

<body>
  <!-- Set up a container element for the button -->
  <div id="paypal-button-container"></div>

  <!-- Include the PayPal JavaScript SDK -->
  <script
    src="https://www.paypal.com/sdk/js?client-id=CLIENT-ID-HERE&currency=USD&vault=true&intent=capture"></script>

  <script>
    let planid = 'P-48A5110983270751ML2P5NVI';

    // Render the PayPal button into #paypal-button-container
    paypal.Buttons({

      // Set up the transaction
      createSubscription: function (data, actions) {
        // Create Subscription
        return actions.subscription.create({ "plan_id": planid });
      },
      onApprove: function (data, actions) {

        // Authorize the transaction
        actions.order.authorize().then(function (authorization) {

          // Get the authorization id
          var authorizationID = authorization.purchase_units[0]
            .payments.authorizations[0].id

          // Call your server to validate and capture the transaction
          return fetch('/api/company/paypal-transaction-complete', {
            method: 'post',
            headers: {
              'content-type': 'application/json'
            },
            body: JSON.stringify({
              orderID: data.orderID,
              authorizationID: authorizationID,
              data: data,
              authorization: authorization
            })
          });
        });
      }
      // Finalize the transaction? Which one do I want, to authorize or to finalize??
      // onApprove: function (data, actions) {
      //   let result = actions.subscription.get();
      //   return actions.order.capture().then(function(details) {
      //   // Do I need to send something to my server here?
      //   // Show a success message to the buyer
      //   alert('Transaction completed by ' + details.payer.name.given_name + '!');
      //   });
      // }

    }).render('#paypal-button-container');
  </script>
</body>

Thanks in advance for your help. This has been a most frustrating project.

John
  • 976
  • 1
  • 15
  • 21
  • 3
    Yeah, paypal's payment system along with its documentation is absolute and total mess, I am trying to pass `custom` field to paypal in order to get that field back through IPN, it costs me divorce and anxiety! still does not work tho. – Nodir Nasirov Feb 17 '21 at 15:13

1 Answers1

1

Why are you using intent=authorize / intent=capture in the URL with subscriptions?

Why are you using actions.order.authorize() with subscriptions?

Who told you to do either of these things with subscriptions?

Please see the Subscriptions Integration guide, which does not include any mention of those things.

Preston PHX
  • 27,642
  • 4
  • 24
  • 44
  • I emailed paypal and they told me to go look at https://developer.paypal.com/docs/checkout/integration-features/auth-capture/# It's been very confusing. I'll check your link out and will check back in after. Thanks for your info – John May 22 '20 at 20:01
  • Did whoever tell you to look there clearly understand that you're working with subscriptions? I don't think you should be looking there, at all. That's some bad misdirection. – Preston PHX May 22 '20 at 20:05
  • For sure. Good news though! Your link to the docs seems to have worked! So I guess I should grab that data object returned from onApprove callback and put it in the database. Then when the user logs in at a future data, is there a way to query paypal to ensure they are paid up to date? Could you direct me to docs or quick explanation on where to make that request? Thanks again for your help! You have no idea how grateful I am for your expertise on this!! – John May 22 '20 at 20:13
  • In the bottom left of the Subscriptions Integration guide there is a Reference, and a link to the Susbscriptions resource group, so you could consider querying that. – Preston PHX May 22 '20 at 20:16
  • An alternative design is to listen for Webhook events about subscriptions being paid (PAYMENT.SALE.COMPLETED) and keep track of that status -- this is actually a more commonly used design, but might be more complicated. – Preston PHX May 22 '20 at 20:18
  • Can I ask you a question: on the frontend, API requests to my server are associated with the users cookie, but webhooks have no cookies associated, they're just data coming from paypal saying arbitrarily that a subscription was created. When a webhook comes in, how does one go about associating it with the user that created it? I was hoping there was a way to send a piece of custom data off with the subscription, like a user id, and then see that piece of data in the webhook. Is there another way to do this? Thanks – John May 28 '20 at 17:53
  • There isn't, you need to associate a subscription ID with a user the moment it is created. – Preston PHX May 28 '20 at 18:00
  • I suspected this. I think that answers my question. Thanks again – John May 28 '20 at 18:11