Does Fastify Work With Paddle?
Fastify works seamlessly with Paddle for handling payments and webhooks in Node.js SaaS applications.
Quick Facts
How Fastify Works With Paddle
Fastify and Paddle integrate naturally through Paddle's REST API and webhook system. You'll typically use Fastify to build your backend routes that interact with Paddle's API for creating checkouts, managing subscriptions, and handling customer data. The real power comes from Fastify's webhook handling: Paddle sends real-time events (subscription created, payment succeeded, customer updated) to your Fastify routes via POST requests, which you verify using Paddle's webhook signature validation. Fastify's performance and low overhead make it ideal for high-volume payment webhooks without latency issues. The integration doesn't require special plugins—you just use standard HTTP libraries like `node-fetch` or `axios` to call Paddle's API, and Fastify's built-in request handlers to receive and process webhooks. Most developers wrap webhook handlers in middleware for consistent signature verification and error handling.
Best Use Cases
Quick Setup
npm install fastify axios dotenvimport Fastify from 'fastify';
import crypto from 'crypto';
import axios from 'axios';
const fastify = Fastify();
const PADDLE_API_KEY = process.env.PADDLE_API_KEY;
const PADDLE_WEBHOOK_SECRET = process.env.PADDLE_WEBHOOK_SECRET;
// Verify webhook signature
function verifyWebhookSignature(body: string, signature: string): boolean {
const hmac = crypto
.createHmac('sha256', PADDLE_WEBHOOK_SECRET)
.update(body)
.digest('base64');
return hmac === signature;
}
// Handle Paddle webhooks
fastify.post('/webhooks/paddle', async (request, reply) => {
const signature = request.headers['paddle-signature'] as string;
const body = JSON.stringify(request.body);
if (!verifyWebhookSignature(body, signature)) {
return reply.status(401).send({ error: 'Invalid signature' });
}
const event = request.body;
console.log('Webhook event:', event.type);
// Handle subscription_created, payment_succeeded, etc.
return reply.status(200).send({ success: true });
});
// Create checkout
fastify.post('/checkout', async (request, reply) => {
const response = await axios.post(
'https://api.paddle.com/checkouts',
{ product_id: 123, customer_email: 'user@example.com' },
{ headers: { 'Authorization': `Bearer ${PADDLE_API_KEY}` } }
);
return reply.send(response.data);
});
fastify.listen({ port: 3000 });Known Issues & Gotchas
Webhook signature verification is critical but easy to misconfigure
Fix: Always validate webhook signatures using Paddle's provided webhook secret before processing events. Use a dedicated middleware or utility function to verify the HMAC-SHA256 signature on every request.
Paddle's API uses different endpoints for sandbox and production without automatic switching
Fix: Set environment variables for API URLs and keys, and switch them based on NODE_ENV. Test thoroughly in sandbox before going live.
Webhook delivery is not guaranteed to be in order or delivered once
Fix: Implement idempotent handlers using transaction IDs or timestamps. Store processed webhook IDs to detect and skip duplicates.
Rate limiting on Paddle API calls can catch you off-guard during bulk operations
Fix: Implement exponential backoff and request queuing for batch operations. Monitor your API usage proactively.
Alternatives
- •Express.js with Stripe: More established webhook ecosystem but Stripe doesn't handle tax compliance as merchant of record
- •Hono with Lemonsqueezy: Lightweight framework with simpler payment infrastructure, better for indie developers
- •NestJS with Chargebee: More opinionated structure for enterprise SaaS, comprehensive subscription management
Resources
Related Compatibility Guides
Explore more compatibility guides