Интеграция LemonSqueezy для SaaS-подписок
LemonSqueezy — Merchant of Record платформа, аналог Paddle, но ориентированная на indie-разработчиков и небольшие SaaS-продукты. Берёт на себя налоги, возвраты, fraud detection. Подходит для продуктов на ранней стадии, где нет ресурсов на полноценный биллинг. Комиссия — 5% + 50¢ на бесплатном плане, 3.5% + 30¢ на Lemon.js Plus.
Интеграция занимает 1–3 рабочих дня.
SDK и setup
LemonSqueezy предоставляет официальные SDK для JavaScript/TypeScript и PHP:
npm install @lemonsqueezy/lemonsqueezy.js
composer require lmsqueezy/laravel
Laravel-пакет (lmsqueezy/laravel) добавляет трейт Billable на модель User, аналогично Laravel Cashier:
use LemonSqueezy\Laravel\Billable;
class User extends Authenticatable
{
use Billable;
}
Создание варианта (variant) для подписки
В LemonSqueezy продукт → вариант (аналог Price в Stripe). Варианты создаются в dashboard. Для подписки указывается billing interval и trial period.
Checkout
// Сгенерировать checkout URL
$checkout = $user->checkout('variant_id_here', [
'checkout_options' => [
'dark' => true,
'button_color' => '#7C3AED',
'subscription_preview' => true,
],
'checkout_data' => [
'email' => $user->email,
'name' => $user->name,
'custom' => ['user_id' => $user->id],
],
'expires_at' => now()->addHours(24)->toIso8601String(),
]);
return redirect($checkout->url);
Checkout открывается как оверлей или отдельная страница на checkout.lemonsqueezy.com. Кастомный домен — только на платном плане.
Webhook
// routes/web.php
Route::lemonSqueezyWebhooks('/lemon-squeezy/webhook');
Пакет автоматически верифицирует подпись и диспатчит Laravel события:
use LemonSqueezy\Laravel\Events\SubscriptionCreated;
use LemonSqueezy\Laravel\Events\SubscriptionUpdated;
use LemonSqueezy\Laravel\Events\SubscriptionExpired;
use LemonSqueezy\Laravel\Events\OrderRefunded;
class EventServiceProvider extends ServiceProvider
{
protected $listen = [
SubscriptionCreated::class => [ActivateUserSubscription::class],
SubscriptionExpired::class => [DeactivateUserSubscription::class],
OrderRefunded::class => [HandleRefund::class],
];
}
Слушатель активации:
class ActivateUserSubscription
{
public function handle(SubscriptionCreated $event): void
{
$userId = $event->subscription->custom_data['user_id'] ?? null;
if (!$userId) return;
$user = User::find($userId);
$user?->update([
'plan' => $event->subscription->product_name,
'subscribed_at' => now(),
'subscription_status' => 'active',
]);
}
}
Управление подпиской
// Получить подписку пользователя
$subscription = $user->subscription();
// Отменить (в конце периода)
$subscription->cancel();
// Немедленная отмена
$subscription->cancelNow();
// Возобновить отменённую подписку
$subscription->resume();
// Проверить статус
if ($user->subscribed()) {
// Активная подписка
}
if ($user->onTrial()) {
$trialEndsAt = $user->trialEndsAt();
}
Customer Portal
LemonSqueezy генерирует ссылку на customer portal:
$portalUrl = $user->customerPortalUrl();
return redirect($portalUrl);
Портал позволяет сменить карту, скачать инвойсы, отменить подписку. Кастомизация ограничена.
Лицензии (одноразовые продукты)
LemonSqueezy поддерживает не только подписки, но и лицензионные ключи для one-time продуктов. При покупке генерируется ключ, который можно активировать через API:
// Активация лицензионного ключа
$response = Http::withToken(config('lemon-squeezy.api_key'))
->post('https://api.lemonsqueezy.com/v1/licenses/activate', [
'license_key' => $request->license_key,
'instance_name'=> $request->app_name,
]);
if ($response->json('activated')) {
$user->update(['license_key' => $request->license_key, 'is_licensed' => true]);
}
Ограничения
LemonSqueezy не поддерживает metered/usage-based billing — только фиксированные суммы. Для SaaS с оплатой по потреблению API лучше Stripe Billing или Orb. Также нет поддержки B2B инвойсов с отсрочкой платежа. Для простых SaaS-продуктов с фиксированными планами — вполне достаточно.







