Does Laravel Work With Lemon Squeezy?
Laravel integrates seamlessly with Lemon Squeezy via webhooks and REST API, making it ideal for SaaS platforms and digital product sales.
Quick Facts
How Laravel Works With Lemon Squeezy
Laravel works excellently with Lemon Squeezy through its REST API and webhook system. You handle customer authentication and data in Laravel while delegating payment processing, tax compliance, and subscription management to Lemon Squeezy. The typical flow: store product IDs in your Laravel database, redirect users to Lemon Squeezy checkout via affiliate/custom links, then listen for webhooks (order.created, subscription.updated, etc.) to sync customer state back into your app. Laravel's event system pairs naturally with Lemon Squeezy's webhook payloads, letting you trigger license generation, email confirmations, or feature unlocks. The API calls are straightforward HTTP requests using Laravel's HTTP client. No SDK exists yet, but the webhook-driven architecture means minimal coupling—Lemon Squeezy handles all tax, currency conversion, and payment complexity, while Laravel manages user accounts and product access control.
Best Use Cases
Handle Lemon Squeezy Webhook in Laravel
composer require laravel/cashier-paddle<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
class LemonSqueezyWebhookController extends Controller
{
public function handle(Request $request)
{
$signature = $request->header('X-Signature');
$body = $request->getContent();
// Verify webhook signature
$publicKey = config('services.lemonsqueezy.public_key');
if (!$this->verifySignature($body, $signature, $publicKey)) {
return response('Unauthorized', 401);
}
$event = $request->input('meta.event_name');
$data = $request->input('data.attributes');
match($event) {
'order.created' => $this->handleOrderCreated($data),
'subscription.updated' => $this->handleSubscriptionUpdated($data),
default => null,
};
return response('OK', 200);
}
private function verifySignature($body, $signature, $publicKey)
{
return hash_equals(
base64_encode(hash('sha256', $body, true)),
$signature
);
}
private function handleOrderCreated($data)
{
// Create license, send email, update user
event(new \App\Events\ProductPurchased($data));
}
}Known Issues & Gotchas
Webhook signature verification is optional but critical—unsigned webhooks are a security risk
Fix: Always verify the X-Signature header using Lemon Squeezy's public key before processing webhook data. Store the key securely in .env.
Lemon Squeezy webhooks can fire multiple times or out of order, causing race conditions
Fix: Implement idempotency keys and check webhook event IDs against a processed_events table to prevent duplicate state changes.
Rate limiting on Lemon Squeezy API (120 req/min) can throttle batch operations
Fix: Use queued jobs in Laravel with backoff strategies for API calls; leverage webhooks instead of polling.
Currency and tax handling happens on Lemon Squeezy side—Laravel won't see calculated tax amounts in basic webhook data
Fix: Query Lemon Squeezy API for order details if you need full tax breakdowns for accounting reconciliation.
Alternatives
- •Stripe + Laravel Cashier—more complex but includes native Laravel bindings and advanced subscription features
- •Paddle + Laravel—similar all-in-one approach with direct Cashier integration, but fewer digital product-specific features
- •Gumroad + custom webhooks—lighter weight for simple digital products, less automation
Resources
Related Compatibility Guides
Explore more compatibility guides