Simplifying PayPal Subscriptions with Laravel: A Practical Guide
PayPal subscriptions are a popular choice for businesses to manage recurring payments efficiently. In this article, we will explore how to integrate PayPal subscriptions into a Laravel application. By following the steps outlined here, you’ll be able to create, cancel, pause, resume, and update PayPal subscriptions seamlessly.
Prerequisites:
To implement PayPal subscriptions in your Laravel application, ensure that you have the following prerequisites:
- A Laravel project set up and running.
- Sufficient knowledge of Laravel’s basic concepts and syntax.
- Familiarity with PayPal’s subscription services.
- Create a PayPal Business account.
- Create subscription plans using the PayPal developer dashboard.
- Set PayPal Plan id in the Plans table column.
Step 1: Install Required Packages:
To begin, open your Laravel project in a terminal or command prompt and run the following command:
For Laravel 5.1 to 5.8
composer require srmklive/paypal:~2.0
For Laravel 6, 7, & 8 and onwards
composer require srmklive/paypal:~3.0
This command will install the “srmklive/paypal” package, which provides the necessary functionality to integrate PayPal subscriptions into your Laravel application.
Step 2: Publish Assets
After installation, you can use the following commands to publish the assets:
php artisan vendor:publish --provider "Srmklive\PayPal\Providers\PayPalServiceProvider"
Step 3: Configuration
After publishing the assets, add the following to your .env file.
#PayPal API Mode
# Values: sandbox or live (Default: live)
PAYPAL_MODE=
#PayPal Setting & API Credentials - sandbox
PAYPAL_SANDBOX_CLIENT_ID=
PAYPAL_SANDBOX_CLIENT_SECRET=
#PayPal Setting & API Credentials - live
PAYPAL_LIVE_CLIENT_ID=
PAYPAL_LIVE_CLIENT_SECRET=
Step 4: Configuration File
The configuration file paypal.php is located in the config folder. Following are its contents when published:
return [
'mode' => env('PAYPAL_MODE', 'sandbox'), // Can only be 'sandbox' Or 'live'. If empty or invalid, 'live' will be used.
'sandbox' => [
'client_id' => env('PAYPAL_SANDBOX_CLIENT_ID', ''),
'client_secret' => env('PAYPAL_SANDBOX_CLIENT_SECRET', ''),
'app_id' => 'APP-80W284485P519543T',
],
'live' => [
'client_id' => env('PAYPAL_LIVE_CLIENT_ID', ''),
'client_secret' => env('PAYPAL_LIVE_CLIENT_SECRET', ''),
'app_id' => '',
],
'payment_action' => env('PAYPAL_PAYMENT_ACTION', 'Sale'), // Can only be 'Sale', 'Authorization' or 'Order'
'currency' => env('PAYPAL_CURRENCY', 'USD'),
'notify_url' => env('PAYPAL_NOTIFY_URL', ''), // Change this accordingly for your application.
'locale' => env('PAYPAL_LOCALE', 'en_US'), // force gateway language i.e. it_IT, es_ES, en_US ... (for express checkout only)
'validate_ssl' => env('PAYPAL_VALIDATE_SSL', true), // Validate SSL when creating api client.
];
Step 4: Create PayPal Subscriptions Class
In your Laravel project, create a new PHP file called “PayPalSubscriptions.php” inside the “app/Subscriptions/PayPalSubscriptions” directory.
This class will contain all the necessary code to create, cancel, pause, resume, and update PayPal subscriptions.
Constructor:
Import PayPal class namespace first before using it. Initialize PayPal Client so that we can use all the necessary functions for our app subscriptions to work properly.
<?php
namespace App\Subscriptions\PayPalSubscriptions;
use Exception;
use Illuminate\Support\Facades\Log;
use Srmklive\PayPal\Services\PayPal as PayPalClient;
class PayPalSubscriptions
{
protected $provider;
public function __construct()
{
$this->provider = new PayPalClient;
$this->provider->setApiCredentials(config('paypal'));
}
// Methods for creating, canceling, pausing, resuming, and updating subscriptions
// will be implemented here
}
Create Subscriptions Interface:
In the same directory as the “PayPalSubscriptions.php” file, create a new PHP file called “Subscriptions.php”. This file will define an interface for the subscription functionality. It is important if you want to have multiple payment gateways implemented in your app. For example Stripe etc.
You can skip this step if you want to have only PayPal implemented.
Copy and paste the following code into the file:
<?php
namespace App\Subscriptions;
interface Subscriptions
{
public function create(int $plan_id, int $coupon_user_id, string $method, float $amount = 0);
public function cancel(string $subscription_id = null);
public function pause();
public function resume();
}
Implement Subscriptions Interface:
Inside the “PayPalSubscriptions.php” file, update the class declaration to implement the Subscriptions
interface:
class PayPalSubscriptions implements Subscriptions
{
// Existing code here (e.g: constructor code)
// Implement the methods defined in the Subscriptions interface
public function create(int $plan_id, int $coupon_user_id, string $method, float $amount = 0)
{
// Implementation goes here
}
public function cancel(string $subscription_id = null)
{
// Implementation goes here
}
public function pause()
{
// Implementation goes here
}
public function resume()
{
// Implementation goes here
}
}
Implement Subscription Methods:
- Create Subscription:
https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_create
To create a subscription, you need to provide the following parameters to the create
method:
$plan_id
: The ID of the selected plan$coupon_user_id
: The ID of the coupon user (set to 0 if no coupon is used)$method
: The payment method used (e.g., 'paypal')$amount
: The amount (if applicable)
The method retrieves the plan details, prepares the necessary data, and sends the request to create the subscription. If the subscription creation is successful, it redirects the user to the PayPal approval URL. Otherwise, it redirects them to the home page with an error message.
Make sure to replace the placeholder values with your actual code and customize it according to your specific implementation.
public function create(int $plan_id, int $coupon_user_id, string $method, float $amount = 0)
{
// Set up the shipping address
$address = [
"address_line_1" => "2211 N First Street",
"address_line_2" => "Building 17",
"admin_area_2" => "San Jose",
"admin_area_1" => "CA",
"postal_code" => "95131",
"country_code" => "US",
];
// Retrieve the PayPal plan ID from the selected plan
$paypalPlanId = Plan::where('id', $plan_id)->first()->paypal_plan_id;
// Prepare the data for subscription creation
// example data
$data = [
'plan_id' => $paypalPlanId,
'quantity' => '1',
'shipping_amount' => [
'currency_code' => 'EUR',
'value' => 0.00,
],
'subscriber' => [
'name' => [
'given_name' => auth()->user()->name,
'surname' => '',
],
'email_address' => auth()->user()->email,
'shipping_address' => [
'name' => [
'full_name' => auth()->user()->id . '-' . $coupon_user_id,
],
'address' => $address,
],
],
'application_context' => [
'brand_name' => env('PAYPAL_PRODUCT_ID'),
'locale' => 'en-US',
'shipping_preference' => 'SET_PROVIDED_ADDRESS',
'user_action' => 'SUBSCRIBE_NOW',
'payment_method' => [
'payer_selected' => 'PAYPAL',
'payee_preferred' => 'IMMEDIATE_PAYMENT_REQUIRED',
],
'return_url' => route('payments.paypal.success', [$plan_id]),
'cancel_url' => route('payments.cancel'),
],
];
// Include additional data for subscription with a coupon
if ($coupon_user_id != 0) {
$data['plan'] = [
'billing_cycles' => [
[
'sequence' => 1,
'total_cycles' => 1,
'pricing_scheme' => [
'fixed_price' => [
'value' => $amount, // discounted amount
'currency_code' => 'EUR',
],
],
],
],
];
}
// Send the request to create the subscription
$response = $this->provider->createSubscription($data);
if (isset($response['id']) && $response['id'] != null) {
// Redirect to PayPal approval URL
foreach ($response['links'] as $link) {
if ($link['rel'] == 'approve') {
return redirect()->away($link['href']);
}
}
return redirect()
->route('home')
->with('error', 'Something went wrong.');
} else {
return redirect()
->route('home')
->with('error', $response['message'] ?? 'Something went wrong.');
}
}
Note that in following snippet above:
'shipping_address' => [
'name' => [
'full_name' => auth()->user()->id . '-' . $coupon_user_id,
],
We did that because, PayPal Webhook doesn’t return back metadata, which is important to get back important data, from which we extract useful data like user_id, coupon_id etc. So, I found this method to work properly.
2. Cancelling a PayPal Subscription:
https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_cancel
The cancel
method allows you to cancel a subscription in the PayPalSubscriptions system. It takes an optional parameter $subscription_id
, which specifies the ID of the subscription to cancel. If the $subscription_id
is not provided, the method cancels the subscription associated with the authenticated user.
Here’s the code for the cancel
method:
public function cancel(string $subscription_id = null)
{
if (is_null($subscription_id)) {
$subscription = Subscription::where('user_id', auth()->user()->id)->first();
$reason = 'no longer using';
} else {
$subscription = Subscription::where('subscription_id', $subscription_id)->first();
$reason = 'new subscription';
}
$subscriptionId = $subscription->subscription_id;
try {
$response = $this->provider->cancelSubscription($subscriptionId, $reason);
return true;
} catch (Exception $e) {
$error = "Something went wrong." . $e->getMessage();
return false;
}
}
To cancel a subscription, simply call the cancel
method. If you provide the $subscription_id
parameter, it will cancel the specified subscription. Otherwise, it will cancel the subscription associated with the authenticated user.
If the cancellation is successful, the method will return true
. Otherwise, it will return false
and an error message will be logged.
Make sure to replace the placeholder values with your actual code and customize it according to your specific implementation.
3. Pausing the Subscription:
https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_suspend
The pause
method allows you to pause a subscription in the PayPalSubscriptions system. It temporarily suspends the recurring billing for the subscription. When a subscription is paused, the user will not be charged until it is resumed.
Here’s the code for the pause
method:
public function pause()
{
$subscription = Subscription::where('user_id', auth()->user()->id)->first();
$subscriptionId = $subscription->subscription_id;
try {
$response = $this->provider->suspendSubscription($subscriptionId, 'Subscription Paused');
return true;
} catch (Exception $e) {
$error = "Something went wrong." . $e->getMessage();
return false;
}
}
To pause a subscription, simply call the pause
method. It retrieves the subscription associated with the authenticated user and suspends it using the PayPal API. If the suspension is successful, the method will return true
. Otherwise, it will return false
and an error message will be logged.
Make sure to replace the placeholder values with your actual code and customize it according to your specific implementation.
4. Resuming the Subscription:
https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_activate
The resume
method allows you to resume a paused subscription in the PayPalSubscriptions system. When a subscription is resumed, the recurring billing is reactivated, and the user will be charged according to the original billing cycle.
Here’s the code for the resume
method:
public function resume()
{
$subscription = Subscription::where('user_id', auth()->user()->id)->first();
$subscriptionId = $subscription->subscription_id;
try {
$response = $this->provider->activateSubscription($subscriptionId, 'Reactivating the subscription');
return true;
} catch (Exception $e) {
$error = "Something went wrong." . $e->getMessage();
return false;
}
}
To resume a subscription, simply call the resume
method. It retrieves the subscription associated with the authenticated user and activates it using the PayPal API. If the reactivation is successful, the method will return true
. Otherwise, it will return false
and an error message will be logged.
Conclusion:
Congratulations! You have successfully set up the foundation for implementing PayPal subscriptions in your Laravel application. The provided code gives you a starting point to work with PayPal subscriptions, and you can now proceed to implement the logic for each subscription-related method based on your application’s requirements. Remember to test thoroughly before deploying to a production environment.
You can use this in a running as well as new project. As you progress, explore the PayPal SrmkLive developer documentation and additional resources to enhance your knowledge and customize the implementation further.
For PayPal Webhooks, please see my Handling PayPal Subscription Webhooks in Laravel post.