PayPal Payouts API Integration in PHP

PayPal Payouts allows developers to send payments to multiple recipients at the same time from a web application. This post will demonstrate how to use PayPal Payout API to send out payments in bulk in PHP.

Paypal Payouts API Integration in PHP

With PayPal payout it is possible to send payments to multiple recipients as a batch. There are three types of payouts PayPal provides.

  1. Large Batch Payout: Create a payouts file and upload it to secure FTP server. Number of recipients is unlimited.
  2. API Integration: Programmatically send payout using PayPal payout API. Number of recipients is up to 15000 per request.
  3. Payouts Web: Create a payouts file and upload it using Payouts Web. Number of recipients is 5000 per file.

Before we begin with our integration we need confirm we have the following in place. The prerequisites list include:

  • A PayPal account.
  • PayPal App Credentials i.e. Client ID and Client Secret.
  • Sufficient funds PayPal account.
  • Payout feature must be enabled in PayPal.
 

How to Integrate PayPal Payouts in PHP

This post demonstrates how to integrate PayPal payout in PHP to send bulk payments. We will show only an example request of payout. Steps to send request to PayPal payout API

  • Create PayPal sandbox account.
  • Get OAuth 2.0 client ID and client secret of this sandbox account.
  • Create a PHP class to handle PayPal API requests.
  • Create an example request and send payouts with PayPal.

We are going to create following files:

  • constants.php: Contains PayPal constants.
  • paypal-sdk/paypal_client.php: A PHP class to send requests to PayPal endpoints.
  • index.php: HTML page containing the cart items and PayPal checkout button

Before we send any kind of resource request to PayPal we need an access token to authenticate our request. We will be sending two requests one to get an access token and other to send payouts so we will first write a function that can be used in both requests. To get an access token we need our client ID and Client Secret.

 

Step 1: Create a PayPal Sandbox Account and Get Client Credentials

First we setup a sandbox account and create an App. After our app is created we get our client ID and client secret. Next under "SANDBOX APP SETTINGS" enable payouts options to allow our app to send requests to PayPal Payouts API.

We have divided the PayPal payouts integration into three basic steps:

  1. A function to send CURL requests.
  2. A request to get access token.
  3. Final request to send payouts.
 

Step 2: Add PayPal Configuration Constants

Just like in PayPal Checkout with Payment Buttons in PHP we need to add configuration constants for PayPal environment, client ID and client secret.

constants.php

<?php
define('PAYPAL_ENVIRONMENT', 'sandbox');
define('PAYPAL_CLIENT_ID', 'PAYPAL_CLIENT_ID');
define('PAYPAL_CLIENT_SECRET', 'PAYPAL_CLIENT_SECRET');

Step 3: Create PayPal Client Class in PHP to Handle PayPal API Requests

A custom PHP class which will be responsible to handle requests to PayPal API endpoints. Class has the following properties in use:

  • $base_url: Holds the endpoint URL for sandbox or production.
  • $client_id: Client id created in previous steps.
  • $client_secret: Client secret created in previous steps.
  • $access_token: Access token for PayPal requests authorization.
  • $token_type: The type of token i.e "Bearer".
  • $expires_in: The expire time of current access token. Used to refresh/regenerate the token when expired.
  • $created_at: The creation time of current access token. Used to refresh/regenerate the token when expired.
The methods used in paypal_client class:
  • __construct(): Constructor of class when and instance of class is created. Sets $client_id, $client_secret, $base_url and $access_token properties of the class.
  • set_access_token(): Sends the request to PayPal's authorization endpoint to retrieve access token for future requests. Sets $access_token, $token_type, $expires_in and $created_at properties of class.
  • curl_request(): A generic function used to send curl requests to PayPal endpoints.

paypal_client.php

<?php

class paypal_client
{
public string $base_url;

private string $client_id;

private string $client_secret;

private ?string $access_token;

private string $token_type;

private int $expires_in;

private int $created_at;

public function __construct($client_id, $client_secret, $sandbox = false)
{
$this->client_id = $client_id;

$this->client_secret = $client_secret;

$this->base_url = $sandbox
? 'https://api-m.sandbox.paypal.com'
: 'https://api-m.paypal.com';

$this->access_token = null;
}


/**
* @throws Exception
*/
public function set_access_token(): stdClass|array
{
$headers = [
'content-type' => 'application/x-www-form-urlencoded'
];

$curl_options = [
CURLOPT_USERPWD => $this->client_id . ':' . $this->client_secret
];

$body = [
'grant_type' => 'client_credentials'
];

$response = $this->curl_request('/v1/oauth2/token', 'POST', $headers, http_build_query($body), $curl_options);

$response = json_decode($response);

$this->access_token = $response->access_token;

$this->token_type = $response->token_type;

$this->expires_in = $response->expires_in;

$this->created_at = time();

return $response;
}


/**
* @param string $path
* @param string $method
* @param array $headers
* @param array|string $body
* @param array $curl_options
* @return bool|string
* @throws Exception
*/
public function curl_request(string $path, string $method, array $headers = [], array|string $body = [], array $curl_options = []): bool|string
{
$curl = curl_init();

array_change_key_case($headers);

$headers = array_merge(['accept' => 'application/json'], $headers);

curl_setopt($curl, CURLOPT_URL, $this->base_url . $path);
curl_setopt($curl, CURLOPT_TIMEOUT, 0);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

if (str_starts_with($this->base_url, 'https://')) {
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
}

if (!array_key_exists('authorization', $headers) && !str_ends_with($path, 'v1/oauth2/token')) {
if (is_null($this->access_token) || time() > ($this->created_at + $this->expires_in)) {
$this->set_access_token();
}

$headers['authorization'] = sprintf('%s %s', $this->token_type, $this->access_token);
}

// If any headers set add them to curl request
if (!empty($headers)) {
curl_setopt($curl, CURLOPT_HTTPHEADER, array_map(function ($key, $value) {
return $key . ': ' . $value;
}, array_keys($headers), array_values($headers)));
}

// Set the request type , GET, POST, PUT or DELETE
switch (strtoupper($method)) {
case 'POST':
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST');
break;
case 'PUT':
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT');
break;
case 'DELETE':
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
break;
default:
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'GET');
break;
}

// If any data is supposed to be sent along with request add it to curl request
if (!empty($body)) {
curl_setopt($curl, CURLOPT_POSTFIELDS, $body);
}

// Any extra curl options to add in curl object
if (!empty($curl_options)) {
foreach ($curl_options as $option_key => $option_value) {
curl_setopt($curl, $option_key, $option_value);
}
}

$response = curl_exec($curl);

$error = curl_error($curl);

$error_code = curl_errno($curl);

$status_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);

if ($error_code > 0) {
throw new Exception($error, $error_code);
}

if ($status_code < 200 || $status_code >= 300) {
throw new Exception($response, $status_code);
}

curl_close($curl);

return $response;
}
}

Step 4: Send PayPal Payout Request in PHP

Finally after every step followed we are ready to send PayPal payout request in PHP using the Payout API. Prepare an array of receivers with required data and send request to PayPal API endpoint to initiate a bulk payout.

Payouts Request

<?php
// Headers for our token request
$headers['accept'] = 'application/json';
$headers['content-type'] = 'application/json';

$request_body = [];
$items = [];

$time = time();

// Prepare sender batch header
$sender_batch_header['sender_batch_id'] = $time;
$sender_batch_header['email_subject'] = 'Payout Received';
$sender_batch_header['email_message'] = 'You have received a payout, Thank you for using our services';

// First receiver
$receiver['recipient_type'] = 'EMAIL';
$receiver['note'] = 'Thank you for your services';
$receiver['sender_item_id'] = $time++;
$receiver['receiver'] = '[email protected]';
$receiver['amount']['value'] = 10.00;
$receiver['amount']['currency'] = 'USD';

$items[] = $receiver;

// Second receiver
$receiver['recipient_type'] = "EMAIL";
$receiver['note'] = 'You received a payout for your services';
$receiver['sender_item_id'] = $time++;
$receiver['receiver'] = '[email protected]';
$receiver['amount']['value'] = 15.00;
$receiver['amount']['currency'] = 'USD';

$items[] = $receiver;

$request_body['sender_batch_header'] = $sender_batch_header;
$request_body['items'] = $items;

$paypal_client = new paypal_client(PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, PAYPAL_ENVIRONMENT === 'sandbox');

$response = $paypal_client->curl_request('/v1/payments/payouts', 'POST', $headers, json_encode($request_body));


We just demonstrated how use the PayPal Payout API in PHP to create payout batch request and send payouts programmatically. For demo purpose we used static array of receivers, Which can of course be modified to a receivers list from database table or a file. PayPal prevents duplicate payouts if sender_batch_id has already been used in past 30 days, PayPal will reject the payout request and return an error. Below is the successful payout response.

{
  "batch_header": {
    "sender_batch_header": {
      "sender_batch_id": "2014021801",
      "email_subject": "You have a payout!"
    },
    "payout_batch_id": "12345678",
    "batch_status": "PENDING"
  }
}