Laravel Cashier (Paddle): React Implementation Not Storing Transactions & Subscriptions

Updated: Mar 03, 2025

Laravel Cashier (Paddle): React Implementation Not Storing Transactions & Subscriptions

I. Introduction

Laravel Cashier is a billing and subscription management solution built on top of Laravel, a popular PHP web application framework. Cashier integrates with various payment gateways, including Paddle, to handle recurring billing and manage subscriptions. In this response, we will discuss how to implement Laravel Cashier with Paddle in a React application and address the issue of missing transactions and subscriptions.

II. Setting up Laravel Cashier with Paddle

To set up Laravel Cashier with Paddle, follow these steps:

  1. Install Laravel and Cashier: Ensure you have Laravel installed on your server. After that, install Cashier using Composer:
composer require laravel/cashier
  1. Configure Cashier: Update your .env file with your Stripe or Mollie credentials if you're using Stripe or Mollie as your payment gateway. For Paddle, you don't need to provide any credentials since Cashier doesn't support Paddle directly. Instead, you'll use Paddle's webhooks to sync transactions and subscriptions with Laravel.

  2. Install Laravel Sanctum: Laravel Sanctum is an authentication system that will help secure your application's routes. Install it using Composer:

composer require laravel/sanctum
  1. Configure Laravel Sanctum: Update your .env file with the following settings:
SANCTUM_STATEFUL_DOMAINS=localhost:3000,your-app-domain.com
  1. Set up Paddle: Create an account on Paddle (https://paddle.com/) and create a new product. Make sure to note down the product ID.

  2. Create a route in Laravel: Create a new route in Laravel to handle Paddle's webhooks. This route will be responsible for receiving webhook events and storing them in your database.

// routes/web.php
Route::post('/paddle/webhook', 'App\Http\Controllers\WebhookController@handlePaddleWebhook')->name('paddle.webhook');
  1. Create a controller: Create a new controller named WebhookController and implement the handlePaddleWebhook method:
// app/Http/Controllers/WebhookController.php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class WebhookController extends Controller
{
    public function handlePaddleWebhook(Request $request)
    {
        // Validate the signature
        $paddleSignature = $request->header('X-Paddle-Signature');
        $webhookSecret = env('PADDLE_WEBHOOK_SECRET');

        if (!hash_equals(sha1($request->getContent()), $paddleSignature)) {
            abort(401);
        }

        // Process the webhook event
        $event = json_decode($request->getContent());

        // Store the event in your database
        // ...

        return response()->json(['status' => 'success']);
    }
}

Make sure to set the PADDLE_WEBHOOK_SECRET environment variable with your Paddle webhook secret.

  1. Set up Laravel Cashier with Paddle: Since Laravel Cashier doesn't support Paddle directly, you'll need to use a package like laravel-cashier-paddle to interact with Paddle's API. Install the package using Composer:
composer require spatie/laravel-cashier-paddle
  1. Configure the package: Update your .env file with your Paddle API key:
PADDLE_API_KEY=your_paddle_api_key
  1. Register the service provider: Register the Spatie\Cashier\CashierServiceProvider in your app/Providers/AppServiceProvider.php file:
// app/Providers/AppServiceProvider.php
namespace App\Providers;

use Spatie\Cashier\CashierServiceProvider;

class AppServiceProvider extends CashierServiceProvider
{
    // ...
}
  1. Create a User model: Laravel Cashier requires a User model to manage subscriptions and transactions. Make sure you have a User model in your Laravel application.

  2. Set up the User model: Update the User model to use Laravel Cashier:

// app/Models/User.php
namespace App\Models;

use Laravel\Cashier\Billable;
use Spatie\Cashier\Contracts\Billable as CashierBillable;

class User implements CashierBillable
{
    use Billable;

    // ...
}

III. Implementing Paddle in React

To implement Paddle in a React application, you can use the react-paddle-checkout package. Follow these steps:

  1. Install the package: Install the react-paddle-checkout package using npm or yarn:
npm install react-paddle-checkout

or

yarn add react-paddle-checkout
  1. Import the package: Import the Checkout component from react-paddle-checkout in your React component:
import Checkout from 'react-paddle-checkout';
  1. Set up the Checkout component: Use the Checkout component to create a checkout form:
function CheckoutPage() {
  const productId = 'your_product_id';
  const priceId = 'your_price_id';

  return (
    <Checkout
      productId={productId}
      priceId={priceId}
      onSuccess={(order) => {
        // Handle successful checkout
      }}
      onError={(error) => {
        // Handle checkout error
      }}
    >
      {({ openCheckout }) => (
        <button onClick={openCheckout}>Buy Now</button>
      )}
    </Checkout>
  );
}

Replace your_product_id and your_price_id with your actual product and price IDs from Paddle.

IV. Syncing Transactions and Subscriptions

Since Laravel Cashier doesn't support Paddle directly, you'll need to use Laravel's webhooks to sync transactions and subscriptions between Laravel and Paddle. The webhook controller we created earlier will handle this.

When a user creates a new subscription or makes a payment through Paddle, Paddle will send a webhook event to your Laravel application. The webhook controller we created earlier will receive this event and store it in your database.

You can use Laravel's Eloquent ORM to query your database and fetch the latest transactions and subscriptions for a user.

V. Conclusion

In this response, we discussed how to implement Laravel Cashier with Paddle in a React application and addressed the issue of missing transactions and subscriptions. By following the steps outlined above, you should be able to set up a functional billing and subscription management system using Laravel Cashier, Paddle, and React.