How to integrate your website with PayPal using PHP
Intro
You decided to integrate your website with PayPal and you don’t know where to start. There are several ways to integrate your website with PayPal, and in this post I will explain you how to communicate with PayPal API and how to make PayPal Express Checkout payments.
PayPal payment options
There are several different payment options provided by PayPal:
- PayPal Payments Standard (aka PayPal IPN)
- PayPal Express Checkout – Explained in this post
- Website Payments Pro
- PayPal Payments Advanced
PayPal payment standard (PayPal IPN)
PayPal Payments Standard or PayPal IPN redirects customer to the PayPal after the checkout process is finished on your website. This method is really popular when implementing “Donate” buttons, and some other really easy straightforward transactions. Customer can make transaction without having PayPal account which is sometimes really useful. After payment, customer is redirected to the desired “success” page, and your website (store) is informed about completed payment. PayPal servers send IPN requests (yes, you can receive serveral requests for the same payment) to your website, and you should process requests and make changes in your database.
I do not suggest you to implement this method if you are running e-Commerce website with dynamic prices, discounts etc. Also, if there is communication error between PayPal server and your server, transaction in your database will never be marked as successful (because you never processed IPN request), and your customer will be disappointed because customer can’t access content on your website even he paid for it.
PayPal Express Checkout
If you are running e-Commerce website with dynamic prices, discount coupons, discount actions, and other features, then go ahead and implement PayPal Express Checkout. With Express Checkout, customer can login to their PayPal before checkout process on your site (this enables customer to prefil checkout forms on your site with data from PayPal, which is cool thus customer doesn’t have to write personal data every time), and after checkout process.
Express checkout doesn’t completely rely on IPN requests in order to make transaction. An order is stored immediately after payment is completed, and this happens while customer is actively engaged on your website. Simply said, when payment is complete, customer is redirected to your website, but your website is immediately informed by PayPal (not in a form of IPN request) weather transaction was successful or not. This enables your to change transaction status immediatelly after payment in your database, and to redirect user to the resource he bought (or to send email saying “Thank you for buying item”).
Express checkout doesn’t fully rely on IPN requests, but if you want to implement refund functionality or to make some order adjustments, you have to implement IPN listener too. This IPN listener will listen for IPN requests and will make transaction changes in your database, based on the content in IPN request. IPN listener is also required when you want to implement recurring payments.
Website Payments Pro
You embed credit card HTML form on your website, where customer has to enter credit card details. Customer is not redirected to the PayPal, and order is processed directly on your website (technically transaction is processed via PayPal but customer has no idea of that). As in Express Checkout, you have to implement IPN listener in order to support refund or order adjustments.
Implementation
As previously said, in this post I will concentrate on Express Checkout payments. Here is nice diagram explaining Express Checkout flow:
Here is step by step explanation:
Step 1: Customer visits your page, and buys an item or several items. He clicks on the PayPal Pay button. SetExpressionCheckout REST service is called (you are calling PayPal’s API) in order to obtain PayPal TOKEN. At this stage you will not be redirected to the PayPal. When you obtain a TOKEN, you have to provide it in any subsequent API calls.
Step 2: REST service returns you the TOKEN. The TOKEN is valid some period of time and has to be provided in any further API call.
Step 3: Using provided TOKEN, you redirect a user to the PayPal (TOKEN is provided as HTTP GET parameter). User logs in to a PayPal account and confirms order.
Step 4: User is redirected from PayPal, to your page.
Step 5: User is reviewing and confirming an order. Depending on your requirements, you can skip process of displaying checkout details page (but you always have to call GetExpressCheckoutDetails method). If you want to implement order details and confirmation page on your website then you will call GetExpressCheckoutDetails API once user clicks “Confirm” button on confirmation page. If you don’t want to implement and display order confirmation page, then just call GetExpressCheckoutDetails API method and wait for result. You have to pass result from the GetExpressCheckoutDetails to DoExpressCheckout API method.
Step 6: DoExpressCheckoutPayment method is called in order to make a payment. If the payment is good, API method will return success, and if not, you will receive failure message.
Now when we have explain everything, let’s start with code.
PHP Library
In order to make integration with PayPal really easy, I implemented PHP library which you can download and use in your project. Library is available on my GitHub page.
Library contains only one PHP file (which can be imported simply by calling require_once function), and one certificate file for making HTTPS requests. On GitHub page you can find detailed steps about library installation.
Code example
Here is code which you can use in your project in order to implement PayPal integration:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
<?php $paypal = new DPayPal(); //Create an DPayPal object //Making SetExpressCheckout API call //All available parameters for SetExpressCheckout are available at https://developer.paypal.com/docs/classic/api/merchant/SetExpressCheckout_API_Operation_NVP/ $requestParams = array( 'RETURNURL' => "", //Enter URL of the page where you want to redirect your user after user enters PayPal login data and confirms order on PayPal page 'CANCELURL' => ""//Page you want to redirect user to, if user press cancel button on PayPal website ); //Order settings $orderParams = array( 'LOGOIMG' => "", //URL of your website logo. This image which will be displayed to the customer on the PayPal checkout page "MAXAMT" => "100", //Set maximum amount of transaction "NOSHIPPING" => "1", //I do not want shipping "ALLOWNOTE" => "0", //I do not want to allow notes "BRANDNAME" => "Here enter your brand name", "GIFTRECEIPTENABLE" => "0",//Disable gift receipt widget on the PayPal pages "GIFTMESSAGEENABLE" => "0"//Disables the gift message widget on the PayPal pages ); //Item settings $item = array( 'PAYMENTREQUEST_0_AMT' => "20", 'PAYMENTREQUEST_0_CURRENCYCODE' => 'EUR', 'PAYMENTREQUEST_0_ITEMAMT' => "20", 'L_PAYMENTREQUEST_0_NAME0' => 'Item name', 'L_PAYMENTREQUEST_0_DESC0' => 'Item description', 'L_PAYMENTREQUEST_0_AMT0' => "20", 'L_PAYMENTREQUEST_0_QTY0' => '1', //"PAYMENTREQUEST_0_INVNUM" => $transaction->id - This field is useful if you want to send your internal transaction ID ); //Now we will call SetExpressCheckout API operation. $response = $paypal->SetExpressCheckout($requestParams + $orderParams + $item); //Response is also accessible by calling $paypal->getLastServerResponse() if (is_array($response) && $response['ACK'] == 'Success') { //Request successful //Now we have to redirect user to the PayPal //This is the point where user will be redirected to the PayPal page in order to provide Login details //After providing Login details, and after he confirms order in PayPal, user will be redirected to the page which you specified in RETURNURL field $token = $response['TOKEN']; header('Location: https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=' . urlencode($token)); } else if (is_array($response) && $response['ACK'] == 'Failure') { var_dump($response); exit; } |
The code above covers Step 1, Step 2, Step 3, Step 4.
If user confirmed order in PayPal, he will be redirected to the RETURN url specified in the order. Transaction still didn’t occurred, and we are preparing to call DoExpressCheckout API method. In order to call it, we have to call GetExpressCheckout API method.
In PHP which will generate RETURN URL page, you have to add the following code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<?php $token=$_GET["token"];//Returned by paypal, you can save this in SESSION too $paypal = new Paypal(); $requestParams = array('TOKEN' => $token); $response = $paypal->GetExpressCheckoutDetails($requestParams); $payerId=$response["PAYERID"];//Payer id returned by paypal //Create request for DoExpressCheckoutPayment $requestParams=array( "TOKEN"=>$token, "PAYERID"=>$payerId, "PAYMENTREQUEST_0_AMT"=>"20",//Payment amount. This value should be sum of of item values, if there are more items in order "PAYMENTREQUEST_0_CURRENCYCODE"=>"EUR",//Payment currency "PAYMENTREQUEST_0_ITEMAMT"=>"20"//Item amount ); $transactionResponse=$paypal->DoExpressCheckoutPayment($requestParams);//Execute transaction if(is_array($transactionResponse) && $transactionResponse["ACK"]=="Success"){//Payment was successfull //Successful Payment } else{ //Failure } |
Let me now explain Step 5, Step 6. In Step 5, just call GetExpressionCheckoutDetails method, and as result you should get PAYERID parameter, which is required parameter for DoExpressionCheckout method. As last step, just call DoExpressionCheckoutPayment method:
1 |
$transactionResponse=$paypal->DoExpressCheckoutPayment($requestParams);//Execute transaction |
Recurring Payments
Sometimes you would like to implement recurring payments. Recurring payment is payment which frequently happens in some specific time period. This could be really nice of you want to enable subscription for example magazine you are publishing, or specific resource or service you are providing. Good example of recurring payments are implemented in hosting plans, where you can check option to automatically renew hosting plan after one year.
In order to implement recurring payments, you have to call CreateRecurringPaymentsProfile API method. Here is example:
1 2 3 4 5 6 7 8 9 10 11 12 |
$requestParams=array( "TOKEN"=>$token, "PROFILESTARTDATE"=>date("Y-m-d\TH:i:s\Z",strtotime('+1 year')), "DESC"=>"Subscription to your service or book or anything else", "BILLINGPERIOD"=>"Year", "BILLINGFREQUENCY"=>"1", "AMT"=>"20", "CURRENCYCODE"=>"EUR", "PROFILEREFERENCE"=>"15"//This value is for example ID of a user ); $recurringProfileResponse=$paypal->CreateRecurringPaymentsProfile($requestParams); |
Once when a recurring payment profile is created, they are available/visible in PayPal account of the customer. In order to process recurring payment, you have to implement your IPN listener. Every time when new recurring payment occurs, PayPal will send you IPN request.
Here I want to write few words about PROFILEREFERENCE field. If you set this field when creating recurring payment profile, then this field and its value will be resent in IPN request once recurring payment occurs. If you set this field to be USER_ID from your database, then once you receive IPN request, you exactly know to whom this IPN request is belonging to, and you can extend subscription to this user, and send him an “Thank you” email or you can take any other action.
IPN Requests
In order to implement IPN listener, you can use one of the many available IPN listener PHP libraries. One I used in several projects is the following one.
Conclusion
In this post I wanted to share how to easily integrate your website with PayPal using Express Checkout Payments. If you have any questions or if you find my article useful please share it, so it can help anyone else. Also, please leave comments for suggestions.
http://code-epicenter.com/how-to-integrate-your-website-with-paypal-using-php/How to integrate your website with PayPal API using PHPhttp://code-epicenter.com/wp-content/uploads/2015/09/pp.pnghttp://code-epicenter.com/wp-content/uploads/2015/09/pp-150x142.pngLibrariesPHPProgrammingTutorialsExpress Checkout Payments,library,PayPal,PHPIntro You decided to integrate your website with PayPal and you don't know where to start. There are several ways to integrate your website with PayPal, and in this post I will explain you how to communicate with PayPal API and how to make PayPal Express Checkout payments. PayPal payment options There are several different...Amir DuranAmir Duranamir.duran@gmail.comAdministratorAmir Duran is software engineer who currently lives and works in Germany. He obtained Masters degree diploma on Faculty of Electrical Engineering in Sarajevo, department Computer science. With good educational background he is specialized in designing and implementing a full-stack web based applications.Code Epicenter
Thanks a ton Amir. Definitely worked for me!
Hi
I m getting this error
string(80) “error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure”
Looking forward to your help for the resolution
Thanks
Your problem is in SSL Certificates.
Hello i am having this same error>
would you please help me.
I tried to implement on my server but I get the error:
“Calling PayPal SetExpressCheckout method
string(17) “SSL connect error” bool(false) Response from PayPal received:
In 5 seconds you will be redirected to PayPal to enter your credentials.”
My server has:
TLS 1.0
NSS/3.19.1 Basic ECC
Could you point on how I can make it work?
Hello
Is this still working in 2016?
Calling https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=XXXX
gives me already an “Internal Server error”
Did they just close the sandbox, or will also the http://www.paypal.com page give an Internal Server Error soon?
It is working. I integrated one website one month ago, using my library.
Hi there, this is the best explanation yet, of the PayPal Express Checkout process that I could find. Thanks for that.
Not to put a damper on anything, but can I just check; is there a couple of errors at the top of your second piece of PHP code (the one regarding the RETURN URL page).
this line:
$paypal = new Paypal();
should it be $paypal = new DPaypal(); (a missing ‘D’ before the class name) ?
and do we need to use:
require_once ‘DPayPal.php’; (or is it sufficient in the first code block only) ?
apart from this, it’s excellently explained.
Yep, there are few mistakes that I have to fix. Thx for letting me know.
Perfect, thanks for this code.
Where set we API signature ?
I found the solution, it’s ok 😉
Great 😀
down vote
favorite
I am using paypal payment gateway for recurring payment Payment gateway working fine but i have following problems
when user creates recurring payment for daily/monthly/yearly then I got ipn_track_id & subscr_id on IPN page & i saved that in db. ex. for monthly payment user done payment first time from my site but next month payment will auto done by paypal on paypals site. then how can I check payment status for saved subscr_id, because subscr_id not got in payment list records.
How can I get translation details of recurring payment done on paypal?
On Recurring payment, PayPal will send you new IPN request. Based on this request you can change status in your DB.
Please have a look at the following part of the code:
//Item settings
$item = array(
'PAYMENTREQUEST_0_AMT' => "20",
'PAYMENTREQUEST_0_CURRENCYCODE' => 'EUR',
'PAYMENTREQUEST_0_ITEMAMT' => "20",
'L_PAYMENTREQUEST_0_NAME0' => 'Item name',
'L_PAYMENTREQUEST_0_DESC0' => 'Item description',
'L_PAYMENTREQUEST_0_AMT0' => "20",
'L_PAYMENTREQUEST_0_QTY0' => '1',
//"PAYMENTREQUEST_0_INVNUM" => $transaction->id - This field is useful if you want to send your internal transaction ID
);
When you make your first recurring payment, you can send parameter PAYMENTREQUEST_0_INVNUM. This can be for example internal user ID in your DB, or transaction ID, or subscription ID or anythings that helps you to uniquely identify the user. When after one year, recurring payment happens, PayPal will send you (or better to say forward) value you sent in this parameter. Your IPN listener should extract this value on your side, find a user (or transaction) with this ID, and change status, based on the status of recurring payment.
For example:
You create recurring payment and you set PAYMENTREQUEST_0_INVNUM=175
PayPal creates recurring payment profile in PayPal account of the user, and “saves” this value internally.
After one year, recurring payment is processed, and PayPal sends you IPN request to notify you that payment happened. In this IPN request, PayPal will resend this ID=175
You receive IPN request, and extract this value 175 from it.
You goes to DB and find a user
You check whether IPN request was successful, and if yes, you extends user’s subscription for 1 year.
I hope I helped.
Hello,
I used your example code and have successfully been able to use the sandbox to make payments. However when I try and move to live paypal I am having difficulty.
Changing the API credentials and $payPalAPIUrl in DPayPal.php is easy, but in your payment.php example code you have this line:
header(‘Location: https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=‘ . urlencode($token));
What should that be when using Paypal live? I have tried https://api-3t.paypal.com/nvp/cgi-bin… which generated a “Specified Method is not Supported” error. Then noticing that your example had the nvp directory removed, I tried https://api-3t.paypal.com/cgi-bin… which generated a page of XML errors.
Thanks for any help you can offer. So far everything has gone remarkably well.
On my github page, where Library is available there is link for live PayPal service:
Thanks for your reply. It hasn’t helped though. When redirecting to the paypal site for payment I am still seeing the error 81002 – Method Specified is not Supported. SetExpressCheckout has been executed successfully, and I have a token. This error then occurs when redirecting to paypal for payment. Really beginning to tear my hair out now!!
Hi John,
I’m really sad to hear that. I checked now the redirect URL on the website where this library is used and it is still working without problem. When I click on submit button, I’m redirected to the following URL:
https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=EC-6TS91472CP568832D#/checkout/login
Can you compare your URL (where your user is redirected) and this one. Maybe you are not encoding your GET parameters properly.
Thanks for helping. I was using api-3t.paypal.com but once I changed it to http://www.paypal.com as per your example it is working.
Thanks ever so much for your code and for your assistance.
I had spent more than a week trying to integrate Paypal express checkout but had no success till I reached this page. This is by far the easiest way to get things up and running with excellent documentation. The example makes it extremely easy to understand what’s going on. Thanks a lot for saving my day!!
PS. I am using Laravel 4.
I’m glad that I’ve helped.
Hi,
First of all your code is great and works, if I am only purchasing 1 item through PP from my cart. I am having issues adding an array of items from cart to PP. Could you provide an explanation of how to alter the code to except multiple items from cart? Thank you.
I appear to be missing something… Where do I put the name of my business or my email address into this configuration so Paypal knows who I am and who to pay?
Hi Robert,
please have a look at DPayPal class here:
https://github.com/amirduran/duranius-paypal-rest-api-php-library/blob/master/library/DPayPal.php
You have to put your API Credentials in order to communicate with API. Based on your credentials, PayPal knows who you are 😉
Regards, Amir
can i use payment through card using express checkout method? on my website
Yes, I think paypal is providing that option.
Hi! Does this still work in 2017?
I am trying in a sandbox, but always get an error:
array(9) { [“TIMESTAMP”]=> string(20) “2017-01-04T11:58:12Z” [“CORRELATIONID”]=> string(10) “5f452690b5” [“ACK”]=> string(7) “Failure” [“VERSION”]=> string(4) “74.0” [“BUILD”]=> string(8) “28387177” [“L_ERRORCODE0”]=> string(5) “10002” [“L_SHORTMESSAGE0”]=> string(14) “Security error” [“L_LONGMESSAGE0”]=> string(28) “Security header is not valid” [“L_SEVERITYCODE0”]=> string(5) “Error” }
Not sure what to do…
Hi Rok,
yes, the library works in 2017. Can you specify a bit more details about your error?
It was my mistake. I was using real API password/signature in a sandbox environment – I didn’t know that you need to create a test account in a sandbox (now it is obvious of course). Maybe you add this chapter for us – totally PayPal beginners 🙂
However, I did get a positive response from a PayPal. Today I will implement last steps from your code and I think it will work 🙂
Thank you!
By the way, is it possible that this call fails (timeout)?
$response = $paypal->SetExpressCheckout(..);
How long will this wait for response?
And second…
if(is_array($transactionResponse) && $transactionResponse[“ACK”]==”Success”){
//Successful Payment
}
This means that it is 100 % sure that s/he paid?
What about if he pays and then a connection drops (in his part). So, I did save a token in my DB and he paid (but we didn’t update a status in the meantime).
Can I check (later) with only a token if he paid?
Q: By the way, is it possible that this call fails (timeout)?
$response = $paypal->SetExpressCheckout(..);
How long will this wait for response?
A: Yes, it is possible, but calling setExpressCheckout will return you just a token. If this API call fails, then you can call it again to get a new token.
Q: if(is_array($transactionResponse) && $transactionResponse[“ACK”]==”Success”){
//Successful Payment
}
A: Yes, this means that user paid.
Hi Amir, thanks for that. Nice implementation full of details. I’m trying it for the first time and I’m struggling to understand how I match the database record that is added upon completion of a transaction to my actual customers table. Email or name don’t seem like a reasonable option but I don’t see how we’re passing some info to PayPal that gets return to my app at the end of the transaction. Any ideas on the best practices here?
Thanks again!
Hi,
The script works flawlessly for one-time payment. I’m trying to create a Recurring Payment system now. Should I replace the ‘Item settings’ section and the SetExpressCheckout API operation:
//Item settings
$item = array(
‘PAYMENTREQUEST_0_AMT’ => “20”,
‘PAYMENTREQUEST_0_CURRENCYCODE’ => ‘EUR’,
‘PAYMENTREQUEST_0_ITEMAMT’ => “20”,
‘L_PAYMENTREQUEST_0_NAME0’ => ‘Item name’,
‘L_PAYMENTREQUEST_0_DESC0’ => ‘Item description’,
‘L_PAYMENTREQUEST_0_AMT0’ => “20”,
‘L_PAYMENTREQUEST_0_QTY0’ => ‘1’,
//”PAYMENTREQUEST_0_INVNUM” => $transaction->id – This field is useful if you want to send your internal transaction ID
);
//Now we will call SetExpressCheckout API operation.
$response = $paypal->SetExpressCheckout($requestParams + $orderParams + $item);
With the Recurring Payments code snippet provided for it to work? Or are there any additional steps involved?
A big thank you for the article and code.
Yes, you have to replace “item settings” array in order to make recurring payment. The second thing is to implement IPN listener. IPN listener is PHP script that will receive POST requests from the PayPal. PayPal will send POST request every time when recurring payment happens (so let’s say every 1 year).
Hi Amir
Thanks a lot for the code and all the explanation you prepared. It helped a lot. Everything is looking like working fine, it even returns to my success page. However, i do not see any transaction on test and live environment. I couldnt see it in sandbox, and i thought maybe it will work in the live but still the same. It looks like everything works perfectly, but i do not see any log in the transactions. Do you have any idea ? I would appreciate for your help.
You should see transactions in your sandbox account. If not, that means something is not working and you should not go to the live. You have to try to var_dump all responses from the server (especially result from doExpressionCheckout() function) to ensure your transaction was successful.
You need different details for every seller account
Sorry for bothering you. I was to lazy to read your documents completely.
Everything is explained here:
https://developer.paypal.com/docs/classic/api/merchant/SetExpressCheckout_API_Operation_NVP/
Hi there,
Firstly I found your example scripts incredibly handy here and really appreciate your posting them for others.
I have recently seen that Paypal are discontinuing the NVP/SOAP APIs – do your files only use the REST API? The links in your example to check eligibility criteria lead to a Paypal page saying that this integration is discontinued form Jan 1st 2017 – But you sample files still seem to work (For – In-Context Checkout integration steps) – could you clarify?
Many thanks in advance!
Sorry please ignore this comment, placed on the wrong thread.
Just wanted to let you know the paypal payment runs perfectly with your library in use. Thousand thanks, Amir. You helped me a lot
Great article,
I was struggling to integrate a simple payment after my own checkout following the paypal documentation which is at best patchy.
Thanks to your codes I am now up and running with all i wanted
Now nvp library is deprecated from 1st Jan 2017. Is there another way to do it?
hi
thanks for the good code, what should be changed in order to pass multiple items to the class?
Hi,
Where do we get PayPal attribution id BN code for sandbox testing
Hello,
Thank you for this tutorial. With your help I could implement PayPal-payment. Thank you so much!
But there is one typing mistake:
In the step to execute the order you start the class with “$paypal = new Paypal();” this throws a error.
The correct would be: “$paypal = new DPaypal();”
Then all is working fine! =)
Best regards from Berlin
Montgomery
Thank you for pointing it out. I will fix the typo.