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 the PayPal Payout API to send 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 the secure FTP server. The number of recipients is unlimited.
  2. API Integration: Programmatically send payout using the 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. The number of recipients is 5000 per file.

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

  • A PayPal account.
  • PayPal App Credentials i.e. Client ID and Client Secret.
  • Sufficient funds in the PayPal account.
  • The 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 for payout. Steps to send a request to the PayPal payout API

  • Create a PayPal sandbox account.
  • Get the 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 the following files:

  • constants.php: Contains PayPal constants.
  • paypal-sdk/paypal_client.php: A PHP class to send requests to PayPal endpoints.

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 another 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 set up 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 payout options to allow our app to send requests to the 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 an 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 the 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 a PayPal Client Class in PHP to Handle PayPal API Requests

A custom PHP class will be responsible for handling 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 expiration time of the current access token. Used to refresh/regenerate the token when expired.
  • $created_at: The creation time of the current access token. Used to refresh/regenerate the token when expired.
The methods used in the paypal_client class:
  • __construct(): Constructor of class when an instance of the class is created. Sets the $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 the access token for future requests. Sets the $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 is followed, we are ready to send a PayPal payout request in PHP using the Payout API. Prepare an array of receivers with the required data and send a request to the 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 to use the PayPal Payout API in PHP to create payout batch requests and send payouts programmatically. For demo purposes, we used a static array of receivers, which can of course, be modified to a list of receivers from a database table or a file. PayPal prevents duplicate payouts if sender_batch_id has already been used in the 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"
  }
}