Paypal Checkout V2 Sample (Server-Side) – Integrate Paypal with Your Custom PHP App

Cinthia Fraire

Getting Started with Paypal Checkout V2 (Server-Side)

If you have landed on this article, you’re most likely having trouble with PayPal Checkout integration. No worries, this article has been created just for you. We’ve created a step-by-step guide so you can start creating dynamic orders using PayPal Checkout. This is specifically a Paypal Checkout V2 Sample that’ll be supported with code examples and notes, helping you to implement this feature in full by the end of this tutorial.

First things first, we need to create a PayPal developers account to obtain a client ID and secret key for your app. Once you are logged in, create a new app under My Apps & Credentials. You will automatically get directed to a page that will provide these keys. Let’s set these aside, we’ll need those later.

Now let’s begin the PayPal Checkout integration by installing the PayPal Javascript SDK. You can find more info here.

Composer require paypal/paypal-checkout-sdk

After installing the sdk we need to make it available to our app and configure credentials. In your .env, create two new variables CLIENT_ID and CLIENT_SECRET. Copy and paste the client ID and secret key we saved earlier.

Now, to make the SDK available to our app we called PayPalClient or any name you like.

namespace App\Service;
use PayPalCheckoutSdk\Core\PayPalHttpClient;
use PayPalCheckoutSdk\Core\SandboxEnvironment;

ini_set('error_reporting', E_ALL); // or error_reporting(E_ALL);
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');

class PayPalClient
    * Returns PayPal HTTP client instance with environment that has access
    * credentials context. Use this instance to invoke PayPal APIs, provided the 
    * credentials have access.
   public static function client()
       return new PayPalHttpClient(self::environment());
    *Set up and return PayPal PHP SDK environment with PayPal access credentials. 
    *This sample uses SandboxEnvironment. In production, use LiveEnvironment.
   public static function environment()
       $clientId = getenv("CLIENT_ID") ?: "PAYPAL-SANDBOX-CLIENT-ID";
       $clientSecret = getenv("CLIENT_SECRET") ?: "PAYPAL-SANDBOX-CLIENT-SECRET";
       return new SandboxEnvironment($clientId, $clientSecret);

The most important part here is to make sure we are passing in the CLIENT_ID and CLIENT_SECRET env variables to this service.

The next step is to create another service called CreateOrder. This service will generate our orders.

<?php namespace Sample\CaptureIntentExamples; require __DIR__ . '/vendor/autoload.php'; //1. Import the PayPal SDK client that was created in `Set up Server-Side SDK`. use Sample\PayPalClient; use PayPalCheckoutSdk\Orders\OrdersCreateRequest; class CreateOrder { // 2. Set up your server to receive a call from the client /** *This is the sample function to create an order. It uses the *JSON body returned by buildRequestBody() to create an order. */ public static function createOrder($debug=false, $transcationAmount, $description) { $request = new OrdersCreateRequest(); $request->prefer('return=representation'); $request->body = self::buildRequestBody($transactionAmount, $description); // 3. Call PayPal to set up a transaction $client = PayPalClient::client(); $response = $client->execute($request); if ($debug) { print "Status Code: {$response->statusCode}\n"; print "Status: {$response->result->status}\n"; print "Order ID: {$response->result->id}\n"; print "Intent: {$response->result->intent}\n"; print "Links:\n"; foreach($response->result->links as $link) { print "\t{$link->rel}: {$link->href}\tCall Type: {$link->method}\n"; } // To print the whole response body, uncomment the following line // echo json_encode($response->result, JSON_PRETTY_PRINT); } // 4. Return a successful response to the client. return $response; } /** * Setting up the JSON request body for creating the order with minimum request body. The intent in the * request body should be "AUTHORIZE" for authorize intent flow. * */ private static function buildRequestBody($transactionAmount, $description) { return array( 'intent' => 'CAPTURE', 'application_context' => array( 'return_url' => '', 'cancel_url' => '' ), 'purchase_units' => array( 0 => array( ‘description’ => $description, 'amount' => array( 'currency_code' => 'USD', 'value' => $transactionAmount ) ) ) ); } } /** *This is the driver function that invokes the createOrder function to create *a sample order. */ if (!count(debug_backtrace())) { CreateOrder::createOrder(true); } ?>

Notice we have two parameters in our createOrder method, $transactionAmount and $description. The value to these parameters will be generated dynamically in our app. The values are passed down to our buildRequestBody method that will be generating our purchase units.

Next we create a new controller that will handle our transactions. Within this controller we’ll create a route that will handle creating our new orders.

/** * @Route("/api/create-order", name="api_create_order") */ public function apiCreateOrder(CreateOrderService $createOrderService, Request $request) { $user = $this->getUser(); $transaction = $this->transactionRepository->findTransaction($user); $transactionAmount = $transaction->getAmount(); $description = $transaction->getDescription(); if($request->isMethod('POST')){ $paypalResponse = $createOrderService->CreateOrder(false, $request, $transactionAmount, $description); return new JsonResponse($paypalResponse->result, $paypalResponse->statusCode); } }

Next, we want to create a route that will handle what happens after the Paypal transaction has been accepted.

/** * @Route("/payment/approved", name="payment_approved") */ public function paymentApproved( Request $request ){ //do something here }

Ok we’re almost at the finish line. So far we’ve set up all of the backend logic, now we just need to set up our front-end checkout flow.

If you are building this feature in a single-page application, here is documentation on how to add the javascript SDK to your checkout page. You’ll find the following example to be similar. You can find more information on this example in Paypal documentation here.


At the top of your checkout page you want to add this script, to add the javascript SDK.

You can customize the integration by passing parameters in the SDK script tag.

<script src=",funding-eligibility"> // Replace YOUR_SB_CLIENT_ID with your client ID </script>

At the bottom of your checkout page we’ll begin to integrate the PayPal Buttons and set up the Javascript SDK for transactions.

We will begin with the PayPal Buttons.

Create a button container and give it an id.

<div id="paypal-button-container" style="width: 200px"></div> <script> paypal.Buttons().render('#paypal-button-container'); </script>

Next, we’ll set up the createOrder function which will be triggered when your user clicks on the PayPal Button. Notice we are fetching our createOrder route we created earlier.

<script> paypal.Buttons({ createOrder: function(data, actions) { return fetch('{{ path('api_create_order' ) }}', { method: 'POST', headers: { 'content-type': 'application/json', } }).then(function (res) { return res.json(); }).then(function (data) { return; }) } }).render('#paypal-button-container'); </script>

We can pass the transaction amount and description to our createOrder route or you can already have the transaction information in your database and pull that information into your createOrder route and your checkout page can

be an order confirmation page. Now we need to implement the OnApprove function that will be triggered when a transaction has been approved by your user. Earlier we created a paymentApproved route that would handle custom logic for our app after a user is done paying.

<script> paypal.Buttons({ createOrder: function(data, actions) { return fetch('{{ path('api_create_order' ) }}', { method: 'POST', headers: { 'content-type': 'application/json', } }).then(function (res) { return res.json(); }).then(function (data) { return; }) }, onApprove: function(data, actions) { return actions.order.capture().then(function(details) { fetch('{{ path('payment_approved') }}', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(details) }).then(function (res) { window.location.href = res.url; }); }) } }).render('#paypal-button-container'); </script>

Note the details variable holds a lot of helpful information like transaction status, payer information, shipping information etc.

We are done. You should now have the PayPal Checkout feature fully integrated. Below there is a list of references that may be useful for customizing this feature to your specific need. We hope this guide has been helpful to you, enjoy!


- Cinthia FraireDeveloper | 

Filed under: <BlogE-commerceWeb Development>

Don't Know if Paypal is the Right Payment Gateway for Your Store?

Contact Us