How to integrate PayPal payment gateway in Laravel

Hello Laravel enthusiasts, welcome back to justlaravel.com. Here in this post, I will let you know how to integrate PayPal payment gateway in Laravel.
There are many payment gateways to integrate into your laravel applications. Previously I have written about Stripe payment gateway integration, you can check it here. Here I will tell you the one of the famous payment gateway PayPal.
You can watch the video on YouTube here.
Configuring PayPal in your app
- First I will install its SDK using composer.
composer require paypal/rest-api-sdk-php
- Next, I need to login to PayPal developer mode, create a new sandbox account and get some keys like
client_id
andsecret
for testing this integration. - Login to developer.paypal.com to create a merchant account, so that you can sell or to credit funds to your account.
- You can also create a buyer account, to buy from some merchant.
- I have created both merchant and buyer test accounts.
- You will need to create a new app to get the
client_id
andsecret
keys. - After creating your app click on the app it shows you client_id and secret keys.
- Copy those and paste those in your
.env
file for security.PAYPAL_CLIENT_ID= PAYPAL_SECRET= PAYPAL_MODE=sandbox
- Next, I will create a new file
paypal.php
, at\config
directory. - Place the following content in the file
<?php return [ 'client_id' => env('PAYPAL_CLIENT_ID',''), 'secret' => env('PAYPAL_SECRET',''), 'settings' => array( 'mode' => env('PAYPAL_MODE','sandbox'), 'http.ConnectionTimeOut' => 30, 'log.LogEnabled' => true, 'log.FileName' => storage_path() . '/logs/paypal.log', 'log.LogLevel' => 'ERROR' ), ];
Payment form
You can add any form, the way you want, here for demo purposes, I just have 1 input field to enter the amount and a button to submit the form.
Payment Controller
I will create a new controller to manage all the PayPal related PHP stuff.
php artisan make:controller PaymentController
The above command will create a new controller at /app/http/Controllers
with name PaymentController
First I will initialize the PayPal configuration and settings in the _construct
function.
public function __construct() { /** PayPal api context **/ $paypal_conf = \Config::get('paypal'); $this->_api_context = new ApiContext(new OAuthTokenCredential( $paypal_conf['client_id'], $paypal_conf['secret']) ); $this->_api_context->setConfig($paypal_conf['settings']); }
So now after some amount is entered in the form and when clicked on the ‘Pay with PayPal’ button, the following functionality executes.
public function payWithpaypal(Request $request) { $payer = new Payer(); $payer->setPaymentMethod('paypal'); $item_1 = new Item(); $item_1->setName('Item 1') /** item name **/ ->setCurrency('USD') ->setQuantity(1) ->setPrice($request->get('amount')); /** unit price **/ $item_list = new ItemList(); $item_list->setItems(array($item_1)); $amount = new Amount(); $amount->setCurrency('USD') ->setTotal($request->get('amount')); $transaction = new Transaction(); $transaction->setAmount($amount) ->setItemList($item_list) ->setDescription('Your transaction description'); $redirect_urls = new RedirectUrls(); $redirect_urls->setReturnUrl(URL::route('status')) /** Specify return URL **/ ->setCancelUrl(URL::route('status')); $payment = new Payment(); $payment->setIntent('Sale') ->setPayer($payer) ->setRedirectUrls($redirect_urls) ->setTransactions(array($transaction)); /** dd($payment->create($this->_api_context));exit; **/ try { $payment->create($this->_api_context); } catch (\PayPal\Exception\PPConnectionException $ex) { if (\Config::get('app.debug')) { \Session::put('error', 'Connection timeout'); return Redirect::route('paywithpaypal'); } else { \Session::put('error', 'Some error occur, sorry for inconvenient'); return Redirect::route('paywithpaypal'); } } foreach ($payment->getLinks() as $link) { if ($link->getRel() == 'approval_url') { $redirect_url = $link->getHref(); break; } } /** add payment ID to session **/ Session::put('paypal_payment_id', $payment->getId()); if (isset($redirect_url)) { /** redirect to paypal **/ return Redirect::away($redirect_url); } \Session::put('error', 'Unknown error occurred'); return Redirect::route('paywithpaypal'); }
In the above function, the terminology like Payer
, Item
is all from the PayPal SDK, so let me explain those terminologies form PayPal official docs here.
Payer
A resource representing a Payer that funds a payment For PayPal account payments, set payment method to ‘paypal’.
$payer = new Payer(); $payer->setPaymentMethod("paypal");
Item information
(Optional) Lets you specify item wise information
$item_1 = new Item(); $item_1->setName('Item 1') /** item name **/ ->setCurrency('USD') ->setQuantity(1) ->setPrice($request->get('amount')); /** unit price **/ $item_list = new ItemList(); $item_list->setItems(array($item_1));
Amount
Lets you specify a payment amount. You can also specify additional details such as shipping, tax.
$amount = new Amount(); $amount->setCurrency('USD') ->setTotal($request->get('amount'));
Transaction
A transaction defines the contract of payment – what is the payment for and who is fulfilling it.
$transaction = new Transaction(); $transaction->setAmount($amount) ->setItemList($item_list) ->setDescription('Your transaction description');
Redirect URLs
Set the URLs that the buyer must be redirected to after payment approval/ cancellation.
$redirect_urls = new RedirectUrls(); $redirect_urls->setReturnUrl(URL::route('status')) /** Specify return URL **/ ->set
Payment
A Payment Resource; create one using the above types and intent set to ‘sale’
$payment = new Payment(); $payment->setIntent('Sale') ->setPayer($payer) ->setRedirectUrls($redirect_urls) ->setTransactions(array($transaction));
Create Payment
Create a payment by calling the ‘create’ method passing it a valid apiContext. (See bootstrap.php for more on ApiContext
) The returned object contains the state and the URL to which the buyer must be redirected to for payment approval
$payment->create($this->_api_context);
PayPal Payment Status
So after the payment is made, we need to tell the user whether the payment is a success or a failure. The following functionality executes after payment is processed.
public function getPaymentStatus() { /** Get the payment ID before session clear **/ $payment_id = Session::get('paypal_payment_id'); /** clear the session payment ID **/ Session::forget('paypal_payment_id'); if (empty(Input::get('PayerID')) || empty(Input::get('token'))) { \Session::put('error', 'Payment failed'); return Redirect::route('/'); } $payment = Payment::get($payment_id, $this->_api_context); $execution = new PaymentExecution(); $execution->setPayerId(Input::get('PayerID')); /**Execute the payment **/ $result = $payment->execute($execution, $this->_api_context); if ($result->getState() == 'approved') { \Session::put('success', 'Payment success'); return Redirect::route('/'); } \Session::put('error', 'Payment failed'); return Redirect::route('/'); }
Approval Status
Determine if the user approved the payment or not.
Get the payment Object by passing paymentId payment id was previously stored in session.
$payment = Payment::get($payment_id, $this->_api_context);
Payment Execute
PaymentExecution object includes information necessary to execute a PayPal account payment. The payer_id is added to the request query parameters when the user is redirected from PayPal back to your site.
$execution = new PaymentExecution(); $execution->setPayerId(Input::get('PayerID')); /**Execute the payment **/ $result = $payment->execute($execution, $this->_api_context);
And finally, if the result of the payment is a success, I will show a success message and a failure message if the payment fails.
if ($result->getState() == 'approved') { \Session::put('success', 'Payment success'); return Redirect::route('/'); } \Session::put('error', 'Payment failed'); return Redirect::route('/');
I will store the messages in the Session and show them in the view.
@if ($message = Session::get('success')) <div class="w3-panel w3-green w3-display-container"> <span onclick="this.parentElement.style.display='none'" class="w3-button w3-green w3-large w3-display-topright">×</span> <p>{!! $message !!}</p> </div> <?php Session::forget('success');?> @endif @if ($message = Session::get('error')) <div class="w3-panel w3-red w3-display-container"> <span onclick="this.parentElement.style.display='none'" class="w3-button w3-red w3-large w3-display-topright">×</span> <p>{!! $message !!}</p> </div> <?php Session::forget('error');?> @endif
Check out the images below,
Enter some amount,

Logging with test buyer account,

Paypal payment page,

Success mesage,

Also please feel free to look at other payment gateway implementations like Stripe payment gateway Integration or have a look at all payment gateway integration tutorials here or check all of the posts on the site here.
Hi!
It also message me success!! But when I checked my balance, its still the same before the transaction is made.
The is no deduction. I also tried it live and still, my balance was not change. Please help me.
Did you pay via credit/debit card? If yes, then it won’t deduct from buyer account, else it will deduct, refer the same issue here on GitHub https://github.com/paypal/PayPal-Ruby-SDK/issues/58
“please choose another way to pay ” generating such error
Hi, amazing post avinash
Is there any way to integrate this payment gateway with a pop-up window without redirecting the original site? My payment experience focus on that.
Thanks
Hi, I get the following error when uploading it to my hosting: Use of undefined constant CURLOPT_SSLVERSION – assumed ‘CURLOPT_SSLVERSION’
Do your server has SSL installed?
Give me the example for Paypal recurring payment.Thanks
i get payment capture status – pending and status code- pending_review, can you say any solution
hello guys, how to sift from sandbox to real production site? please tell me what changes I need to make?
You need to toggle the option from sandbox to live from PayPal developer account, I have shared it in the video https://youtu.be/WOsXayVmnoc?t=1740
hi!
when make payment
get this error
COMPLIANCE_VIOLATION”,”message”:”Transaction is declined due to compliance violation.