# Paddle Node.js SDK The Paddle Node.js SDK (`@paddle/paddle-node-sdk`) is a server-side JavaScript library for integrating with Paddle Billing, a developer-first merchant of record platform designed for SaaS, AI, mobile apps, and digital product businesses. The SDK provides a unified API for handling payments, tax, subscriptions, and metrics with complete feature parity with the Paddle REST API. This SDK enables developers to manage the full lifecycle of subscription-based and one-time payment businesses. Core functionality includes managing products and prices, handling customer data and addresses, processing transactions and subscriptions, creating adjustments (refunds/credits), generating reports, and receiving real-time webhook notifications. The SDK supports both Node.js environments (v20+) and edge runtimes (Cloudflare Workers, Deno, Bun) with full TypeScript support. --- ## Client Initialization Initialize the Paddle client with your API key to authenticate API requests. You can configure environment (sandbox/production), logging level, and custom headers. ```typescript import { Environment, LogLevel, Paddle } from '@paddle/paddle-node-sdk' // Basic initialization const paddle = new Paddle('YOUR_API_KEY') // Full configuration with options const paddleConfigured = new Paddle('YOUR_API_KEY', { environment: Environment.sandbox, // Environment.production for live logLevel: LogLevel.verbose, // LogLevel.error (default), LogLevel.none customHeaders: { 'X-Custom-Header': 'custom-value' } }) ``` --- ## Products Resource Manage your product catalog including creating, listing, updating, archiving, and retrieving products. Products are containers for prices and represent the items you sell. ```typescript import { Paddle, Product, ProductCollection, CreateProductRequestBody, GetProductQueryParameters } from '@paddle/paddle-node-sdk' const paddle = new Paddle('YOUR_API_KEY') // Create a product const newProduct = await paddle.products.create({ name: 'Pro Plan', taxCategory: 'standard', description: 'Full access to all features', imageUrl: 'https://example.com/pro-plan.png', customData: { tier: 'professional' } }) console.log('Created product:', newProduct.id) // pro_01gsz97mq9pa4fkyy0wqenepkz // List all products with pagination const productCollection: ProductCollection = paddle.products.list({ status: ['active'] }) const firstPage: Product[] = await productCollection.next() console.log('Products:', firstPage.map(p => p.name)) // Iterate all products across pages for await (const product of paddle.products.list()) { console.log(`Product: ${product.name} (${product.id})`) } // Get a single product with prices included const product = await paddle.products.get('pro_01gsz97mq9pa4fkyy0wqenepkz', { include: ['prices'] }) console.log('Product prices:', product.prices) // Update a product const updated = await paddle.products.update('pro_01gsz97mq9pa4fkyy0wqenepkz', { name: 'Pro Plan (Updated)', description: 'Enhanced professional plan' }) // Archive a product const archived = await paddle.products.archive('pro_01gsz97mq9pa4fkyy0wqenepkz') console.log('Product archived:', archived.status) // 'archived' ``` --- ## Prices Resource Create and manage prices for your products. Prices define the amount, currency, billing cycle, and trial periods for products. ```typescript import { Paddle, Price, CreatePriceRequestBody } from '@paddle/paddle-node-sdk' const paddle = new Paddle('YOUR_API_KEY') // Create a recurring price with trial const monthlyPrice = await paddle.prices.create({ description: 'Pro Plan - Monthly', productId: 'pro_01gsz97mq9pa4fkyy0wqenepkz', unitPrice: { amount: '2999', currencyCode: 'USD' }, billingCycle: { interval: 'month', frequency: 1 }, trialPeriod: { interval: 'day', frequency: 14 }, taxMode: 'account_setting' }) // Create a one-time price const oneTimePrice = await paddle.prices.create({ description: 'Setup Fee', productId: 'pro_01gsz97mq9pa4fkyy0wqenepkz', unitPrice: { amount: '9900', currencyCode: 'USD' }, taxMode: 'account_setting' }) // List prices filtered by product for await (const price of paddle.prices.list({ productId: ['pro_01gsz97mq9pa4fkyy0wqenepkz'] })) { console.log(`Price: ${price.description} - ${price.unitPrice.amount} ${price.unitPrice.currencyCode}`) } // Get price with product details const price = await paddle.prices.get('pri_01gsz8z1q1n00f12qt82y31smh', { include: ['product'] }) // Update price await paddle.prices.update('pri_01gsz8z1q1n00f12qt82y31smh', { description: 'Pro Plan - Monthly (Discounted)', unitPrice: { amount: '2499', currencyCode: 'USD' } }) // Archive price await paddle.prices.archive('pri_01gsz8z1q1n00f12qt82y31smh') ``` --- ## Customers Resource Manage customer records including creating, updating, archiving customers, retrieving credit balances, and generating authentication tokens. ```typescript import { Paddle, Customer, CustomerCollection } from '@paddle/paddle-node-sdk' const paddle = new Paddle('YOUR_API_KEY') // Create a customer const customer = await paddle.customers.create({ email: 'customer@example.com', name: 'John Doe', locale: 'en', customData: { referralSource: 'google' } }) console.log('Customer ID:', customer.id) // ctm_01grnn4zta5a1mf02jjze7y2ys // List customers with email filter const customers: CustomerCollection = paddle.customers.list({ email: ['customer@example.com'], status: ['active'] }) const results = await customers.next() // Get a customer const existingCustomer = await paddle.customers.get('ctm_01grnn4zta5a1mf02jjze7y2ys') // Update customer details await paddle.customers.update('ctm_01grnn4zta5a1mf02jjze7y2ys', { name: 'John Smith', email: 'john.smith@example.com' }) // Get customer credit balances const creditBalances = await paddle.customers.getCreditBalance('ctm_01grnn4zta5a1mf02jjze7y2ys', { currencyCode: ['USD'] }) for (const balance of creditBalances) { console.log(`Credit: ${balance.balance.amount} ${balance.balance.currencyCode}`) } // Generate auth token for Paddle.js const authToken = await paddle.customers.generateAuthToken('ctm_01grnn4zta5a1mf02jjze7y2ys') console.log('Auth token:', authToken.customerAuthToken) // Archive customer await paddle.customers.archive('ctm_01grnn4zta5a1mf02jjze7y2ys') ``` --- ## Addresses Resource Manage customer billing addresses. Addresses are associated with customers and used for tax calculations. ```typescript import { Paddle, Address, AddressCollection } from '@paddle/paddle-node-sdk' const paddle = new Paddle('YOUR_API_KEY') const customerId = 'ctm_01grnn4zta5a1mf02jjze7y2ys' // Create an address for a customer const address = await paddle.addresses.create(customerId, { countryCode: 'US', postalCode: '94107', region: 'CA', city: 'San Francisco', firstLine: '123 Market Street', description: 'Billing Address' }) console.log('Address ID:', address.id) // add_01gm302t81w94gyjpjpqypkzkf // List addresses for a customer const addressCollection: AddressCollection = paddle.addresses.list(customerId) const addresses = await addressCollection.next() // Get a specific address const existingAddress = await paddle.addresses.get(customerId, 'add_01gm302t81w94gyjpjpqypkzkf') // Update an address await paddle.addresses.update(customerId, 'add_01gm302t81w94gyjpjpqypkzkf', { city: 'Los Angeles', region: 'CA', postalCode: '90001' }) // Archive an address await paddle.addresses.archive(customerId, 'add_01gm302t81w94gyjpjpqypkzkf') ``` --- ## Businesses Resource Manage business entities associated with customers for B2B billing scenarios. ```typescript import { Paddle, Business, BusinessCollection } from '@paddle/paddle-node-sdk' const paddle = new Paddle('YOUR_API_KEY') const customerId = 'ctm_01grnn4zta5a1mf02jjze7y2ys' // Create a business for a customer const business = await paddle.businesses.create(customerId, { name: 'Acme Corporation', companyNumber: 'US123456789', taxIdentifier: 'US123456789', contacts: [ { name: 'Jane Doe', email: 'jane@acme.com' } ] }) // List businesses for a customer for await (const biz of paddle.businesses.list(customerId)) { console.log(`Business: ${biz.name} (${biz.id})`) } // Get a specific business const existingBusiness = await paddle.businesses.get(customerId, 'biz_01grrebrzaee2qj2fqqhmcyzaj') // Update a business await paddle.businesses.update(customerId, 'biz_01grrebrzaee2qj2fqqhmcyzaj', { name: 'Acme Inc.', contacts: [ { name: 'John Smith', email: 'john@acme.com' } ] }) // Archive a business await paddle.businesses.archive(customerId, 'biz_01grrebrzaee2qj2fqqhmcyzaj') ``` --- ## Transactions Resource Create, manage, and preview transactions. Transactions represent payment attempts for checkout sessions. ```typescript import { Paddle, Transaction, TransactionCollection } from '@paddle/paddle-node-sdk' const paddle = new Paddle('YOUR_API_KEY') // Create a transaction const transaction = await paddle.transactions.create({ items: [ { priceId: 'pri_01gsz8z1q1n00f12qt82y31smh', quantity: 1 } ], customerId: 'ctm_01grnn4zta5a1mf02jjze7y2ys', addressId: 'add_01gm302t81w94gyjpjpqypkzkf', currencyCode: 'USD', customData: { orderId: 'internal-123' } }) console.log('Transaction ID:', transaction.id) // txn_01h04vsbhqc62t8hmd4z3b578c // List transactions with filters const transactions: TransactionCollection = paddle.transactions.list({ status: ['completed', 'billed'], customerId: ['ctm_01grnn4zta5a1mf02jjze7y2ys'] }) const page = await transactions.next() // Get transaction with includes const txn = await paddle.transactions.get('txn_01h04vsbhqc62t8hmd4z3b578c', { include: ['customer', 'address', 'discount', 'available_payment_methods'] }) // Preview a transaction (calculate prices without creating) const preview = await paddle.transactions.preview({ items: [ { priceId: 'pri_01gsz8z1q1n00f12qt82y31smh', quantity: 2 } ], customerId: 'ctm_01grnn4zta5a1mf02jjze7y2ys', addressId: 'add_01gm302t81w94gyjpjpqypkzkf', currencyCode: 'USD' }) console.log('Subtotal:', preview.details?.totals?.subtotal) // Update transaction await paddle.transactions.update('txn_01h04vsbhqc62t8hmd4z3b578c', { customData: { orderId: 'updated-123' } }) // Revise a completed transaction (update customer info) await paddle.transactions.revise('txn_01h04vsbhqc62t8hmd4z3b578c', { address: { countryCode: 'GB', postalCode: 'SW1A 1AA' } }) // Get invoice PDF const invoice = await paddle.transactions.getInvoicePDF('txn_01h04vsbhqc62t8hmd4z3b578c', { disposition: 'attachment' // or 'inline' }) console.log('Invoice URL:', invoice.url) ``` --- ## Subscriptions Resource Manage recurring subscriptions including updating, pausing, resuming, canceling, and creating one-time charges. ```typescript import { Paddle, Subscription, SubscriptionCollection } from '@paddle/paddle-node-sdk' const paddle = new Paddle('YOUR_API_KEY') // List subscriptions const subscriptions: SubscriptionCollection = paddle.subscriptions.list({ status: ['active', 'trialing'], customerId: ['ctm_01grnn4zta5a1mf02jjze7y2ys'] }) const activeSubscriptions = await subscriptions.next() // Get subscription with details const subscription = await paddle.subscriptions.get('sub_01h04vsc0qhwtsbsxh3422wjs4', { include: ['next_transaction', 'recurring_transaction_details'] }) console.log('Next billing:', subscription.nextBilledAt) // Update subscription (change items, billing details) const updated = await paddle.subscriptions.update('sub_01h04vsc0qhwtsbsxh3422wjs4', { items: [ { priceId: 'pri_01gsz8z1q1n00f12qt82y31smh', quantity: 2 } ], prorationBillingMode: 'prorated_immediately' }) // Preview an update before applying const preview = await paddle.subscriptions.previewUpdate('sub_01h04vsc0qhwtsbsxh3422wjs4', { items: [ { priceId: 'pri_01h1vjes1y163xfj1rh1tkfb65', quantity: 1 } ] }) console.log('Immediate charge:', preview.immediateTransaction?.details?.totals?.total) // Pause a subscription await paddle.subscriptions.pause('sub_01h04vsc0qhwtsbsxh3422wjs4', { effectiveFrom: 'next_billing_period' }) // Resume a paused subscription await paddle.subscriptions.resume('sub_01h04vsc0qhwtsbsxh3422wjs4', { effectiveFrom: 'immediately', onResume: 'continue_existing_billing_period' }) // Cancel a subscription await paddle.subscriptions.cancel('sub_01h04vsc0qhwtsbsxh3422wjs4', { effectiveFrom: 'next_billing_period' }) // Activate a trialing subscription await paddle.subscriptions.activate('sub_01h04vsc0qhwtsbsxh3422wjs4') // Create a one-time charge on subscription await paddle.subscriptions.createOneTimeCharge('sub_01h04vsc0qhwtsbsxh3422wjs4', { items: [ { priceId: 'pri_01gsz91ez5f6s9dshcz4c0hx27', quantity: 1 } ], effectiveFrom: 'immediately' }) // Preview one-time charge const chargePreview = await paddle.subscriptions.previewOneTimeCharge('sub_01h04vsc0qhwtsbsxh3422wjs4', { items: [ { priceId: 'pri_01gsz91ez5f6s9dshcz4c0hx27', quantity: 1 } ], effectiveFrom: 'immediately' }) // Get transaction for updating payment method const paymentTxn = await paddle.subscriptions.getPaymentMethodChangeTransaction('sub_01h04vsc0qhwtsbsxh3422wjs4') ``` --- ## Discounts Resource Create and manage discount codes and percentage/flat discounts. ```typescript import { Paddle, Discount, DiscountCollection } from '@paddle/paddle-node-sdk' const paddle = new Paddle('YOUR_API_KEY') // Create a percentage discount const percentDiscount = await paddle.discounts.create({ amount: '15', type: 'percentage', description: '15% Off for New Customers', code: 'WELCOME15', enabledForCheckout: true, recur: true, // Apply on renewals maximumRecurringIntervals: 3, usageLimit: 100 }) // Create a flat amount discount const flatDiscount = await paddle.discounts.create({ amount: '1000', // $10.00 type: 'flat', currencyCode: 'USD', description: '$10 Off', code: 'SAVE10', enabledForCheckout: true, restrictTo: ['pri_01gsz8z1q1n00f12qt82y31smh'] // Limit to specific prices }) // List discounts for await (const discount of paddle.discounts.list({ status: ['active'] })) { console.log(`Discount: ${discount.code} - ${discount.amount}${discount.type === 'percentage' ? '%' : ''}`) } // Get a discount const discount = await paddle.discounts.get('dsc_01gv5kpg05xp104ek2fmgjwttf') // Update a discount await paddle.discounts.update('dsc_01gv5kpg05xp104ek2fmgjwttf', { description: 'Updated - 15% Off', usageLimit: 200 }) // Archive a discount await paddle.discounts.archive('dsc_01gv5kpg05xp104ek2fmgjwttf') ``` --- ## Adjustments Resource Create refunds and credits for completed transactions. ```typescript import { Paddle, Adjustment, AdjustmentCollection } from '@paddle/paddle-node-sdk' const paddle = new Paddle('YOUR_API_KEY') // Create a partial refund const partialRefund = await paddle.adjustments.create({ transactionId: 'txn_01h04vsbhqc62t8hmd4z3b578c', action: 'refund', reason: 'Customer requested partial refund', type: 'partial', items: [ { itemId: 'txnitm_01hvcc94b7qgz60qmrqmbm19zw', type: 'partial', amount: '500' } ] }) // Create a full refund const fullRefund = await paddle.adjustments.create({ transactionId: 'txn_01h04vsbhqc62t8hmd4z3b578c', action: 'refund', reason: 'Full refund requested', type: 'full' }) // Create a credit (doesn't return funds, adds to customer balance) const credit = await paddle.adjustments.create({ transactionId: 'txn_01h04vsbhqc62t8hmd4z3b578c', action: 'credit', reason: 'Service credit', type: 'partial', items: [ { itemId: 'txnitm_01hvcc94b7qgz60qmrqmbm19zw', type: 'partial', amount: '1000' } ] }) // List adjustments for await (const adjustment of paddle.adjustments.list({ transactionId: 'txn_01h04vsbhqc62t8hmd4z3b578c' })) { console.log(`Adjustment: ${adjustment.action} - ${adjustment.totals?.total}`) } // Get credit note PDF for adjustment const creditNote = await paddle.adjustments.getCreditNotePDF('adj_01h9apkx1d320kpvvfyezr96k0', { disposition: 'attachment' }) console.log('Credit note URL:', creditNote.url) ``` --- ## Pricing Preview Resource Preview pricing calculations without creating transactions. Useful for displaying prices before checkout. ```typescript import { Paddle, PricingPreview } from '@paddle/paddle-node-sdk' const paddle = new Paddle('YOUR_API_KEY') // Preview pricing with customer and address const preview = await paddle.pricingPreview.preview({ items: [ { priceId: 'pri_01gsz8z1q1n00f12qt82y31smh', quantity: 1 }, { priceId: 'pri_01h1vjes1y163xfj1rh1tkfb65', quantity: 2 } ], customerId: 'ctm_01grnn4zta5a1mf02jjze7y2ys', addressId: 'add_01gm302t81w94gyjpjpqypkzkf', currencyCode: 'USD', discountId: 'dsc_01gv5kpg05xp104ek2fmgjwttf' }) console.log('Subtotal:', preview.details?.lineItems?.[0]?.totals?.subtotal) console.log('Tax:', preview.details?.lineItems?.[0]?.totals?.tax) console.log('Total:', preview.details?.lineItems?.[0]?.totals?.total) // Preview for anonymous user (IP-based location) const anonPreview = await paddle.pricingPreview.preview({ items: [ { priceId: 'pri_01gsz8z1q1n00f12qt82y31smh', quantity: 1 } ], address: { countryCode: 'DE', postalCode: '10115' }, currencyCode: 'EUR' }) ``` --- ## Metrics Resource Retrieve time-series business metrics including revenue, subscriptions, refunds, and checkout conversion. ```typescript import { Paddle } from '@paddle/paddle-node-sdk' const paddle = new Paddle('YOUR_API_KEY') // Get revenue metrics const revenue = await paddle.metrics.getRevenue({ from: '2024-01-01', to: '2024-12-31' }) console.log('Revenue data points:', revenue.data) // Get active subscribers count const subscribers = await paddle.metrics.getActiveSubscribers({ from: '2024-01-01', to: '2024-12-31' }) // Get Monthly Recurring Revenue (MRR) const mrr = await paddle.metrics.getMonthlyRecurringRevenue({ from: '2024-01-01', to: '2024-12-31' }) // Get MRR change (growth/churn) const mrrChange = await paddle.metrics.getMonthlyRecurringRevenueChange({ from: '2024-01-01', to: '2024-12-31' }) // Get refund metrics const refunds = await paddle.metrics.getRefunds({ from: '2024-01-01', to: '2024-12-31' }) // Get chargeback metrics const chargebacks = await paddle.metrics.getChargebacks({ from: '2024-01-01', to: '2024-12-31' }) // Get checkout conversion rates const conversion = await paddle.metrics.getCheckoutConversion({ from: '2024-01-01', to: '2024-12-31' }) ``` --- ## Payment Methods Resource Manage saved payment methods for customers. ```typescript import { Paddle, PaymentMethod, PaymentMethodCollection } from '@paddle/paddle-node-sdk' const paddle = new Paddle('YOUR_API_KEY') const customerId = 'ctm_01grnn4zta5a1mf02jjze7y2ys' // List payment methods for a customer const paymentMethods: PaymentMethodCollection = paddle.paymentMethods.list(customerId) const methods = await paymentMethods.next() for (const method of methods) { console.log(`Payment method: ${method.type} - ${method.id}`) } // Get a specific payment method const paymentMethod = await paddle.paymentMethods.get(customerId, 'paymtd_01hkm9xwqpbbpr1ksmvg3sx3v1') console.log('Card type:', paymentMethod.card?.type) console.log('Last 4:', paymentMethod.card?.last4) // Delete a payment method await paddle.paymentMethods.delete(customerId, 'paymtd_01hkm9xwqpbbpr1ksmvg3sx3v1') ``` --- ## Customer Portal Sessions Resource Create portal sessions for customers to manage their subscriptions. ```typescript import { Paddle, CustomerPortalSession } from '@paddle/paddle-node-sdk' const paddle = new Paddle('YOUR_API_KEY') // Create a customer portal session const session = await paddle.customerPortalSessions.create( 'ctm_01grnn4zta5a1mf02jjze7y2ys', ['sub_01h04vsc0qhwtsbsxh3422wjs4'] // subscription IDs to show ) console.log('Portal URL:', session.urls?.general?.overview) // Redirect customer to this URL for self-service management ``` --- ## Reports Resource Generate and download business reports. ```typescript import { Paddle, Report, ReportCollection } from '@paddle/paddle-node-sdk' const paddle = new Paddle('YOUR_API_KEY') // Create a transaction line items report const report = await paddle.reports.create({ type: 'transaction_line_items', filters: [ { name: 'updated_at', operator: 'gte', value: '2024-01-01' } ] }) console.log('Report ID:', report.id) // rep_01h9apkx1d320kpvvfyezr96k0 // List reports for await (const rep of paddle.reports.list()) { console.log(`Report: ${rep.type} - ${rep.status}`) } // Get report status const reportStatus = await paddle.reports.get('rep_01h9apkx1d320kpvvfyezr96k0') // Download report CSV when ready if (reportStatus.status === 'ready') { const csv = await paddle.reports.getReportCsv('rep_01h9apkx1d320kpvvfyezr96k0') console.log('Download URL:', csv.url) } ``` --- ## Notifications and Notification Settings Resources Manage webhook notification settings and view notification history. ```typescript import { Paddle, NotificationSettings, Notification } from '@paddle/paddle-node-sdk' const paddle = new Paddle('YOUR_API_KEY') // Create notification settings (webhook endpoint) const settings = await paddle.notificationSettings.create({ description: 'Production Webhook', type: 'url', destination: 'https://example.com/paddle/webhook', subscribedEvents: [ 'subscription.created', 'subscription.updated', 'subscription.canceled', 'transaction.completed', 'transaction.payment_failed' ], includeSensitiveFields: false }) // List notification settings for await (const setting of paddle.notificationSettings.list()) { console.log(`Endpoint: ${setting.destination} - ${setting.subscribedEvents?.length} events`) } // Update notification settings await paddle.notificationSettings.update('ntfset_01gt21c5pdx9q1e4mh1xrsjjn6', { subscribedEvents: ['subscription.created', 'subscription.canceled'] }) // List notifications (webhook delivery history) for await (const notification of paddle.notifications.list({ notificationSettingId: 'ntfset_01gt21c5pdx9q1e4mh1xrsjjn6' })) { console.log(`Notification: ${notification.type} - ${notification.status}`) } // Get notification details const notification = await paddle.notifications.get('ntf_01ghbkd0frb9k95cnhwd1bxpvk') // Replay a failed notification await paddle.notifications.replay('ntf_01ghbkd0frb9k95cnhwd1bxpvk') // Get notification delivery logs const logs = await paddle.notifications.getLogs('ntf_01ghbkd0frb9k95cnhwd1bxpvk') // Delete notification settings await paddle.notificationSettings.delete('ntfset_01gt21c5pdx9q1e4mh1xrsjjn6') ``` --- ## Webhook Signature Verification Verify webhook signatures to ensure notifications are authentic. Use the `unmarshal` method to validate and parse webhook payloads. ```typescript import { Paddle, EventName } from '@paddle/paddle-node-sdk' import express, { Request, Response } from 'express' const paddle = new Paddle('YOUR_API_KEY') const app = express() // IMPORTANT: Use express.raw() middleware to get raw body for signature verification app.post('/paddle/webhook', express.raw({ type: 'application/json' }), async (req: Request, res: Response) => { const signature = req.headers['paddle-signature'] as string const rawBody = req.body.toString() const secretKey = process.env.PADDLE_WEBHOOK_SECRET || '' try { // Validate signature and parse event const event = await paddle.webhooks.unmarshal(rawBody, secretKey, signature) switch (event.eventType) { case EventName.SubscriptionCreated: console.log(`New subscription: ${event.data.id}`) // Handle new subscription break case EventName.SubscriptionUpdated: console.log(`Subscription updated: ${event.data.id}`) // Handle subscription update break case EventName.SubscriptionCanceled: console.log(`Subscription canceled: ${event.data.id}`) // Handle cancellation break case EventName.TransactionCompleted: console.log(`Transaction completed: ${event.data.id}`) // Handle successful payment break case EventName.TransactionPaymentFailed: console.log(`Payment failed: ${event.data.id}`) // Handle failed payment break default: console.log(`Received event: ${event.eventType}`) } res.status(200).send('OK') } catch (error) { console.error('Webhook verification failed:', error) res.status(400).send('Invalid signature') } }) // Alternative: Just validate signature without parsing app.post('/paddle/webhook/validate', express.raw({ type: 'application/json' }), async (req, res) => { const isValid = await paddle.webhooks.isSignatureValid( req.body.toString(), process.env.PADDLE_WEBHOOK_SECRET || '', req.headers['paddle-signature'] as string ) if (isValid) { const event = JSON.parse(req.body.toString()) // Process event... res.status(200).send('OK') } else { res.status(400).send('Invalid signature') } }) app.listen(3000) ``` --- ## Events Resource List historical events that occurred in your Paddle account. ```typescript import { Paddle, Event } from '@paddle/paddle-node-sdk' const paddle = new Paddle('YOUR_API_KEY') // List events for await (const event of paddle.events.list({ eventType: ['subscription.created'] })) { console.log(`Event: ${event.eventType} at ${event.occurredAt}`) console.log('Data:', event.data) } // List all event types available const eventTypes = await paddle.eventTypes.list() for await (const eventType of eventTypes) { console.log(`Event type: ${eventType.name} - ${eventType.description}`) } ``` --- ## Simulations Resource Create and run webhook simulations for testing your integration. ```typescript import { Paddle, Simulation, SimulationRun } from '@paddle/paddle-node-sdk' const paddle = new Paddle('YOUR_API_KEY') // Create a simulation for a single event const simulation = await paddle.simulations.create({ name: 'Test Subscription Created', notificationSettingId: 'ntfset_01gt21c5pdx9q1e4mh1xrsjjn6', type: 'subscription.created', payload: { status: 'active', currencyCode: 'USD' } }) // Create a scenario simulation (multi-event) const scenarioSimulation = await paddle.simulations.create({ name: 'Test Subscription Pause Flow', notificationSettingId: 'ntfset_01gt21c5pdx9q1e4mh1xrsjjn6', type: 'subscription_pause', config: { subscriptionPause: { entities: { subscriptionId: 'sub_01h04vsc0qhwtsbsxh3422wjs4' }, options: { effectiveFrom: 'next_billing_period', hasPastDueTransaction: false } } } }) // List simulations for await (const sim of paddle.simulations.list()) { console.log(`Simulation: ${sim.name} - ${sim.type}`) } // Run a simulation const simulationRun = await paddle.simulationRuns.create('ntfsim_01ghbkd0frb9k95cnhwd1bxpvk') console.log('Run ID:', simulationRun.id) // List simulation runs for await (const run of paddle.simulationRuns.list('ntfsim_01ghbkd0frb9k95cnhwd1bxpvk')) { console.log(`Run: ${run.status}`) } // Get simulation run with events const runDetails = await paddle.simulationRuns.get( 'ntfsim_01ghbkd0frb9k95cnhwd1bxpvk', 'ntfsimrun_01ghbkd0frb9k95cnhwd1bxpvk', { include: ['events'] } ) // List simulation run events for await (const event of paddle.simulationRunEvents.list( 'ntfsim_01ghbkd0frb9k95cnhwd1bxpvk', 'ntfsimrun_01ghbkd0frb9k95cnhwd1bxpvk' )) { console.log(`Event: ${event.eventType} - ${event.status}`) } // Update simulation await paddle.simulations.update('ntfsim_01ghbkd0frb9k95cnhwd1bxpvk', { name: 'Updated Simulation Name' }) ``` --- ## Client Tokens Resource Generate client-side tokens for Paddle.js integration. ```typescript import { Paddle, ClientToken } from '@paddle/paddle-node-sdk' const paddle = new Paddle('YOUR_API_KEY') // Create a client token const clientToken = await paddle.clientTokens.create({ customerId: 'ctm_01grnn4zta5a1mf02jjze7y2ys', subscriptionIds: ['sub_01h04vsc0qhwtsbsxh3422wjs4'] }) console.log('Client token:', clientToken.token) // Use this token with Paddle.js on the frontend ``` --- ## Discount Groups Resource Manage discount groups for organizing related discounts. ```typescript import { Paddle, DiscountGroup } from '@paddle/paddle-node-sdk' const paddle = new Paddle('YOUR_API_KEY') // Create a discount group const group = await paddle.discountGroups.create({ description: 'Summer Sale Discounts' }) // List discount groups for await (const discountGroup of paddle.discountGroups.list()) { console.log(`Group: ${discountGroup.description} (${discountGroup.id})`) } // Get a discount group const existingGroup = await paddle.discountGroups.get('dsgrp_01h1vjes1y163xfj1rh1tkfb65') // Update a discount group await paddle.discountGroups.update('dsgrp_01h1vjes1y163xfj1rh1tkfb65', { description: 'Winter Sale Discounts' }) ``` --- ## Error Handling The SDK throws `ApiError` for API errors, which includes error codes matching the Paddle API documentation. ```typescript import { Paddle, ApiError } from '@paddle/paddle-node-sdk' const paddle = new Paddle('YOUR_API_KEY') try { await paddle.customers.create({ email: 'invalid-email' }) } catch (error) { if (error instanceof ApiError) { console.error('Error code:', error.code) console.error('Error message:', error.message) console.error('HTTP status:', error.status) // Handle specific error codes switch (error.code) { case 'conflict': console.error('Resource already exists') break case 'not_found': console.error('Resource not found') break case 'validation_error': console.error('Validation failed:', error.errors) break case 'too_many_requests': console.error('Rate limited. Retry after:', error.retryAfter) break default: console.error('Unknown error:', error.code) } } else { throw error } } ``` --- ## Summary The Paddle Node.js SDK provides a comprehensive solution for integrating subscription billing into server-side JavaScript applications. Primary use cases include: building SaaS subscription platforms with recurring billing, creating checkout flows with pricing previews, managing customer self-service through portal sessions, processing refunds and credits via adjustments, generating business intelligence reports, and receiving real-time payment notifications through webhooks. Integration patterns typically involve initializing the Paddle client during application startup, creating products and prices in the Paddle dashboard or via API, using the pricing preview for displaying checkout prices, creating transactions for payment collection, managing subscription lifecycle events through webhooks, and using the customer portal for self-service management. The SDK supports both traditional Node.js environments and modern edge runtimes, making it suitable for serverless architectures on platforms like Vercel, Cloudflare Workers, and AWS Lambda.