Paypal Integration Gotcha!

January 2018 · 3 minute read

This post was initially a hit-piece on Paypal’s developer experience before transitioning into a guide to integrate paypal and finally flattened into showing a grave mistake to avoid whilst using paypal’s API.

Foundational concepts

To give Paypal credit where it is due, their APIs are nicely standardized. Which is to say that the front-end library has the same methods as the back-end libraries despite implementaiton differences. There are 3 main methods that you want to know:

paypal.payment.create(): Creates and authorizes a payment

paypal.payment.get(): Retreives all information pertaining to a payment

paypal.payment.execute(): Executes a payment and charges the user’s account

The first one can be broken down further into paypal.payment.authorize() and paypal.payment.capture() but you can figure those out on your own.

Fundamentally, you are only really required to use .create() and .execute() to create and then execute the payment. What is interesting with Paypal is that you can move them around as you please. The most useful and reasonable way to organise it is (and the one that paypal recommends) is to create the payment on the front-end, send the information needed to execute the payment to the back-end then execute it.

Never trust user input

In the above example, you know that the payment was successful. Congratulations! But what makes you think the proper sum was paid? What if the user modified the amout owned from 300$ to 1$? For that case, I see people adding checks for the total amount before executing it using .get. But that is not enough, the currency could have changed too and you will need to check that as well.

With those two precautions in place, this issue could be considered solved:

This could also be done after receiving the payment but that would require refunds which could become a pain.

What about other payment processors?

Other payment processors (at least Stripe), have a forced security mecanisms for this. With Stripe, for instance, will require you to essentially create the same charge twice. Discrepencies will make the charge fail. The first time this is done is on the front-end, when the user enters his credit card.

The second time it is done is on the back-end, when you recreate the payment with the amount owned and the currency.

I wonder how many websites have failed to securely implement paypal because of naively following Paypal’s own documentation with the assumption that the official documentation of the world’s largest payment processor will be secure.