0

I am registered as a paypal user with sendbox, so I can already do my payment tests.

I added the paypal payment script to my small ecommerce site a few days ago. On my ecommerce site there is a shopping cart that stores the products you want to buy and automatically calculates the shipping costs, giving as a final result the total amount to be paid for the buyer. So based on that, the script I put on my payment page is this (you can see the $ pptotalpay variable which allows me to complete the payment with the set amount):

 <script src="https://www.paypal.com/sdk/js?client-id=XXXXXXXXXXXX&currency=EUR"></script> <script> paypal.Buttons({ style: { layout: 'vertical', color: 'blue', shape: 'rect', label: 'paypal' }, // Sets up the transaction when a payment button is clicked createOrder: (data, actions) => { return actions.order.create({ purchase_units: [{ amount: { value: '<?php echo $pptotalpay; ?>' } }] }); }, // Finalize the transaction after payer approval onApprove: (data, actions) => { return actions.order.capture().then(function(orderData) { // Successful capture! For dev/demo purposes: console.log('Capture result', orderData, JSON.stringify(orderData, null, 2)); const transaction = orderData.purchase_units[0].payments.captures[0]; //alert(`Transaction ${transaction.status}: ${transaction.id}\n\nSee console for all available details`); // When ready to go live, remove the alert and show a success message within this page. For example: //const element = document.getElementById('paypal-button-container'); //element.innerHTML = `<h3>Thank you for your payment! ${transaction.status} ${transaction.id} </h3>`; // Or go to another URL: actions.redirect('thank_you.html'); actions.redirect(`https://www.example.com/thank_you.php?transactionid=${transaction.id}&transactionstatus=${transaction.status}`); //actions.redirect(`https://www.example.com/cart.php`); }); } }).render('#paypal-button-container'); </script> <div id="paypal-button-container"></div> 

I have two options to manage the next phase (the payment message and the archiving of the order), to that of the actual payment with paypal: the first is to activate the two lines:

const element = document.getElementById ('paypal-button-container'); element.innerHTML = `<h3> Thank you for your payment! $ {transaction.status} $ {transaction.id} </h3> `; 

or to redirect the user to a personalized page:

actions.redirect (`https://www.example.com/thank_you.php?transactionid=$ {transaction.id} & transactionstatus = $ {transaction.status}`); 

Now, I'd like to use the second option, just because I can have a personalized page and freely write whatever I want as a purchase confirmation response. As you can see, however, there are two parameters that are passed via _GET; these are very important for me as they allow me to understand the outcome of the payment, and, when storing the purchased items in the database, associate the transaction ID with them.

My concern, however, is given by the fact that a "playful" user could play with the variables found in the URL, jeopardizing the security of the site; for example, it could start a new session for the purchase of products, skip the part of the payment with paypal and load the result page (where the code that stores the transaction in the database is found). I would notice it later when I would not see the correspondence between archived orders and amounts collected by paypal.

In this case, in addition to using the _GET method, paypal can use the _POST method? If so, how?

Or there is the first option (perhaps safer), which is to activate those two lines:

const element = document.getElementById ('paypal-button-container'); element.innerHTML = `<h3> Thank you for your payment! $ {transaction.status} $ {transaction.id} </h3> `; 

In this case I would have to incorporate my payment message in that string, but I don't know how I could make the $ {transaction.status} and $ {transaction.id} variables available in PHP so that I can manage the page dynamically and store the 'id of the transaction.

If anyone can give me advice I would be grateful.

1 Answer 1

1

actions.order.create() / .capture() are for very simple websites, not shopping carts. Do not use such client-side functions and then send information to your server after the fact. Even worse, do not depend on an obvious full-page redirect for doing so.

Instead, for use cases like this that need to do anything automated after payment (such as writing transaction information to a database most importantly, but also things like sending an email confirmation, or reserving product) ... use a backend integration with the PayPal API for creating and capturing the order that the JS SDK is going to use.

Use the v2/checkout/orders API and make two routes (url paths) on your server, one for 'Create Order' and one for 'Capture Order'. You could use the (recently deprecated/no longer maintained) Checkout-PHP-SDK for the routes' API calls to PayPal, or your own HTTPS implementation of first getting an access token and then doing the call. Both of these routes should return/output only JSON data (no HTML or text). Inside the 2nd route, when the capture API is successful you should verify the amount was correct and store its resulting payment details in your database (particularly purchase_units[0].payments.captures[0].id, which is the PayPal transaction ID) and perform any necessary business logic (such as reserving product or sending an email) immediately before forwarding return JSON to the frontend caller. In the event of an error forward the JSON details of it as well, since the frontend must handle such cases.

Pair those 2 routes with this frontend approval flow: https://developer.paypal.com/demo/checkout/#/pattern/server . (If you need to send any additional data from the client to the server, such as an items array or selected options, add a body parameter to the fetch with a value that is a JSON string or object)

Sign up to request clarification or add additional context in comments.

2 Comments

With this method you listed is it different from IPN (Instant Payment Notification)? I took a look at the PayPal documentation these days, and it is truly remarkable but dispersed. Putting aside what I had started, what did you advise me? API v2 / checkout / orders (version 2 if I'm not mistaken), or install an IPN on my server and process the archiving operations from there? @Preston PHX
IPN is a (very old) add-on integration that gives you an asyncrhonous notification when Payments and other events complete. It's been superceded by Webhooks, but still works for those who've integrated it already. With the above, you have a synchronous notification of payment completion when calling the capture API, so there is no need to wait for a separate post from PayPal to your server. Something like webhooks or IPN is only useful to add on if you need to be programmatically notified of later events, such as refunds make in PayPal or subscription payments in the future

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.