PayPal Subscriptions Payment Gateway Integration in PHP

PayPal Subscriptions payment lets you accept payment for your member subscription service. If you have a membership website and want to add a subscription feature, PayPal subscription API helps to do it easily. The PayPal Subscription button is a quick and effective way to allow your website’s members to purchase the membership online.

PayPal subscription integration process is mostly the same as PayPal Standard Checkout, by has some differences with the billing procedure. By integrating the PayPal subscriptions you can bill customers recurringly at regular intervals. PayPal subscription payment gateway makes it easier to allow the user to subscribe online and manage users’ subscriptions on web application. In this tutorial, we will show you how to integrate PayPal subscription payment gateway in PHP and accept online payment on the website.

In the example script, we will use PayPal JavaScript SDK and REST API to set up recurring payments for subscription. The following functionality will be implemented to accept payment online and create subscriptions via PayPal Payment Gateway.

  1. Define an HTML element to attach the PayPal button.
  2. When the buyer clicks the button, the JS library launches the PayPal Checkout experience dialog.
    • The buyer completes the subscription agreement and payment.
  3. Create a subscription with PayPal JavaScript SDK and execute REST API request with PHP.
  4. On success, subscription info is captured and posted to the backend server for verification.
  5. The backend server verifies the transaction using PayPal Billing REST API.
  6. Store subscription data in the database with PHP and MySQL.
  7. Show a confirmation message to the subscriber.

PayPal REST API Credentials

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:

  • 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.
  • Sandbox Buyer Account: Create a sandbox buyer account with Account type: Personal. This buyer account will be used to test payment.
    • After the sandbox buyer account creation, an email ID and password will be generated. You can use these credentials to log in at the time of testing the PayPal checkout.

Create REST API App:
In the Apps & Credentials section, create a new REST API App with Type: Merchant.

  • Select a business account under the Sandbox Account dropdown.

After the App creation, the Client ID and Secret will be generated.

  • Copy these API credentials to 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.

  • Create a new REST API App, you will get the credentials (Client ID and Secret) for the Live environment.

Before getting started to integrate PayPal Subscription payment API in PHP, take a look at the file structure.

paypal_subscriptions_payment_with_php/
├── config.php
├── dbConnect.php
├── index.php
├── payment-status.php
├── paypal_checkout_init.php
├── PaypalCheckout.class.php
└── css/
    └── style.css

Create Database Tables

To store plans, members, and subscriptions information 3 tables are required in the database.

1. The following SQL creates a plans table to store the subscription plans info in the MySQL database.

CREATE TABLE `plans` (
  `id` int(5) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `price` float(10,2) NOT NULL,
  `interval` enum('DAY','WEEK','MONTH','YEAR') NOT NULL COMMENT 'DAY(365) | WEEK(52) | MONTH(12) | YEAR(1)',
  `interval_count` tinyint(2) NOT NULL DEFAULT 1,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

2. The following SQL creates a users table to store the member’s information in the MySQL database.

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `subscription_id` int(11) NOT NULL DEFAULT 0 COMMENT 'foreign key of "user_subscriptions" table',
  `first_name` varchar(25) NOT NULL,
  `last_name` varchar(25) NOT NULL,
  `email` varchar(50) NOT NULL,
  `password` varchar(255) DEFAULT NULL,
  `gender` enum('Male','Female') DEFAULT NULL,
  `phone` varchar(15) DEFAULT NULL,
  `created` datetime DEFAULT NULL,
  `modified` datetime DEFAULT NULL,
  `status` tinyint(1) NOT NULL DEFAULT 1,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

3.The following SQL creates a user_subscriptions table to store the subscription and payment information in the MySQL database.

CREATE TABLE `user_subscriptions` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL COMMENT 'foreign key of "users" table',
  `plan_id` int(5) DEFAULT NULL COMMENT 'foreign key of "plans" table',
  `paypal_order_id` varchar(255) DEFAULT NULL,
  `paypal_plan_id` varchar(255) DEFAULT NULL,
  `paypal_subscr_id` varchar(100) NOT NULL,
  `valid_from` datetime DEFAULT NULL,
  `valid_to` datetime DEFAULT NULL,
  `paid_amount` float(10,2) NOT NULL,
  `currency_code` varchar(10) NOT NULL,
  `subscriber_id` varchar(100) DEFAULT NULL,
  `subscriber_name` varchar(50) DEFAULT NULL,
  `subscriber_email` varchar(50) DEFAULT NULL,
  `status` varchar(50) DEFAULT NULL,
  `created` datetime DEFAULT NULL,
  `modified` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

PayPal API and Database Configuration (config.php)

In the config.php file, constant variables of the Product, PayPal REST API and database settings are defined.

PayPal REST API Constants:

  • PAYPAL_SANDBOX – (TRUE/FALSE) Set PayPal environment, Sandbox or Live.
  • PAYPAL_SANDBOX_CLIENT_ID – Client ID of PayPal Sandbox REST API App.
  • PAYPAL_SANDBOX_CLIENT_SECRET – Secret key of PayPal Sandbox REST API App.
  • PAYPAL_PROD_CLIENT_ID – Client ID of PayPal Live REST API App.
  • PAYPAL_PROD_CLIENT_SECRET – Secret key of PayPal Live REST API App.
  • CURRENCY – Specify the currency code.

Database Constants:

  • DB_HOST – Specify the database host.
  • DB_USERNAME – Specify the database username.
  • DB_PASSWORD – Specify the database password.
  • DB_NAME – Specify the database name.
<?php 

/* 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');

define('CURRENCY''USD'); 

// Database configuration 
define('DB_HOST''localhost');
define('DB_USERNAME''root');
define('DB_PASSWORD''root');
define('DB_NAME''codexworld_db');


// Start session
if(!session_id()){
    
session_start();


?>

Database Connection (dbConnect.php)

The dbConnect.php file is used to connect the database using PHP and MySQL.

<?php 
// Connect with the database 
$db = new mysqli(DB_HOSTDB_USERNAMEDB_PASSWORDDB_NAME); 
 
// Display error if failed to connect 
if ($db->connect_errno) { 
    
printf("Connect failed: %s\n"$db->connect_error); 
    exit(); 
}

PayPal Subscription Page (index.php)

First, include the configuration file to load the PayPal API variables and connect the database to fetch subscription plans.

  • Fetch the subscription plans from the database.
  • Retrieve the logged-in user ID from the session and set it in the $loggedInUserID variable.
<?php 
// Include configuration file 
require_once 'config.php';

// Include the database connection file
include_once 'dbConnect.php';

// Fetch plans from the database
$sqlQ "SELECT * FROM plans";
$stmt $db->prepare($sqlQ);
$stmt->execute();
$result $stmt->get_result();

// Get logged-in user ID from sesion
// Session name need to be changed as per your system
$loggedInUserID = !empty($_SESSION['userID'])?$_SESSION['userID']:0;
?>

Load the PayPal JavaScript SDK, and set the Client ID and intent=subscription 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?>&vault=true&intent=subscription"></script>

Define the select box dropdown and list all the subscription plans.

  • Define a container element for the PayPal 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">Subscription with PayPal</h3>
        
        <!-- Subscription Plan Info -->
        <div class="form-group">
            <label>Select Subscription Plan:</label>
            <select id="subscr_plan" class="form-control">
                <?php 
                
if($result->num_rows 0){
                    while(
$row $result->fetch_assoc()){
                        
$interval $row['interval'];
                        
$interval_count $row['interval_count'];
                        
$interval_str = ($interval_count 1)?$interval_count.' '.$interval.'s':$interval;
                
?> <option value="<?php echo $row['id']; ?>"><?php echo $row['name'].' [$'.$row['price'].'/'.$interval_str.']'?></option>                 <?php
                    
}
                }
                
?> </select> </div> </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 subscription payment with PayPal JavaScript SDK library:
The paypal.Buttons() method of PayPal JavaScript SDK is used to process the checkout operations.

  • The button container is attached by the element ID (#paypal-button-container) using the render() method.

createSubscription():

  • The selected plan ID is posted to the server-side script (paypal_checkout_init.php) to create a subscription plan using PayPal REST API.
  • Initiate actions.subscription.create() method and pass plan_id to create subscription on PayPal.

onApprove():

  • The subscriptionID is sent to the server-side script (paypal_checkout_init.php) via HTTP request.
  • If the subscription and payment are verified successfully, redirect the user to the subscription status page.

The encodeFormData(), setProcessing(), and resultMessage() are the helper functions used in the checkout process.

<script>
paypal.Buttons({
    createSubscription: async (data, actions) => {
        setProcessing(true);

        // Get the selected plan ID
        let subscr_plan_id = document.getElementById("subscr_plan").value;
        
        // Send request to the backend server to create subscription plan via PayPal API
        let postData = {request_type: 'create_plan', plan_id: subscr_plan_id};
        const PLAN_ID = await 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;
            }
        });

        // Creates the subscription
        return actions.subscription.create({
            'plan_id': PLAN_ID,
            'custom_id': '<?php echo $loggedInUserID; ?>'
        });
    },
    onApprove: (data, actions) => {
        setProcessing(true);

        // Send request to the backend server to validate subscription via PayPal API
        var postData = {request_type:'capture_subscr', order_id:data.orderID, subscription_id:data.subscriptionID, plan_id: document.getElementById("subscr_plan").value};
        fetch('paypal_checkout_init.php', {
            method: 'POST',
            headers: {'Accept': 'application/json'},
            body: encodeFormData(postData)
        })
        .then((response) => response.json())
        .then((result) => {
            if(result.status == 1){
                // Redirect the user to the status page
                window.location.href = "payment-status.php?checkout_ref_id="+result.ref_id;
            }else{
                resultMessage(result.msg);
            }
            setProcessing(false);
        })
        .catch(error => console.log(error));
    }
}).render('#paypal-button-container');

// Helper function to encode payload parameters
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>

PayPal REST API Handler Library (PaypalCheckout.class.php)

We will create a custom library to handle PayPal REST API execution with PHP. This PaypalCheckout library helps to generate Access Token, create plans, and retrieve subscription details with PayPal REST API using PHP. The cURL method is used to call the PayPal Subscription APIs in PHP.

  • generateAccessToken(): Fetch the access token from PayPal OAuth 2 API.
  • createPlan(): Initialize cURL request to create a product with Catalog Products API and plan with Billing API using PayPal REST API v2.
  • getSubscription(): Initialize cURL request to retrieve subscription details with PayPal Billing REST API v2 using PHP.
<?php  
/** 
 * 
 * This PayPal Checkout API handler class is a custom PHP library to handle the PayPal REST API requests. 
 * 
 * @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 
$paypalProductAPI PAYPAL_SANDBOX?'https://api-m.sandbox.paypal.com/v1/catalogs/products':'https://api-m.paypal.com/v1/catalogs/products';
    public 
$paypalBillingAPI PAYPAL_SANDBOX?'https://api-m.sandbox.paypal.com/v1/billing':'https://api-m.paypal.com/v1/billing';
    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($chCURLOPT_URL$this->paypalAuthAPI);  
        
curl_setopt($chCURLOPT_HEADERfalse);  
        
curl_setopt($chCURLOPT_SSL_VERIFYPEERfalse);  
        
curl_setopt($chCURLOPT_POSTtrue);  
        
curl_setopt($chCURLOPT_RETURNTRANSFERtrue);  
        
curl_setopt($chCURLOPT_USERPWD$this->paypalClientID.":".$this->paypalSecret);  
        
curl_setopt($chCURLOPT_POSTFIELDS"grant_type=client_credentials");  
        
$auth_response json_decode(curl_exec($ch)); 
        
$http_code curl_getinfo($chCURLINFO_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 
createPlan($planInfo){ 
        
$accessToken $this->generateAccessToken(); 
        if(empty(
$accessToken)){ 
            return 
false;  
        }else{ 
            
$postParams = array(
                
"name" => $planInfo['name'],
                
"type" => "DIGITAL",
                
"category" => "SOFTWARE"
            
); 
 
            
$ch curl_init(); 
            
curl_setopt($chCURLOPT_URL$this->paypalProductAPI); 
            
curl_setopt($chCURLOPT_RETURNTRANSFER1); 
            
curl_setopt($chCURLOPT_SSL_VERIFYPEERFALSE);  
            
curl_setopt($chCURLOPT_HTTPHEADER, array('Content-Type: application/json''Authorization: Bearer '$accessToken));  
            
curl_setopt($chCURLOPT_POSTtrue); 
            
curl_setopt($chCURLOPT_POSTFIELDSjson_encode($postParams));
            
$api_resp curl_exec($ch); 
            
$pro_api_data json_decode($api_resp); 
            
$http_code curl_getinfo($chCURLINFO_HTTP_CODE);  
            
curl_close($ch); 
 
            if (
$http_code != 200 && $http_code != 201) {  
                throw new 
Exception('Failed to create Product ('.$http_code.'): '.$api_resp);  
            } 
            
            if(!empty(
$pro_api_data->id)){
                
$postParams = array( 
                    
"product_id" => $pro_api_data->id,
                    
"name" => $planInfo['name'],
                    
"billing_cycles" => array( 
                        array( 
                            
"frequency" => array( 
                                
"interval_unit" => $planInfo['interval'], 
                                
"interval_count" => $planInfo['interval_count'
                            ),
                            
"tenure_type" => "REGULAR",
                            
"sequence" => 1,
                            
"total_cycles" => 999,
                            
"pricing_scheme" => array( 
                                
"fixed_price" => array(                                    
                                    
"value" => $planInfo['price'],
                                    
"currency_code" => CURRENCY
                                
)
                            ),
                        ) 
                    ),
                    
"payment_preferences" => array( 
                        
"auto_bill_outstanding" => true
                    
)
                ); 
     
                
$ch curl_init(); 
                
curl_setopt($chCURLOPT_URL$this->paypalBillingAPI.'/plans'); 
                
curl_setopt($chCURLOPT_RETURNTRANSFER1); 
                
curl_setopt($chCURLOPT_SSL_VERIFYPEERFALSE);  
                
curl_setopt($chCURLOPT_HTTPHEADER, array('Content-Type: application/json''Authorization: Bearer '$accessToken));  
                
curl_setopt($chCURLOPT_POSTtrue); 
                
curl_setopt($chCURLOPT_POSTFIELDSjson_encode($postParams));  
                
$api_resp curl_exec($ch); 
                
$plan_api_data json_decode($api_resptrue); 
                
$http_code curl_getinfo($chCURLINFO_HTTP_CODE);  
                
curl_close($ch); 
     
                if (
$http_code != 200 && $http_code != 201) {  
                    throw new 
Exception('Failed to create Product ('.$http_code.'): '.$api_resp);  
                } 
                
                return !empty(
$plan_api_data)?$plan_api_data:false;
            }else{
                return 
false;
            }
        } 
    }
    
    public function 
getSubscription($subscription_id){
        
$accessToken $this->generateAccessToken(); 
        if(empty(
$accessToken)){ 
            return 
false;  
        }else{ 
            
$ch curl_init();
            
curl_setopt($chCURLOPT_URL$this->paypalBillingAPI.'/subscriptions/'.$subscription_id);
            
curl_setopt($chCURLOPT_RETURNTRANSFER1);
            
curl_setopt($chCURLOPT_SSL_VERIFYPEERFALSE); 
            
curl_setopt($chCURLOPT_HTTPHEADER, array('Content-Type: application/json''Authorization: Bearer '$accessToken)); 
            
curl_setopt($chCURLOPT_CUSTOMREQUEST'GET');
            
$api_data json_decode(curl_exec($ch), true);
            
$http_code curl_getinfo($chCURLINFO_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;
        }
    }
}
?>

Process PayPal Subscription (paypal_checkout_init.php)

This server-side script is accessed by the client-side Fetch API defined in createSubscription() and onApprove() methods in the client-side JavaScript code to process the subscription with PayPal REST API using PHP.

  • Include the PaypalCheckout custom PHP library to handle the PayPal REST API operations.
  • If the create_plan request is submitted:
    • Fetch the DB plan info based on the selected plan reference ID.
    • Create a billing plan on PayPal using the createPlan() function of the PaypalCheckout class.
    • Return subscription plan info to the client side.
  • If the capture_subscr request is submitted:
    • Retrieve the subscription info using the getSubscription() function of the PaypalCheckout class.
    • Verify the subscription and payment status.
    • Insert the subscription data with validity and the next billing date in the database.
    • Return Order ID in base64 encoded format to the client side.
<?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_plan'){ 
    
$plan_id $_POST['plan_id']; 

    
// Fetch plan details from the database 
    
$sqlQ "SELECT `name`,`price`,`interval`,`interval_count` FROM plans WHERE id=?"
    
$stmt $db->prepare($sqlQ); 
    
$stmt->bind_param("i"$plan_id); 
    
$stmt->execute(); 
    
$stmt->bind_result($planName$planPrice$planInterval$intervalCount); 
    
$stmt->fetch(); 

    
$plan_data = array(
        
'name' => $planName
        
'price' => $planPrice
        
'interval' => $planInterval
        
'interval_count' => $intervalCount
    ); 
 
    
// Create plan with PayPal API 
    
try { 
        
$subscr_plan $paypal->createPlan($plan_data); 
    } catch(
Exception $e) {  
        
$api_error $e->getMessage();  
    } 
     
    if(!empty(
$subscr_plan)){ 
        
$response = array( 
            
'status' => 1,  
            
'data' => $subscr_plan 
        
); 
    }else{ 
        
$response['msg'] = $api_error
    } 
}elseif(!empty(
$_POST['request_type']) && $_POST['request_type'] == 'capture_subscr'){ 
    
$order_id $_POST['order_id']; 
    
$subscription_id $_POST['subscription_id'];
    
$db_plan_id $_POST['plan_id']; 
 
    
// Fetch & validate subscription with PayPal API 
    
try { 
        
$subscr_data $paypal->getSubscription($subscription_id); 
    } catch(
Exception $e) {  
        
$api_error $e->getMessage();  
    } 
     
    if(!empty(
$subscr_data)){ 
        
$status $subscr_data['status']; 
        
$subscr_id $subscr_data['id']; 
        
$plan_id $subscr_data['plan_id']; 
        
$custom_user_id $subscr_data['custom_id'];

        
$create_time $subscr_data['create_time']; 
        
$dt = new DateTime($create_time); 
        
$created $dt->format("Y-m-d H:i:s");
        
        
$start_time $subscr_data['start_time']; 
        
$dt = new DateTime($start_time); 
        
$valid_from $dt->format("Y-m-d H:i:s");

        if(!empty(
$subscr_data['subscriber'])){
            
$subscriber $subscr_data['subscriber'];
            
$subscriber_email $subscriber['email_address'];
            
$subscriber_id $subscriber['payer_id'];
            
$given_name trim($subscriber['name']['given_name']);
            
$surname trim($subscriber['name']['surname']);
            
$subscriber_name trim($given_name.' '.$surname);

            
// Insert user details if not exists in the DB users table 
            
if(empty($custom_user_id)){ 
                
$sqlQ "INSERT INTO users (first_name,last_name,email,created) VALUES (?,?,?,NOW())"
                
$stmt $db->prepare($sqlQ); 
                
$stmt->bind_param("sss"$given_name$surname$subscriber_email); 
                
$insertUser $stmt->execute(); 
                 
                if(
$insertUser){ 
                    
$custom_user_id $stmt->insert_id
                } 
            } 
        }

        if(!empty(
$subscr_data['billing_info'])){
            
$billing_info $subscr_data['billing_info'];

            if(!empty(
$billing_info['outstanding_balance'])){
                
$outstanding_balance_value $billing_info['outstanding_balance']['value'];
                
$outstanding_balance_curreny $billing_info['outstanding_balance']['currency_code'];
            }

            if(!empty(
$billing_info['last_payment'])){
                
$last_payment_amount $billing_info['last_payment']['amount']['value'];
                
$last_payment_curreny $billing_info['last_payment']['amount']['currency_code'];
            }

            
$next_billing_time $billing_info['next_billing_time'];
            
$dt = new DateTime($next_billing_time); 
            
$valid_to $dt->format("Y-m-d H:i:s");
        }
 
        if(!empty(
$subscr_id) && $status == 'ACTIVE'){ 
            
// Check if any subscription data exists with the same ID 
            
$sqlQ "SELECT id FROM user_subscriptions WHERE paypal_order_id = ?"
            
$stmt $db->prepare($sqlQ);  
            
$stmt->bind_param("s"$order_id); 
            
$stmt->execute(); 
            
$stmt->bind_result($row_id); 
            
$stmt->fetch(); 
             
            
$payment_id 0
            if(!empty(
$row_id)){ 
                
$payment_id $row_id;
            }else{ 
                
// Insert subscription data into the database 
                
$sqlQ "INSERT INTO user_subscriptions (user_id,plan_id,paypal_order_id,paypal_plan_id,paypal_subscr_id,valid_from,valid_to,paid_amount,currency_code,subscriber_id,subscriber_name,subscriber_email,status,created,modified) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,NOW())"
                
$stmt $db->prepare($sqlQ); 
                
$stmt->bind_param("iisssssdssssss"$custom_user_id$db_plan_id$order_id$plan_id$subscr_id$valid_from$valid_to$last_payment_amount$last_payment_curreny$subscriber_id$subscriber_name$subscriber_email$status$created); 
                
$insert $stmt->execute(); 
                 
                if(
$insert){ 
                    
$user_subscription_id $stmt->insert_id

                    
// Update subscription ID in users table 
                    
$sqlQ "UPDATE users SET subscription_id=? WHERE id=?"
                    
$stmt $db->prepare($sqlQ); 
                    
$stmt->bind_param("ii"$user_subscription_id$custom_user_id); 
                    
$update $stmt->execute(); 
                } 
            } 
 
            if(!empty(
$user_subscription_id)){ 
                
$ref_id_enc base64_encode($order_id); 
                
$response = array('status' => 1'msg' => 'Subscription created!''ref_id' => $ref_id_enc); 
            } 
        }
    }else{ 
        
$response['msg'] = $api_error
    } 

echo 
json_encode($response); 
?> 

Subscription Status (payment-status.php)

Based on the status return by the subscription API, the subscriber is redirected to this page.

  • Fetch subscription data from the database using PHP and MySQL.
  • Display subscription details (subscription ID, validity, billing date, subscriber name & email, etc.) on the web page.
<?php 
// Include the configuration file 
require_once 'config.php';

// Include the database connection file 
require_once 'dbConnect.php';

$statusMsg '';
$status 'error';

// Check whether the DB reference ID is not empty
if(!empty($_GET['checkout_ref_id'])){
    
$paypal_order_id  base64_decode($_GET['checkout_ref_id']);
    
    
// Fetch subscription data from the database
    
$sqlQ "SELECT S.*, P.name as plan_name, P.price as plan_price, P.interval, P.interval_count FROM user_subscriptions as S LEFT JOIN plans as P ON P.id=S.plan_id WHERE paypal_order_id = ?";
    
$stmt $db->prepare($sqlQ); 
    
$stmt->bind_param("s"$paypal_order_id);
    
$stmt->execute();
    
$result $stmt->get_result();

    if(
$result->num_rows 0){
        
$subscr_data $result->fetch_assoc();
        
        
$status 'success';
        
$statusMsg 'Your Subscription Payment has been Successful!';
    }else{
        
$statusMsg "Subscription has been failed!";
    }
}else{
    
header("Location: index.php");
    exit;
}
?> <?php if(!empty($subscr_data)){ ?> <h1 class="<?php echo $status?>"><?php echo $statusMsg?></h1> <h4>Payment Information</h4> <p><b>Reference Number:</b> #<?php echo $subscr_data['id']; ?></p> <p><b>Subscription ID:</b> <?php echo $subscr_data['paypal_subscr_id']; ?></p> <p><b>TXN ID:</b> <?php echo $subscr_data['paypal_order_id']; ?></p> <p><b>Paid Amount:</b> <?php echo $subscr_data['paid_amount'].' '.$subscr_data['currency_code']; ?></p> <p><b>Status:</b> <?php echo $subscr_data['status']; ?></p> <h4>Subscription Information</h4> <p><b>Plan Name:</b> <?php echo $subscr_data['plan_name']; ?></p> <p><b>Amount:</b> <?php echo $subscr_data['plan_price'].' '.CURRENCY?></p> <p><b>Plan Interval:</b> <?php echo $subscr_data['interval_count'].$subscr_data['interval']; ?></p> <p><b>Period Start:</b> <?php echo $subscr_data['valid_from']; ?></p> <p><b>Period End:</b> <?php echo $subscr_data['valid_to']; ?></p> <h4>Payer Information</h4> <p><b>Name:</b> <?php echo $subscr_data['subscriber_name']; ?></p> <p><b>Email:</b> <?php echo $subscr_data['subscriber_email']; ?></p> <?php }else{ ?> <h1 class="error">Your Subscription failed!</h1> <p class="error"><?php echo $statusMsg?></p> <?php ?>

Make PayPal Subscription Payment Gateway Live

Once the integration is completed and the subscription process is working properly, follow the below steps to make PayPal checkout live.
1. Go to the PayPal Developer Dashboard Stripe account.

  • Switch to the Live environment using the toggle button at the top-right corner.
  • Navigate to the Apps & Credentials section and collect the REST API credentials (Client ID and Secret) for the Live environment.

2. In the config.php file,

  • Set the PAYPAL_SANDBOX to FALSE.
  • Specify the REST API keys (Client ID and Secret key) in PAYPAL_PROD_CLIENT_ID and PAYPAL_PROD_CLIENT_SECRET variables.
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

Conclusion

PayPal Subscription REST API is the easiest option to accept payment online for the membership subscription. It allows you to handle the subscription payment recurringly via PayPal. With this checkout system, you can create subscriptions on PayPal to bill customers recurringly at specific intervals. Our example code will help you to integrate subscription payment system with PayPal and PHP.

Do you want to get implementation help, or enhance the functionality of this script? Click here to Submit Service Request

3 Comments

  1. Marvin Said...
  2. Ruhul Amin Said...
  3. Nir Tzin Said...
keyboard_double_arrow_up