Laravel Cashier (Paddle): Not Storing Transactions & Subscriptions

Updated: Mar 03, 2025

Laravel Cashier (Paddle): Not Storing Transactions & Subscriptions

Question: I'm using Laravel Cashier with Paddle as my payment gateway. However, I've noticed that my transactions and subscriptions are not being stored in my Laravel database. How can I fix this issue?

Answer: To store transactions and subscriptions in Laravel when using Cashier with Paddle, you need to configure Cashier to use Paddle's webhooks for event handling. Here's a step-by-step guide to help you set it up:

  1. Set up your Paddle webhook secret key:

    • Log in to your Paddle account and go to the "Webhooks" tab in the dashboard.
    • Click on "Create New Webhook" and provide a name for it (e.g., Laravel).
    • Generate a new secret key and copy it.
  2. Configure Laravel Cashier:

    • In your .env file, set the CASHIER_WEBHOOK_SECRET environment variable to the webhook secret key you generated in step 1.
  3. Create a new Cashier event listener:

    • Use the following command to generate a new event listener: php artisan make:listener CashierWebhookEvent.
    • Open the newly created file (located in app/Listeners) and update its contents as follows:
namespace App\Listeners;

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Laravel\Cashier\Events\WebhookEvent;

class CashierWebhookEvent
{
    use InteractsWithQueue, ShouldQueue;

    public function handle(WebhookEvent $event)
    {
        switch ($event->type) {
            case 'customer.created':
                // Handle new customer event
                break;
            case 'customer.updated':
                // Handle updated customer event
                break;
            case 'invoice.created':
                // Handle new invoice event
                $invoice = $event->invoice;
                $customer = $event->customer;

                // Save invoice data to your database
                Invoice::create([
                    'paddle_id' => $invoice->id,
                    'customer_id' => $customer->id,
                    'status' => $invoice->status,
                    'amount' => $invoice->amount,
                    'currency' => $invoice->currency,
                    'created_at' => $invoice->created_at,
                ]);
                break;
            case 'invoice.updated':
                // Handle updated invoice event
                break;
            case 'subscription.created':
                // Handle new subscription event
                break;
            case 'subscription.updated':
                // Handle updated subscription event
                break;
            case 'subscription.cancelled':
                // Handle cancelled subscription event
                break;
            case 'subscription.deleted':
                // Handle deleted subscription event
                break;
            default:
                // Handle other webhook events
                break;
        }
    }
}
  1. Register the event listener:
    • Open the app/Providers/EventServiceProvider.php file and add the following line to the boot() method:
Event::listen(WebhookEvent::class, CashierWebhookEvent::class);
  1. Create a Invoice model:
    • Use the following command to generate a new model: php artisan make:model Invoice.
    • Open the newly created file (located in app/Models) and define its properties as follows:
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Invoice extends Model
{
    protected $fillable = [
        'paddle_id',
        'customer_id',
        'status',
        'amount',
        'currency',
        'created_at',
    ];
}
  1. Migrate the database:
    • Run the following command to migrate the database: php artisan migrate.

Now, when you receive webhook events from Paddle, Laravel will handle them through the CashierWebhookEvent listener, and you can save the invoice data to your database.

Make sure to handle other webhook events (customer.created, customer.updated, subscription.created, subscription.updated, subscription.cancelled, and subscription.deleted) as needed in the CashierWebhookEvent listener.