Інтеграція Paddle для SaaS-підписок
Paddle — платіжна платформа, яка виступає Merchant of Record (MoR): береже на себе податки (VAT, GST, sales tax), повернення та комплайєнс. Для SaaS-компаній поза США та ЕС це часто єдиний спосіб легально продавати в 200+ країнах без откриття юридичної особи в кожній. Paddle сам розраховує та перечисляє місцеві податки — розробникам не потрібно про це думати.
Paddle Billing (v2) — більш новий продукт, відрізняється від Paddle Classic API. Інтеграція займає 3–5 робочих днів.
Paddle Billing vs Classic
Paddle Classic використовує overlay checkout — JavaScript widget вбудовується на сторінку. Paddle Billing використовує власний checkout URL або inline checkout через iframe. Нові проекти варто починати з Billing, якщо Classic не потрібен для сумісності.
Створення продуктів та цін
// Paddle Billing REST API
const product = await paddle.products.create({
name: 'Pro Plan',
tax_category: 'saas',
});
const price = await paddle.prices.create({
product_id: product.id,
description: 'Pro Monthly',
billing_cycle: { interval: 'month', frequency: 1 },
trial_period: { interval: 'day', frequency: 14 },
unit_price: { amount: '2900', currency_code: 'USD' },
});
Checkout на фронтенді
Paddle Billing надає @paddle/paddle-js SDK:
import { initializePaddle } from '@paddle/paddle-js';
const paddle = await initializePaddle({
environment: 'production', // або 'sandbox'
token: 'live_...',
eventCallback(event) {
if (event.name === 'checkout.completed') {
const { transaction_id, customer } = event.data;
// Перенаправити або оновити UI
window.location.href = `/dashboard?checkout=success&txn=${transaction_id}`;
}
},
});
// Відкрити checkout
paddle.Checkout.open({
items: [{ priceId: 'pri_...', quantity: 1 }],
customer: { email: currentUser.email },
customData: { user_id: currentUser.id },
successUrl: `${window.location.origin}/dashboard`,
});
Webhook-и та синхронізація
Paddle відправляє события підписки. Підписи верифікуються через ECDSA з публічним ключем з dashboard:
use Paddle\Webhooks\Verify;
public function handleWebhook(Request $request): Response
{
$verified = Verify::signature(
$request->getContent(),
$request->header('Paddle-Signature'),
config('services.paddle.webhook_secret')
);
if (!$verified) {
return response('Forbidden', 403);
}
$payload = $request->json()->all();
match ($payload['event_type']) {
'subscription.created' => $this->onSubscriptionCreated($payload['data']),
'subscription.updated' => $this->onSubscriptionUpdated($payload['data']),
'subscription.cancelled' => $this->onSubscriptionCancelled($payload['data']),
'transaction.completed' => $this->onTransactionCompleted($payload['data']),
'transaction.payment_failed' => $this->onPaymentFailed($payload['data']),
default => null,
};
return response('OK', 200);
}
private function onSubscriptionCreated(array $data): void
{
$userId = $data['custom_data']['user_id'];
$user = User::findOrFail($userId);
$user->update([
'paddle_subscription_id' => $data['id'],
'paddle_customer_id' => $data['customer_id'],
'subscription_status' => $data['status'],
'plan' => $data['items'][0]['price']['id'],
'trial_ends_at' => $data['current_billing_period']['starts_at'] ?? null,
'renews_at' => $data['next_billed_at'],
]);
}
Апгрейд та скасування
Paddle Billing дозволяє оновити підписку через API. Prorated billing розраховується автоматично:
// Апгрейд на новий план
$paddleClient->subscriptions()->update($subscription_id, [
'items' => [[
'price_id' => 'pri_new_plan',
'quantity' => 1,
]],
'proration_billing_mode' => 'prorated_immediately',
]);
// Скасування в кінці періоду
$paddleClient->subscriptions()->cancel($subscription_id, [
'effective_from' => 'next_billing_period',
]);
Customer Portal
На відміну від Stripe, Paddle не має готового Customer Portal. Управління підпискою реалізується через Paddle Update Payment Method URL та власні API вызови. Для зміни способу оплати:
$updateUrl = $paddleClient->subscriptions()->getPaymentMethodUpdateTransaction($subscription_id);
// Редирект на $updateUrl->url
Податки та валюти
Paddle автоматично визначає країну покупця за IP та додає місцевий податок (НДС в ЕС, GST в Австралії тощо). Итогова ціна, яку бачить користувач, вже включає податок. Paddle перечисляє його в місцеві податкові органи — ніяких додаткових дій від розробника не потрібно.
Paddle підтримує dynamic pricing: один і той же product відображається в різних валютах залежно від країни користувача.







