How to integrate PayPal payment gateway in Laravel

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.

Project on Github

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 and secret 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.
  • PayPal Payment Integration - justlaravel.com
  • I have created both merchant and buyer test accounts.
  • You will need to create a new app to get the client_id and secret keys."<yoastmark
  • 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'
        ),
    ];

Project on Github

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.

" {{ csrf_field() }} <h2 class=

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);

Project on Github

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.

if (isset($_GET[‘success’]) && $_GET[‘success’] == ‘true’) {

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">&times;</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">&times;</span>
        <p>{!! $message !!}</p>
    </div>
    <?php Session::forget('error');?>
    @endif

Check out the images below,

Enter some amount,

PayPal integration laravel - justlaravel.com
PayPal integration laravel – justlaravel.com

 

Logging with test buyer account,

PayPal integration laravel - justlaravel.com
PayPal integration laravel – justlaravel.com

 

Paypal payment page,

PayPal integration laravel - justlaravel.com
PayPal integration laravel – justlaravel.com

 

Success mesage,

PayPal integration laravel - justlaravel.com
PayPal integration laravel – justlaravel.com

 

Project on Github

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.



10 thoughts on “How to integrate PayPal payment gateway in Laravel”

  • 1
    rmallanao on March 20, 2018 Reply

    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.

  • 3
    srinath on December 4, 2018 Reply

    “please choose another way to pay ” generating such error

  • 4
    mopp12 on March 12, 2019 Reply

    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

  • 5
    José Luis on April 9, 2019 Reply

    Hi, I get the following error when uploading it to my hosting: Use of undefined constant CURLOPT_SSLVERSION – assumed ‘CURLOPT_SSLVERSION’

    • 6
      avinash on April 18, 2019 Reply

      Do your server has SSL installed?

  • 7
    Thiru on May 2, 2020 Reply

    Give me the example for Paypal recurring payment.Thanks

  • 8
    hema srinivas on May 2, 2020 Reply

    i get payment capture status – pending and status code- pending_review, can you say any solution

  • 9
    Mr. 21 on July 27, 2020 Reply

    hello guys, how to sift from sandbox to real production site? please tell me what changes I need to make?

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.