How to Get Paddle PayLinks from a backend API Controller in Laravel

Reece May • November 28, 2020 • 4 min read

laravel api paddle cashier

This is the follow up post to using a renderless component for Paddle paylinks.

Sometimes you may have na application that has a few subscription options, sometimes not.

If you have a few subscription options available and you are displaying them for the user to pick one, there is a request each time to the Paddle API endpoint to generate a payment link, this in turn will reduce the response time for the subscriptions settings page, this sucks.

We will solve this delay by continuing this split of loading the payment links after the initial response.

Creating a Controller to handle the links

So to begin, you need a controller to handle the generation of the links, because this is an API controller basically, you won't need the extra methods of a normal CRUD controller, so we can go with an invokable one.

1php artisan make:controller Api\\SubscriptionLinksListController --invokable

You should have a new controller under App\Http\Controllers\Api. (Please don't feel forced to use the name I have put here, you can use whatever you feel is better.)

Getting the Paddle paylinks from Cashier

Inside our __invoke we are going to place our main logic to check for the user and then create paddle links.

Things we want from this controller are the following:

So with that in mind, lets get the links sorted first off, below is our skeleton of code that we will need:

1use Illuminate\Http\Response;
2use Illuminate\Http\JsonResponse;
3use App\Models\Plan;
4 
5...
6 
7 public function __invoke(Request $request)
8 {
9 /**
10 * This part assumes that the current billable instance is the authorised user.
11 */
12 $billable = $request->user();
13 
14 // Our list of available plans, note the name could be anything here for the plan model.
15 $plans = Plan::whereIsAvailable(true)
16 ->get(['id', 'paddle_id', 'title', 'name', 'is_available']);
17 
18 $subscriptions = $plans->map(function($plan) use($billable){
19 
20 if ($currentSubscription = $billable->subscribedToPlan($plan->name)) {
21 /** For this example you can just giving them the option to cancel the plan*/
22 $payLink = $billable->subscription($plan->name)->cancelUrl();
23 } else {
24 $payLink = $billable->newSubscription($plan->name, $plan->paddle_id)
25 ->returnTo(route('billing'))
26 ->create();
27 }
28 
29 return [
30 'title' => $plan->title,
31 'name' => $plan->name,
32 'paylink' => $paylink,
33 'current' => $currentSubscription,
34 ];
35 });
36 
37 return new JsonResponse([
38 "data" => $subscriptions,
39 ]);
40 }

Lets break down the current parts of this code.

Getting the current billable model

The line of code that reads $billable = $request->user(); is where we get the billable model from cashier, this is the model we will use to compare if they have any active plans currently.

A point to note about this is that the Billable model could be anything, if you get that from a different source, then change that line.

For example

1// if you have an Account model that is billable, then it could look like this.
2$billable = Account::where('user_id', $request->user()->account_id)->firstOrFail();

Fetching the plan names for the Paddle subscriptions

You could manually hard-code the plans into place via config files, this would give you the same option of fetching them with the config file.

This would let you keep the changes in version control, but if you need to change a plan and make a custom one for a customer, you would have to go through a deploy cycle to get it to them.

In this instance, the plan details are fetched from a database table, this gives us the option to even scope the plans to certain people.

The important information to store in the plan table is the following:

Creating the return data from our API

The data that is returned to the frontend code contains only the information that matters for the UI to be rendered, the Paddle Paylink, the name and if it's currently subscribed to.

This makes the data returned light so if they have network issues it isn't a large payload. Making it quicker basically.

The data is returned in the form of a JsonResponse, this wraps the data in the appropriate headers and HTTP response codes.

You could always create a Json Resource class that has the same structure for any subscription data returned from your app, this would allow you to have a consistent pattern of data across your entire app if you are working on a large team. All each person has to do is call new SubscriptionLinkResource($data)

Getting the links from the frontend

To get the data from the front end you can use the component outlined in this post: Using a renderless component for Paddle paylinks.

Or you could create your own version of that.

Either way, you need to make sure to have an entry in your routes file.

Something like Route::get('/billing/subscriptions', SubscriptionLinksListController::class)->middleware('auth:api'); would be enough.

Alternatives

You could use a Resource class in Laravel to contain the structure for each link, then bundle it as a collection handling the fetching of each Paddle link inside the resource class, this would make for a very skinny controller, basically just a fetch of the plans from the DB or from the configuration files, then you can have something like return SubscriptionLinksCollection($data)

I will maybe make an additional version of that later on an link it here.

I hope you enjoyed this, please reach out with feedback or suggestions for improvements. You can find me on twitter @iexistin3d.

Have a great time and keep safe 🙃

Syntax highlighting by Torchlight.