Does NestJS Work With Paddle?
NestJS and Paddle integrate seamlessly for building SaaS backends with subscription billing and tax compliance handled by Paddle.
Quick Facts
How NestJS Works With Paddle
NestJS works excellently with Paddle's payment infrastructure because Paddle provides REST APIs and webhooks that integrate naturally into NestJS's controller and service architecture. You'll create NestJS controllers to handle Paddle webhook events (subscription created, payment succeeded, etc.), validate signatures using Paddle's API, and manage your subscription state in your database. The framework's dependency injection system makes it trivial to create a Paddle service that wraps their API client, handling authentication and providing reusable methods for creating checkouts, managing subscriptions, and retrieving transaction data.
The typical flow: your NestJS backend creates a Paddle checkout URL via their API, your frontend redirects users to complete payment, then Paddle sends signed webhooks back to your backend confirming the transaction. NestJS's guard system is perfect for verifying webhook signatures before processing events. You'll store subscription metadata (customer ID, plan details, renewal dates) in your own database for application logic, while Paddle remains the source of truth for billing state. This separation of concerns keeps your architecture clean—NestJS handles your domain logic, Paddle handles compliance and payments.
The developer experience is smooth: install the Paddle SDK, create a service wrapper, set up webhook routes, and you're handling production payments with PCI compliance and tax calculations out of the box. No custom tax logic needed, no PCI liability—just business logic.
Best Use Cases
Quick Setup
npm install @paddle/paddle-node-sdkimport { Injectable } from '@nestjs/common';
import { Client } from '@paddle/paddle-node-sdk';
@Injectable()
export class PaddleService {
private client: Client;
constructor() {
this.client = new Client({
token: process.env.PADDLE_API_KEY,
environment: process.env.NODE_ENV === 'production' ? 'production' : 'sandbox',
});
}
async createCheckout(priceId: string, customerId: string) {
return this.client.checkouts.create({
items: [{ priceId }],
customData: { customerId },
});
}
async getSubscription(subscriptionId: string) {
return this.client.subscriptions.get(subscriptionId);
}
}
// In your webhook controller:
@Post('/webhooks/paddle')
async handlePaddleWebhook(@Body() event: any, @Headers() headers: any) {
const isValid = this.verifySignature(event, headers['x-paddle-signature']);
if (!isValid) throw new BadRequestException('Invalid signature');
if (event.type === 'subscription.created') {
await this.handleSubscriptionCreated(event.data);
}
return { success: true };
}Known Issues & Gotchas
Webhook signature verification is mandatory in production but easy to skip during development
Fix: Always verify `X-Paddle-Signature` headers using Paddle's public key. Use environment variables to toggle strict verification in dev. Never process unverified webhooks in production.
Paddle uses webhook event IDs and requires idempotent processing since webhooks can be delivered multiple times
Fix: Store processed webhook IDs in your database and skip events you've already handled. Wrap webhook handlers in try-catch and return 200 OK even if processing fails—Paddle will retry.
API rate limits (100 requests/sec) can be hit during bulk operations or high-concurrency scenarios
Fix: Implement exponential backoff retry logic in your Paddle service. Queue bulk operations asynchronously with BullMQ or similar.
Paddle's test mode and live mode use different API keys and have separate data—easy to accidentally test against production
Fix: Use strict environment configuration validation. Fail fast if PADDLE_API_KEY is undefined. Keep test and prod credentials in separate .env files with CI/CD safeguards.
Alternatives
- •Stripe + NestJS: Industry-standard payment processor with more marketplace features, but less built-in tax/VAT compliance
- •Supabase + Stripe: Serverless alternative with Auth + Database included, but requires managing webhooks across multiple services
- •Lemon Squeezy + Node.js Express: Simpler alternative focused on creators/indie developers, fewer enterprise features than Paddle
Resources
Related Compatibility Guides
Explore more compatibility guides