PayPal Payment Gateway Integration in Laravel 9

Talha Maqsood
4 min readJul 4, 2022

First of all, let's create a fresh laravel project

composer create-project laravel/laravel paypal_laravel
The project is successfully created :)

Now, go inside the project directory and open the folder in any code editor. I will recommend using phpStorm

cd paypal_laravel/

Create a database in MySQL workbench (or PHPMyAdmin if you are using xampp or wamp). Open the .env file and configure the database credentials.

Although, we have nothing to do with the database in this project bacause we are not querying any data from database. Just in case, you are querying you need to connect database.

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE="your database name" // paypal_database
DB_USERNAME="your database username" // root
DB_PASSWORD="your database password" // password

Now, for PayPal payment gateway integration I'm going to use srmklive/laravel-paypal as this is the most powerful package laravel. So, run this command to install srmklive/laravel-paypal

composer require srmklive/paypal
srmklive/paypal successfully installed

After, the package is installed successfully. Now, go inside the config folder and open the app.php file and add the following lines,

'providers' => [
...
Srmklive\PayPal\Providers\PayPalServiceProvider::class,
...
],
'aliases' => [
...
'PayPal' => Srmklive\PayPal\Facades\PayPal::class,
...
],

Now, publish the package resources by running this below command,

php artisan vendor:publish — provider=”Srmklive\PayPal\Providers\PayPalServiceProvider”

This will create the paypal.php file in the config folder, so you can customize the paypal configurations as well. The paypal.php file is shown below,

<?php
/**
* PayPal Setting & API Credentials
* Created by Raza Mehdi <srmk@outlook.com>.
*/

return [
'mode' => env('PAYPAL_MODE', 'sandbox'), // Can only be 'sandbox' Or 'live'. If empty or invalid, 'live' will be used.
'sandbox' => [
'client_id' => env('PAYPAL_SANDBOX_CLIENT_ID', ''),
'client_secret' => env('PAYPAL_SANDBOX_CLIENT_SECRET', ''),
'app_id' => 'APP-80W284485P519543T',
],
'live' => [
'client_id' => env('PAYPAL_LIVE_CLIENT_ID', ''),
'client_secret' => env('PAYPAL_LIVE_CLIENT_SECRET', ''),
'app_id' => env('PAYPAL_LIVE_APP_ID', ''),
],

'payment_action' => env('PAYPAL_PAYMENT_ACTION', 'Sale'), // Can only be 'Sale', 'Authorization' or 'Order'
'currency' => env('PAYPAL_CURRENCY', 'USD'),
'notify_url' => env('PAYPAL_NOTIFY_URL', ''), // Change this accordingly for your application.
'locale' => env('PAYPAL_LOCALE', 'en_US'), // force gateway language i.e. it_IT, es_ES, en_US ... (for express checkout only)
'validate_ssl' => env('PAYPAL_VALIDATE_SSL', true), // Validate SSL when creating api client.
];

Now, you need paypal client id and client secret. Follow this tutorial to get client id and client secret

Add variables to .env once you get the client id and client secret. Currently, the mode is sandbox because of testing, you need to add sandbox client id and secret when the mode is a sandbox. BUT, for live mode, you need to add the real client id, client secret, and app id.

PAYPAL_MODE=sandbox // or live// for sandbox testing
PAYPAL_SANDBOX_CLIENT_ID=xyz...
PAYPAL_SANDBOX_CLIENT_SECRET=xyz...
// for live
PAYPAL_LIVE_CLIENT_ID=xyz...
PAYPAL_LIVE_CLIENT_SECRET=xyz...
PAYPAL_LIVE_APP_ID=12xyz...

Lets create a controller for paypal transactions logic

php artisan make:controller PaypalController

Write the code in PaypalController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use Srmklive\PayPal\Services\PayPal as PayPalClient;

class PaypalController extends Controller
{
/**
* process transaction.
*
* @return \Illuminate\Http\RedirectResponse
*/
public function processTransaction($amount)
{
try {
$provider = new PayPalClient;
$provider->setApiCredentials(config('paypal'));
$paypalToken = $provider->getAccessToken();

$response = $provider->createOrder([
"intent" => "CAPTURE",
"application_context" => [
"return_url" => route('successTransaction'),
"cancel_url" => route('cancelTransaction'),
],
"purchase_units" => [
0 => [
"amount" => [
"currency_code" => "USD",
"value" => (int)$amount
]
]
]
]);

if (isset($response['id']) && $response['id'] != null) {
foreach ($response['links'] as $link) {
if ($link['rel'] == 'approve') {
return redirect()->away($link['href']);
}
}

Session::flash('error', 'Something went wrong.');
return redirect()->route('homepage');

} else {
Session::flash('error', $response['message'] ?? 'Something went wrong.');
return redirect()->route('homepage');
}
} catch (\Throwable $throwable) {
Session::flash('error', $throwable->getMessage() ?? 'Something went wrong.');
return redirect()->route('homepage');
}
}

/**
* success transaction.
*
* @return \Illuminate\Http\RedirectResponse
*/
public function successTransaction(Request $request)
{
DB::beginTransaction();
try {
$provider = new PayPalClient;
$provider->setApiCredentials(config('paypal'));
$provider->getAccessToken();
$response = $provider->capturePaymentOrder($request['token']);

if (isset($response['status']) && $response['status'] == 'COMPLETED') {
Session::flash('success', 'Transaction Successfully Completed.');
return redirect()->route('homepage');
} else {
DB::rollBack();
Session::flash('error', $response['message'] ?? 'Something went wrong.');
return redirect()->route('homepage');
}
} catch (\Throwable $throwable) {
DB::rollBack();
Session::flash('error', $throwable->getMessage() ?? 'Something went wrong.');
return redirect()->route('homepage');
}
}

/**
* cancel transaction.
*
* @return \Illuminate\Http\RedirectResponse
*/
public function cancelTransaction(Request $request)
{
Session::flash('error', 'Payment cancelled.');
return redirect()->route('homepage');
}
}

Open the web.php file inside the routes/web.php and write the following routes

Route::get('/', function () {
return view('index');
})->name('homepage');

Route::get('process-transaction/{amount}', [\App\Http\Controllers\PaypalController::class, 'processTransaction'])->name('processTransaction');
Route::get('success-transaction', [\App\Http\Controllers\PaypalController::class, 'successTransaction'])->name('successTransaction');
Route::get('cancel-transaction', [\App\Http\Controllers\PaypalController::class, 'cancelTransaction'])->name('cancelTransaction');

Create the index.blade.php file inside the resources/views folder

<!DOCTYPE html>
<html lang="eng">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Paypal Payment Gateway</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container py-2 text-center">

@if(Session::has('success'))
<div class="alert alert-success">{{ Session::get('success') }}</div>
@endif
@if(Session::has('error'))
<div class="alert alert-danger">{{ Session::get('error') }}</div>
@endif

<a class="btn btn-info" href="{{ route('processTransaction', ['amount' => 100]) }}">Pay 100$ with PayPal</a>
</div>
</body>
</html>

Alright, everything is done now just run the server and test the project.

php artisan serve

Run the project on browser: http://127.0.0.1:8000/

If you have any questions feel free to contact me :)

--

--

Talha Maqsood

Crafting next-level software experiences with Node.js, Laravel, and Blockchain - all while making the complex seem effortless.