PayPal Advanced Checkout lets you accept credit and debit card payments directly from the website. You can set up custom credit card fields and add card payment form without any PayPal branding. The card input fields and payment form style can be customized as per the website design along with your business branding. The PayPal JavaScript SDK and REST API provide an easy way to integrate advanced checkout and credit card payment system in the web application.
PayPal has 2 types of checkout systems, Standard and Advanced. If you want to embed PayPal branded payment component, integrate PayPal Standard Checkout with PHP. On the other hand, use the PayPal advanced checkout integration for card payment without any third-party component.
Direct card payment allows the buyer to purchase online and make payments using their credit and debit card on the website. PayPal advanced checkout helps business owners to accept payment with credit/debit cards from the website. In this tutorial, we will show you how to integrate PayPal advanced checkout in PHP to accept credit and debit card payments on the website. Here we will provide a step-by-step guide to integrate PayPal card payments with customized credit/debit card input fields.
In this example script, we will go through the following operations to integrate PayPal credit and debit card payment checkout system with JavaScript SDK & REST API using PHP.
Before beginning the integration, you need to set up a PayPal business account for advanced card payments. You are required a sandbox business account with Advanced Credit and Debit Card payments feature enabled.
PayPal provides two environments, Sandbox and Live. Sandbox environment allows developers to test the PayPal checkout integration before making it Live for production use. You can create sandbox Business and Personal accounts from the Sandbox Accounts section.
If you have not created a sandbox account already, create a sandbox business account first. To confirm that the Advanced Credit and Debit Card payments feature is enabled on your sandbox business account and get the REST API credentials do the following steps.
Log into the PayPal Developer Dashboard, and toggle Sandbox using the button placed at the top-right corner.
Create Sandbox Merchant Account:
Create a sandbox business account with Account type: Business. This merchant account is required to attach at the time of the REST API app.
Create REST API App:
In the Apps & Credentials section, create a new REST API App with Type: Merchant.
Save changes and copy the API credentials for later use in the script.
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 advanced checkout payment script with PHP, take a look at the file structure.
paypal_advanced_checkout_in_php/ ├── config.php ├── dbConnect.php ├── index.php ├── PaypalCheckout.class.php ├── paypal_checkout_init.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,
`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_source_card_name` varchar(50) DEFAULT NULL,
`payment_source_card_last_digits` varchar(4) DEFAULT NULL,
`payment_source_card_expiry` varchar(10) DEFAULT NULL,
`payment_source_card_brand` varchar(25) DEFAULT NULL,
`payment_source_card_type` varchar(25) 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 REST 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 card fields to accept credit card payments directly 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';
?>
The sample CSS file from the paypalobjects library can be used to style the card field. Instead, you should use styles that align with your website using the CSS properties supported by PayPal card fields.
<link
rel="stylesheet"
type="text/css"
href="https://www.paypalobjects.com/webstatic/en_US/developer/docs/css/cardfields.css"
/>
PayPal JavaScript SDK Library:
Load the PayPal JS SDK with the card-fields
component, and pass the Client ID in the query string of the URL.
<script src="https://www.paypal.com/sdk/js?components=card-fields&client-id=<?php echo PAYPAL_SANDBOX?PAYPAL_SANDBOX_CLIENT_ID:PAYPAL_PROD_CLIENT_ID; ?>"></script>
PayPal Card Fields:
Initially, the product details are displayed with the card fields.
<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="checkout-form">
<div id="card-name-field-container"></div>
<div id="card-number-field-container"></div>
<div id="card-expiry-field-container"></div>
<div id="card-cvv-field-container"></div>
<button id="card-field-submit-button" type="button">
Pay Now
</button>
</div>
</div>
</div>
Process Card Payments with JavaScript:
The paypal.CardFields() method of PayPal JavaScript SDK is used to process the card payments.
createOrder
: Sets up the transaction when the payment button is clicked.
paypal_checkout_init.php
) to create an order using PayPal REST API.onApprove
: Finalize the transaction after the payer approves the payment.
paypal_checkout_init.php
) to capture payment for an order and process it further.submit()
function on the CardField component.encodeFormData()
, setProcessing()
, and resultMessage()
are the helper functions used in the PayPal advanced checkout process.<script>
// Create the Card Fields Component and define callbacks
const cardField = paypal.CardFields({
createOrder: function (data) {
setProcessing(true);
var postData = {request_type: 'create_order', payment_source: data.paymentSource};
return fetch("paypal_checkout_init.php", {
method: "POST",
headers: {'Accept': 'application/json'},
body: encodeFormData(postData)
})
.then((res) => {
return res.json();
})
.then((result) => {
setProcessing(false);
if(result.status == 1){
return result.data.id;
}else{
resultMessage(result.msg);
return false;
}
});
},
onApprove: function (data) {
setProcessing(true);
const { orderID } = data;
var postData = {request_type: 'capture_order', order_id: orderID};
return fetch('paypal_checkout_init.php', {
method: "POST",
headers: {'Accept': 'application/json'},
body: encodeFormData(postData)
})
.then((res) => {
return res.json();
})
.then((result) => {
// Redirect to success page
if(result.status == 1){
window.location.href = "payment-status.php?checkout_ref_id="+result.ref_id;
}else{
resultMessage(result.msg);
}
setProcessing(false);
});
},
onError: function (error) {
// Do something with the error from the SDK
},
});
// Render each field after checking for eligibility
if (cardField.isEligible()) {
const nameField = cardField.NameField();
nameField.render("#card-name-field-container");
const numberField = cardField.NumberField();
numberField.render("#card-number-field-container");
const cvvField = cardField.CVVField();
cvvField.render("#card-cvv-field-container");
const expiryField = cardField.ExpiryField();
expiryField.render("#card-expiry-field-container");
// Add click listener to submit button and call the submit function on the CardField component
document
.getElementById("card-field-submit-button")
.addEventListener("click", () => {
cardField.submit().then(() => {
// submit successful
})
.catch((error) => {
resultMessage(`Sorry, your transaction could not be processed... >>> ${error}`);
});
});
} else {
// Hides card fields if the merchant isn't eligible
document.querySelector("#checkout-form").style = "display: none";
}
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");
}
}
// Display status message
const resultMessage = (msg_txt) => {
const messageContainer = document.querySelector("#paymentResponse");
messageContainer.classList.remove("hidden");
messageContainer.textContent = msg_txt;
setTimeout(function () {
messageContainer.classList.add("hidden");
messageContainer.textContent = "";
}, 5000);
}
</script>
We will create a custom library to handle PayPal REST API execution with PHP. This PaypalCheckout library helps to execute PayPal Orders API operations using PHP. The cURL method is used to call the PayPal REST APIs in PHP.
generateAccessToken()
– Fetch the access token from PayPal OAuth 2 API.createOrder()
– Initialize cURL request to create an order using PayPal Orders REST API v2 using PHP.captureOrder()
– Initialize cURL request to capture payment for an order using PayPal Orders REST API v2 using PHP.<?php
/**
*
* This PayPal Checkout API handler class is a custom PHP library to handle the PayPal REST 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 generateAccessToken(){
$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('Failed to generate Access Token: '.$auth_response->error.' >>> '.$auth_response->error_description);
}
if(!empty($auth_response)){
return $auth_response->access_token;
}else{
return false;
}
}
public function createOrder($productInfo, $paymentSource){
$accessToken = $this->generateAccessToken();
if(empty($accessToken)){
return false;
}else{
$postParams = array(
"intent" => "CAPTURE",
"purchase_units" => array(
array(
"custom_id" => $productInfo['item_number'],
"description" => $productInfo['item_name'],
"amount" => array(
"currency_code" => $productInfo['currency'],
"value" => $productInfo['price']
)
)
)
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->paypalAPI.'/orders/');
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 '. $accessToken));
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postParams));
$api_resp = curl_exec($ch);
$api_data = json_decode($api_resp, true);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($http_code != 200 && $http_code != 201) {
throw new Exception('Failed to create Order ('.$http_code.'): '.$api_resp);
}
return !empty($api_data) && ($http_code == 200 || $http_code == 201)?$api_data:false;
}
}
public function captureOrder($orderId){
$accessToken = $this->generateAccessToken();
if(empty($accessToken)){
return false;
}else{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->paypalAPI.'/orders/'.$orderId.'/capture');
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 '. $accessToken));
curl_setopt($ch, CURLOPT_POST, true);
$api_resp = curl_exec($ch);
$api_data = json_decode($api_resp, true);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($http_code != 200 && $http_code != 201) {
throw new Exception('Failed to create Order ('.$http_code.'): '.$api_resp);
}
return !empty($api_data) && ($http_code == 200 || $http_code == 201)?$api_data:false;
}
}
}
This server-side script is accessed by the client-side Fetch API defined in createOrder()
and onApprove()
methods in the client-side JavaScript code to process the card payment with PayPal REST API using PHP.
create_order
request is submitted:
capture_order
request is submitted:
<?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' => 'Request Failed!');
$api_error = '';
if(!empty($_POST['request_type']) && $_POST['request_type'] == 'create_order'){
$payment_source = $_POST['payment_source'];
$product_data = array(
'item_number' => $itemNumber,
'item_name' => $itemName,
'price' => $itemPrice,
'currency' => $currency,
);
// Create order with PayPal Orders API
try {
$order = $paypal->createOrder($product_data, $payment_source);
} catch(Exception $e) {
$api_error = $e->getMessage();
}
if(!empty($order)){
$response = array(
'status' => 1,
'data' => $order
);
}else{
$response['msg'] = $api_error;
}
}elseif(!empty($_POST['request_type']) && $_POST['request_type'] == 'capture_order'){
$order_id = $_POST['order_id'];
// Create order with PayPal Orders API
try {
$order = $paypal->captureOrder($order_id);
} catch(Exception $e) {
$api_error = $e->getMessage();
}
if(!empty($order)){
$order_id = $order['id'];
$order_status = $order['status'];
$payment_source = $payment_source_card_name = $payment_source_card_last_digits = $payment_source_card_expiry = $payment_source_card_brand = $payment_source_card_type = '';
if(!empty($order['payment_source'])){
foreach($order['payment_source'] as $key=>$value){
$payment_source = $key;
if($payment_source == 'card'){
$payment_source_card_name = $value['name'];
$payment_source_card_last_digits = $value['last_digits'];
$payment_source_card_expiry = $value['expiry'];
$payment_source_card_brand = $value['brand'];
$payment_source_card_type = $value['type'];
}
}
}
if(!empty($order['purchase_units'][0])){
$purchase_unit = $order['purchase_units'][0];
if(!empty($purchase_unit['payments'])){
$payments = $purchase_unit['payments'];
if(!empty($payments['captures'])){
$captures = $payments['captures'];
if(!empty($captures[0])){
$transaction_id = $captures[0]['id'];
$payment_status = $captures[0]['status'];
$custom_id = $captures[0]['custom_id'];
$amount_value = $captures[0]['amount']['value'];
$currency_code = $captures[0]['amount']['currency_code'];
$create_time = date("Y-m-d H:i:s", strtotime($captures[0]['create_time']));
}
}
}
}
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,order_id,transaction_id,paid_amount,paid_amount_currency,payment_source,payment_source_card_name,payment_source_card_last_digits,payment_source_card_expiry,payment_source_card_brand,payment_source_card_type,payment_status,created,modified) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,NOW())";
$stmt = $db->prepare($sqlQ);
$stmt->bind_param("ssdsssdsssssssss", $custom_id, $itemName, $itemPrice, $currency, $order_id, $transaction_id, $amount_value, $currency_code, $payment_source, $payment_source_card_name, $payment_source_card_last_digits, $payment_source_card_expiry, $payment_source_card_brand, $payment_source_card_type, $payment_status, $create_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 API, 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,order_id,transaction_id,paid_amount,paid_amount_currency,payment_source,payment_source_card_name,payment_source_card_last_digits,payment_source_card_expiry,payment_source_card_brand,payment_source_card_type,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, $order_id, $transaction_id, $paid_amount, $paid_amount_currency, $payment_source, $payment_source_card_name, $payment_source_card_last_digits, $payment_source_card_expiry, $payment_source_card_brand, $payment_source_card_type, $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>Payment Source</h4>
<p><b>Method:</b> <?php echo strtoupper($payment_source); ?></p>
<p><b>Card Type:</b> <?php echo $payment_source_card_type; ?></p>
<p><b>Card Brand:</b> <?php echo $payment_source_card_brand; ?></p>
<p><b>Card Number:</b> <?php echo 'XXXX XXXX XXXX '.$payment_source_card_last_digits; ?></p>
<p><b>Card Expiry:</b> <?php echo $payment_source_card_expiry; ?></p>
<p><b>Card Holder Name:</b> <?php echo $payment_source_card_name; ?></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 has been failed!</h1>
<p class="error"><?php echo $statusMsg; ?></p>
<?php } ?>
To test the payment process, you need test card details. Use any of the following test card numbers, a valid future expiration date, and any random CVV number, to test PayPal advanced card payment integration in PHP.
Once the integration is completed and the payment process is working properly, follow the below steps to make PayPal advanced card payments live.
1. Log into the PayPal Developer Dashboard, toggle Live, and go to Apps & Credentials.
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');
Stripe Payment Gateway Integration in PHP
There are various payment gateway service providers available to integrate card payments into the website. The PayPal advanced checkout for direct merchants is one of the most popular service for accepting credit and debit card payments in the web application. Use our example script to integrate PayPal credit and debit card payments with JavaScript using PHP. You can also customize the card fields and payment form to align it with the website design.
Do you want to get implementation help, or enhance the functionality of this script? Click here to Submit Service Request
Hi codexworld,
thank you a lot for the knowledge you are sharing
for this example, when tried to execute it I get this error message : Sorry, your transaction could not be processed… >>> Error: Expected an order id to be passed
any help!
kindest regards
Hi! Thank you for the tutorial! I followed the instructions but I am getting an error when I press the Pay Now button. I am getting the “No ack for postMessage createOrder()” error message in debug mode. In normal mode I am getting “Error: JSON.parse: unexpected character at line 2 column 1 of the JSON data”
I am trying it in sandbox mode. Do you know how to overcome that? Thanks
Hello, I’m from Argentina and it won’t let me have a PayPal account, but what can I do since I’m interested in your website? You tell me how much it is worth in dollars and now for the effort and help
for 3DS autorizazion?