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 PayPal SDK using composer.
1 |
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 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.PayPal Payment Integration – justlaravel.com - 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.123PAYPAL_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
123456789101112<?phpreturn ['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'),];
PayPal 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.
1 2 3 4 5 6 7 8 9 |
<form class="w3-container w3-display-middle w3-card-4 " method="POST" id="payment-form" action="/payment/add-funds/paypal"> {{ csrf_field() }} <h2 class="w3-text-blue">Payment Form</h2> <p>Demo PayPal form - Integrating paypal in laravel</p> <p> <label class="w3-text-blue"><b>Enter Amount</b></label> <input class="w3-input w3-border" name="amount" type="text"></p> <button class="w3-btn w3-blue">Pay with PayPal</button></p> </form> |
PayPal Payment Controller
I will create a new controller to manage all the PayPal related PHP stuff.
1 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 |
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.
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 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
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’.
1 2 |
$payer = new Payer(); $payer->setPaymentMethod("paypal"); |
Item information
(Optional) Lets you specify item wise information
1 2 3 4 5 6 7 8 9 |
$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.
1 2 3 |
$amount = new Amount(); $amount->setCurrency('USD') ->setTotal($request->get('amount')); |
Transaction
A transaction defines the contract of a payment – what is the payment for and who is fulfilling it.
1 2 3 4 |
$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.
1 2 3 |
$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’
1 2 3 4 5 |
$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 return object contains the state and the URL to which the buyer must be redirected to for payment approval
1 |
$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 a payment is processed.
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 |
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.
1 |
$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.
1 2 3 4 5 |
$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 success, I will show a success message and a failure message if the payment fails.
1 2 3 4 5 6 7 8 9 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
@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,
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