PayPal is one of the most popular payment gateway that allows website owners to accept payment online. In the web application, PayPal is the easiest option to integrate payment gateway and enable online payment on the website. There are various payment methods available that the buyer can choose from with PayPal checkout. PayPal checkout is the quickest way to enable an online payment system on the website.
PayPal Standard Checkout uses JavaScript SDK to integrate payment button in the webpage. The buyer can use this button to make payment with their PayPal account or debit/credit card. Integrate PayPal Standard Checkout system to allow buyers to purchase online and make the payment from the website. In this tutorial, we will show you how to integrate PayPal Standard Checkout in PHP. Here we will provide a step-by-step guide for PayPal checkout integration with JavaScript using PHP.
In this example script, we will go through the following operations to integrate PayPal standard checkout system in the web application using PHP.
To get started with the PayPal REST API, you need to create a developer account on the PayPal Developer Dashboard.
PayPal provides two environments, Sandbox and Live. Sandbox environment allows developers to test the PayPal checkout process before making it Live for production usage. You can create sandbox Business and Personal accounts from the Sandbox Accounts section.
In the PayPal Developer Dashboard, you can switch between the Sandbox and Live environment from the toggle button placed at the top-right corner.
Create Sandbox Accounts:
Create REST API App:
In the Apps & Credentials section, create a new REST API App with Type: Merchant.
After the App creation, the Client ID and Secret will be generated.
Live REST API Credentials:
At the top right corner, toggle the switch to Live. Then navigate to the Apps & Credentials section.
Before getting started to develop PayPal standard checkout payment script with PHP, take a look at the file structure.
paypal_standard_checkout_in_php/ ├── config.php ├── dbConnect.php ├── index.php ├── PaypalCheckout.class.php ├── paypal_checkout_validate.php ├── payment-status.php └── css/ └── style.css
A table is required to store the transaction info in the database. The following SQL creates a transactions
table in the MySQL database that holds the transaction data.
CREATE TABLE `transactions` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`item_number` varchar(50) DEFAULT NULL,
`item_name` varchar(255) DEFAULT NULL,
`item_price` float(10,2) DEFAULT NULL,
`item_price_currency` varchar(10) DEFAULT NULL,
`payer_id` varchar(50) DEFAULT NULL,
`payer_name` varchar(50) DEFAULT NULL,
`payer_email` varchar(50) DEFAULT NULL,
`payer_country` varchar(20) DEFAULT NULL,
`merchant_id` varchar(255) DEFAULT NULL,
`merchant_email` varchar(50) DEFAULT NULL,
`order_id` varchar(50) NOT NULL,
`transaction_id` varchar(50) NOT NULL,
`paid_amount` float(10,2) NOT NULL,
`paid_amount_currency` varchar(10) NOT NULL,
`payment_source` varchar(50) DEFAULT NULL,
`payment_status` varchar(25) NOT NULL,
`created` datetime NOT NULL,
`modified` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
In the config.php
file, constant variables of the Product, PayPal Checkout API and database settings are defined.
Product Information:
$itemNumber
– Reference number of the product$itemName
– Name of the product.$itemPrice
– Product price.$currency
– Currency code.PayPal REST API Constants:
Database Constants:
<?php
// Product Details
$itemNumber = "DP12345";
$itemName = "Demo Product";
$itemPrice = 75;
$currency = "USD";
/* PayPal REST API configuration
* You can generate API credentials from the PayPal developer panel.
* See your keys here: https://developer.paypal.com/dashboard/
*/
define('PAYPAL_SANDBOX', TRUE); //TRUE=Sandbox | FALSE=Production
define('PAYPAL_SANDBOX_CLIENT_ID', 'Insert_PayPal_Client_ID_For_Sandbox_Here');
define('PAYPAL_SANDBOX_CLIENT_SECRET', 'Insert_PayPal_Secret_Key_For_Sandbox_Here');
define('PAYPAL_PROD_CLIENT_ID', 'Insert_Live_PayPal_Client_ID_Here');
define('PAYPAL_PROD_CLIENT_SECRET', 'Insert_Live_PayPal_Secret_Key_Here');
// Database configuration
define('DB_HOST', 'localhost');
define('DB_USERNAME', 'root');
define('DB_PASSWORD', 'root');
define('DB_NAME', 'codexworld_db');
?>
Note that: PayPal API Client ID and Secret will be found in the REST API App section of your PayPal Developer Dashboard.
The dbConnect.php
file is used to connect the database using PHP and MySQL.
<?php
// Connect with the database
$db = new mysqli(DB_HOST, DB_USERNAME, DB_PASSWORD, DB_NAME);
// Display error if failed to connect
if ($db->connect_errno) {
printf("Connect failed: %s\n", $db->connect_error);
exit();
}
?>
Add JavaScript SDK and PayPal payment button to accept payment on the web page.
First, include the configuration file to load the product and PayPal API variables.
<?php
// Include the configuration file
require_once 'config.php';
?>
PayPal JavaScript SDK Library:
Load the PayPal JS SDK, and pass the Client ID & currency in the query string of the URL.
<script src="https://www.paypal.com/sdk/js?client-id=<?php echo PAYPAL_SANDBOX?PAYPAL_SANDBOX_CLIENT_ID:PAYPAL_PROD_CLIENT_ID; ?>¤cy=<?php echo $currency; ?>"></script>
PayPal Button:
Initially, the product details are displayed with the PayPal payment button.
paypal-button-container
).<div class="panel">
<div class="overlay hidden"><div class="overlay-content"><img src="css/loading.gif" alt="Processing..."/></div></div>
<div class="panel-heading">
<h3 class="panel-title">Charge <?php echo '$'.$itemPrice; ?> with PayPal</h3>
<!-- Product Info -->
<p><b>Item Name:</b> <?php echo $itemName; ?></p>
<p><b>Price:</b> <?php echo '$'.$itemPrice.' '.$currency; ?></p>
</div>
<div class="panel-body">
<!-- Display status message -->
<div id="paymentResponse" class="hidden"></div>
<!-- Set up a container element for the button -->
<div id="paypal-button-container"></div>
</div>
</div>
Process Checkout Payment:
The paypal.Buttons()
method of PayPal JavaScript SDK is used to process the checkout operations.
#paypal-button-container
) using the render()
method.createOrder
: Sets up the transaction when the payment button is clicked.
purchase_units
:
custom_id
: Set the reference ID of the item.description
: Set item name.amount
:
currency_code
: Set currency code.value
: Set payable amount.items
:
name
: Set item name.description
: Set item details.unit_amount
:
currency_code
: Set currency code.value
: Set payable amount.category
: The item category type (DIGITAL_GOODS / PHYSICAL_GOODS / DONATION ).onApprove
: Finalize the transaction after the payer approves the payment.
paypal_checkout_validate.php
) for verification and further processing.The encodeFormData()
and setProcessing()
are the helper function used in the checkout process.
<script>
paypal.Buttons({
// Sets up the transaction when a payment button is clicked
createOrder: (data, actions) => {
return actions.order.create({
"purchase_units": [{
"custom_id": "<?php echo $itemNumber; ?>",
"description": "<?php echo $itemName; ?>",
"amount": {
"currency_code": "<?php echo $currency; ?>",
"value": <?php echo $itemPrice; ?>,
"breakdown": {
"item_total": {
"currency_code": "<?php echo $currency; ?>",
"value": <?php echo $itemPrice; ?>
}
}
},
"items": [
{
"name": "<?php echo $itemName; ?>",
"description": "<?php echo $itemName; ?>",
"unit_amount": {
"currency_code": "<?php echo $currency; ?>",
"value": <?php echo $itemPrice; ?>
},
"quantity": "1",
"category": "DIGITAL_GOODS"
},
]
}]
});
},
// Finalize the transaction after payer approval
onApprove: (data, actions) => {
return actions.order.capture().then(function(orderData) {
setProcessing(true);
var postData = {paypal_order_check: 1, order_id: orderData.id};
fetch('paypal_checkout_validate.php', {
method: 'POST',
headers: {'Accept': 'application/json'},
body: encodeFormData(postData)
})
.then((response) => response.json())
.then((result) => {
if(result.status == 1){
window.location.href = "payment-status.php?checkout_ref_id="+result.ref_id;
}else{
const messageContainer = document.querySelector("#paymentResponse");
messageContainer.classList.remove("hidden");
messageContainer.textContent = result.msg;
setTimeout(function () {
messageContainer.classList.add("hidden");
messageText.textContent = "";
}, 5000);
}
setProcessing(false);
})
.catch(error => console.log(error));
});
}
}).render('#paypal-button-container');
const encodeFormData = (data) => {
var form_data = new FormData();
for ( var key in data ) {
form_data.append(key, data[key]);
}
return form_data;
}
// Show a loader on payment form processing
const setProcessing = (isProcessing) => {
if (isProcessing) {
document.querySelector(".overlay").classList.remove("hidden");
} else {
document.querySelector(".overlay").classList.add("hidden");
}
}
</script>
We will create a custom library to handle PayPal API execution with PHP. This PaypalCheckout library helps to validate transactions and retrieve order details with PayPal Orders REST API using PHP. The cURL method is used to call the PayPal checkout APIs in PHP.
validate()
– Fetch the access token from PayPal OAuth 2 API.
<?php
/**
*
* This PayPal Checkout API handler class is a custom PHP library to handle the PayPal API calls.
*
* @class PaypalCheckout
* @author CodexWorld
* @link https://www.codexworld.com
* @version 1.0
*/
// Include the configuration file
include_once 'config.php';
class PaypalCheckout{
public $paypalAuthAPI = PAYPAL_SANDBOX?'https://api-m.sandbox.paypal.com/v1/oauth2/token':'https://api-m.paypal.com/v1/oauth2/token';
public $paypalAPI = PAYPAL_SANDBOX?'https://api-m.sandbox.paypal.com/v2/checkout':'https://api-m.paypal.com/v2/checkout';
public $paypalClientID = PAYPAL_SANDBOX?PAYPAL_SANDBOX_CLIENT_ID:PAYPAL_PROD_CLIENT_ID;
private $paypalSecret = PAYPAL_SANDBOX?PAYPAL_SANDBOX_CLIENT_SECRET:PAYPAL_PROD_CLIENT_SECRET;
public function validate($order_id){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->paypalAuthAPI);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, $this->paypalClientID.":".$this->paypalSecret);
curl_setopt($ch, CURLOPT_POSTFIELDS, "grant_type=client_credentials");
$auth_response = json_decode(curl_exec($ch));
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($http_code != 200 && !empty($auth_response->error)) {
throw new Exception('Error '.$auth_response->error.': '.$auth_response->error_description);
}
if(empty($auth_response)){
return false;
}else{
if(!empty($auth_response->access_token)){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->paypalAPI.'/orders/'.$order_id);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json', 'Authorization: Bearer '. $auth_response->access_token));
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
$api_data = json_decode(curl_exec($ch), true);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($http_code != 200 && !empty($api_data['error'])) {
throw new Exception('Error '.$api_data['error'].': '.$api_data['error_description']);
}
return !empty($api_data) && $http_code == 200?$api_data:false;
}else{
return false;
}
}
}
}
This server-side script is accessed by the client-side Fetch API defined in onApprove()
method to verify orders using PayPal REST API and store transaction details in the database using PHP and MySQL.
validate()
function of the PaypalCheckout class to verify the order by reference ID posted from the client-side script.<?php
// Include the configuration file
require_once 'config.php';
// Include the database connection file
include_once 'dbConnect.php';
// Include the PayPal API library
require_once 'PaypalCheckout.class.php';
$paypal = new PaypalCheckout;
$response = array('status' => 0, 'msg' => 'Transaction Failed!');
if(!empty($_POST['paypal_order_check']) && !empty($_POST['order_id'])){
// Validate and get order details with PayPal API
try {
$order = $paypal->validate($_POST['order_id']);
} catch(Exception $e) {
$api_error = $e->getMessage();
}
if(!empty($order)){
$order_id = $order['id'];
$intent = $order['intent'];
$order_status = $order['status'];
$order_time = date("Y-m-d H:i:s", strtotime($order['create_time']));
if(!empty($order['purchase_units'][0])){
$purchase_unit = $order['purchase_units'][0];
$item_number = $purchase_unit['custom_id'];
$item_name = $purchase_unit['description'];
if(!empty($purchase_unit['amount'])){
$currency_code = $purchase_unit['amount']['currency_code'];
$amount_value = $purchase_unit['amount']['value'];
}
if(!empty($purchase_unit['payments']['captures'][0])){
$payment_capture = $purchase_unit['payments']['captures'][0];
$transaction_id = $payment_capture['id'];
$payment_status = $payment_capture['status'];
}
if(!empty($purchase_unit['payee'])){
$payee = $purchase_unit['payee'];
$payee_email_address = $payee['email_address'];
$merchant_id = $payee['merchant_id'];
}
}
$payment_source = '';
if(!empty($order['payment_source'])){
foreach($order['payment_source'] as $key=>$value){
$payment_source = $key;
}
}
if(!empty($order['payer'])){
$payer = $order['payer'];
$payer_id = $payer['payer_id'];
$payer_name = $payer['name'];
$payer_given_name = !empty($payer_name['given_name'])?$payer_name['given_name']:'';
$payer_surname = !empty($payer_name['surname'])?$payer_name['surname']:'';
$payer_full_name = trim($payer_given_name.' '.$payer_surname);
$payer_full_name = filter_var($payer_full_name, FILTER_SANITIZE_STRING,FILTER_FLAG_STRIP_HIGH);
$payer_email_address = $payer['email_address'];
$payer_address = $payer['address'];
$payer_country_code = !empty($payer_address['country_code'])?$payer_address['country_code']:'';
}
if(!empty($order_id) && $order_status == 'COMPLETED'){
// Check if any transaction data is exists already with the same TXN ID
$sqlQ = "SELECT id FROM transactions WHERE transaction_id = ?";
$stmt = $db->prepare($sqlQ);
$stmt->bind_param("s", $transaction_id);
$stmt->execute();
$stmt->bind_result($row_id);
$stmt->fetch();
$payment_id = 0;
if(!empty($row_id)){
$payment_id = $row_id;
}else{
// Insert transaction data into the database
$sqlQ = "INSERT INTO transactions (item_number,item_name,item_price,item_price_currency,payer_id,payer_name,payer_email,payer_country,merchant_id,merchant_email,order_id,transaction_id,paid_amount,paid_amount_currency,payment_source,payment_status,created,modified) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,NOW())";
$stmt = $db->prepare($sqlQ);
$stmt->bind_param("ssdsssssssssdssss", $item_number, $item_name, $itemPrice, $currency, $payer_id, $payer_full_name, $payer_email_address, $payer_country_code, $merchant_id, $payee_email_address, $order_id, $transaction_id, $amount_value, $currency_code, $payment_source, $payment_status, $order_time);
$insert = $stmt->execute();
if($insert){
$payment_id = $stmt->insert_id;
}
}
if(!empty($payment_id)){
$ref_id_enc = base64_encode($transaction_id);
$response = array('status' => 1, 'msg' => 'Transaction completed!', 'ref_id' => $ref_id_enc);
}
}
}else{
$response['msg'] = $api_error;
}
}
echo json_encode($response);
?>
Based on the status return by the order.capture()
, the buyer is redirected to this page.
<?php
// Include the configuration file
require_once 'config.php';
// Include the database connection file
require_once 'dbConnect.php';
$payment_ref_id = $statusMsg = '';
$status = 'error';
// Check whether the payment ID is not empty
if(!empty($_GET['checkout_ref_id'])){
$payment_txn_id = base64_decode($_GET['checkout_ref_id']);
// Fetch transaction data from the database
$sqlQ = "SELECT id,payer_id,payer_name,payer_email,payer_country,order_id,transaction_id,paid_amount,paid_amount_currency,payment_source,payment_status,created FROM transactions WHERE transaction_id = ?";
$stmt = $db->prepare($sqlQ);
$stmt->bind_param("s", $payment_txn_id);
$stmt->execute();
$stmt->store_result();
if($stmt->num_rows > 0){
// Get transaction details
$stmt->bind_result($payment_ref_id, $payer_id, $payer_name, $payer_email, $payer_country, $order_id, $transaction_id, $paid_amount, $paid_amount_currency, $payment_source, $payment_status, $created);
$stmt->fetch();
$status = 'success';
$statusMsg = 'Your Payment has been Successful!';
}else{
$statusMsg = "Transaction has been failed!";
}
}else{
header("Location: index.php");
exit;
}
?>
<?php if(!empty($payment_ref_id)){ ?>
<h1 class="<?php echo $status; ?>"><?php echo $statusMsg; ?></h1>
<h4>Payment Information</h4>
<p><b>Reference Number:</b> <?php echo $payment_ref_id; ?></p>
<p><b>Order ID:</b> <?php echo $order_id; ?></p>
<p><b>Transaction ID:</b> <?php echo $transaction_id; ?></p>
<p><b>Paid Amount:</b> <?php echo $paid_amount.' '.$paid_amount_currency; ?></p>
<p><b>Payment Status:</b> <?php echo $payment_status; ?></p>
<p><b>Date:</b> <?php echo $created; ?></p>
<h4>Payer Information</h4>
<p><b>ID:</b> <?php echo $payer_id; ?></p>
<p><b>Name:</b> <?php echo $payer_name; ?></p>
<p><b>Email:</b> <?php echo $payer_email; ?></p>
<p><b>Country:</b> <?php echo $payer_country; ?></p>
<h4>Product Information</h4>
<p><b>Name:</b> <?php echo $itemName; ?></p>
<p><b>Price:</b> <?php echo $itemPrice.' '.$currency; ?></p>
<?php }else{ ?>
<h1 class="error">Your Payment been failed!</h1>
<p class="error"><?php echo $statusMsg; ?></p>
<?php }?>
Once the integration is completed and the payment process is working properly, follow the below steps to make PayPal checkout live.
1. Go to the PayPal Developer Dashboard Stripe account.
2. In the config.php
file,
define('PAYPAL_SANDBOX', FALSE);
define('PAYPAL_PROD_CLIENT_ID', 'Insert_Live_PayPal_Client_ID_Here');
define('PAYPAL_PROD_CLIENT_SECRET', 'Insert_Live_PayPal_Secret_Key_Here');
PayPal Advanced Checkout Card Payments Integration in PHP
Previously, the PayPal Standard payment gateway was used to accept payment with PayPal form variables. The PayPal standard checkout is the replacement of it and introduced with advanced features and security. The PayPal checkout provides a smooth UI experience on both desktop and mobile devices. So, you don’t need to worry about the payment checkout UI on the website. Use our example script to integrate the PayPal checkout system on the website with JavaScript and accept payment online instantly.
Do you want to get implementation help, or enhance the functionality of this script? Click here to Submit Service Request
Very nice and well explained, exactly what I was looking for. I notice that only successfull payments are recordered on the database. Thanks anyway the basis are there to start and develope a complete solution. My regards
GretJob, thank you so much!
Hi, thanks for the code. Nice work!
Problem:
Being in sandbox mode there are 5 choices of payment options: Paypal, Sepa, GiroPay, Sofort, Debit/Credit Card
Being in production mode there a only 3 choices of payment options: Paypal, Sepa, Debit/Credit Card
Why are in production mode less payment options?
Do I have to configurate my Paypal Account to offer all option in production mode?
Any help is appreciated.
Ulrich
Yes, you must enable all the payment options in the PayPal Live account for production.
Thanks for the code.
Am having an issue where
https://developer.paypal.com/docs/api/orders/v2/#error-PERMISSION_DENIED
I did successfully get the access token from PayPal but not able to order details.
This is awesome, it does with Credit Cards. Thanks so much brothers and sisters!
This looks fantastic, just what I was looking for, a guide for real people rather than a corporation. May I ask, does this PayPal solution allow customers to make purchases with their credit card, even if they don’t have a PayPal account? I remember the old PayPal Express Checkout did not support credit cards.
How do i use the script multiple times on a website for different products?