Overview
The Paddle integration is a webhook server that manages the complete license lifecycle for Paddle Billing platform. It uses the official Paddle SDK for webhook verification and handles new purchases, recurring renewals, subscription pauses, and customer creation. Key capabilities:- Create licenses for new transactions (web, API, and subscription purchases)
- Automatically renew licenses on recurring subscription payments
- Resume licenses when subscriptions are updated/resumed
- Suspend licenses when subscriptions are paused
- Sync customer data between Paddle and Cryptlex
- Support for both one-time and subscription pricing
This integration uses Paddle Billing (not Paddle Classic). No Paddle API key is required - webhook verification is handled entirely by the Paddle SDK using your webhook secret.
Supported Webhook Events
The integration handles three Paddle webhook event types:transaction.completed
transaction.completed
Triggered when a transaction is successfully completed. Handles multiple transaction origins:Origin:
web or api (New purchases)- Creates a user in Cryptlex (or finds existing by Paddle customer ID)
- Creates licenses for all items in the transaction
- Stores subscription ID or transaction ID in metadata
- Supports both subscription and one-time products
subscription_recurring (Recurring renewals)- Finds licenses by subscription ID
- Renews each license to extend expiry date
- Unsuspends licenses if they were previously suspended
- Updates expiry to match billing period end date
subscription_update (Subscription resumed)- Finds suspended licenses by subscription ID
- Unsuspends each license
- Updates expiry date to billing period end date
subscription.paused
subscription.paused
Triggered when a subscription is paused in Paddle.Actions:
- Finds all licenses with matching Paddle subscription ID
- Suspends each license to prevent usage
transaction.completed event with origin subscription_update is received.customer.created
customer.created
Triggered when a new customer is created in Paddle.Actions:
- Creates or updates a user in Cryptlex with customer email and name
- Stores Paddle customer ID in Cryptlex user metadata for future lookups
- Returns the Cryptlex user ID
Environment Variables
Set these environment variables in your hosting environment:| Variable | Required | Description |
|---|---|---|
PADDLE_WEBHOOK_SECRET | Yes | Your Paddle webhook secret key for signature verification |
CRYPTLEX_ACCESS_TOKEN | Yes | Cryptlex API access token with license:read, license:write, user:read, user:write permissions |
CRYPTLEX_WEB_API_BASE_URL | Yes | Base URL of the Cryptlex Web API |
Setup Instructions
1. Deploy the Integration
Choose your deployment method: AWS Lambda: Review the providedaws.yml GitHub Actions workflow for automated deployments.
Node.js / Docker:
Use the provided Dockerfile to run in any containerized environment.
2. Configure Paddle Webhook
- Log in to your Paddle Dashboard
- Go to Developer Tools > Notifications
- Click New notification destination
- Set the destination URL:
https://your-domain.com/v1 - Select Secret key authentication
- Copy the generated secret key and save it as
PADDLE_WEBHOOK_SECRET - Subscribe to the following event types:
transaction.completedsubscription.pausedcustomer.created
- Save the notification destination
3. Configure Product Custom Data
For each Paddle product/price, add custom data to map to Cryptlex: Add to product or price custom data (JSON):item.product.customData or falls back to item.price.customData.
4. Set Environment Variables
Configure all required environment variables:Webhook Signature Verification
The integration uses the official Paddle SDK to verify webhook authenticity:- Paddle signs each webhook with your secret key
- The signature is sent in the
Paddle-Signatureheader - The SDK verifies the signature and parses the event
- Verification failure throws an error, rejecting the request
The Paddle SDK handles all signature verification complexity, including timestamp validation and signature format parsing.
Example Workflows
New Purchase (Web/API)
When a customer completes a purchase:- Event:
transaction.completedwith originweborapi - Handler:
handleNewLicense - Actions:
- Get or create Cryptlex user by Paddle customer ID
- Extract product and template IDs from custom data
- Determine subscription interval from billing cycle
- Create licenses based on item quantity
- Store subscription ID (for subscriptions) or transaction ID (for one-time)
- Result: Customer receives license(s)
- Monthly:
P1M - Yearly:
P1Y - Weekly:
P1W - Daily:
P1D - Custom:
P{frequency}{unit}(e.g.,P3Mfor quarterly)
Recurring Renewal
When a subscription auto-renews:- Event:
transaction.completedwith originsubscription_recurring - Handler:
handleRecurringRenewal - Actions:
- Find licenses by Paddle subscription ID
- For each license:
- If suspended: unsuspend and update expiry
- If active: renew to extend expiry
- Result: Licenses remain valid for next billing period
The handler checks for suspended licenses because Paddle may send
subscription_recurring for resumed subscriptions depending on how the resume was triggered.Subscription Paused
When a customer pauses their subscription:- Event:
subscription.paused - Handler:
handleSubscriptionPaused - Actions:
- Find licenses by subscription ID
- Suspend each license
- Result: License usage blocked until resumed
Subscription Resumed
When a paused subscription is resumed:- Event:
transaction.completedwith originsubscription_update - Handler:
handleSubscriptionResume - Actions:
- Find suspended licenses by subscription ID
- Unsuspend each license
- Update expiry to billing period end
- Result: Licenses reactivated
Customer Creation
When a customer is created:- Event:
customer.created - Handler:
handleCustomerCreated - Actions:
- Create or update user with email and name
- Store Paddle customer ID in user metadata
- Result: User ready for license assignment
One-Time vs. Subscription Products
The integration automatically detects product type: One-time products (no billing cycle):- Store transaction ID in metadata:
paddle_transaction_id - Set
subscriptionIntervalto empty string (perpetual) - No automatic renewals
- Store subscription ID in metadata:
paddle_subscription_id - Set
subscriptionIntervalbased on billing cycle - Automatic renewals on
transaction.completedwith originsubscription_recurring
FAQ
What's the difference between Paddle Classic and Paddle Billing?
What's the difference between Paddle Classic and Paddle Billing?
This integration is for Paddle Billing (the new platform). Paddle Classic is deprecated. If you’re on Paddle Classic, you’ll need a different integration approach.
How are quantity-based purchases handled?
How are quantity-based purchases handled?
The integration creates multiple licenses based on
item.quantity. For example, quantity of 3 creates 3 separate licenses, all linked to the same transaction or subscription.What happens if webhook verification fails?
What happens if webhook verification fails?
The Paddle SDK throws an error and the request is rejected with HTTP 400. Paddle will retry the webhook automatically.
Can I use this for free trials?
Can I use this for free trials?
Yes! Paddle supports trial periods. The integration creates licenses when the trial converts to a paid subscription (transaction.completed event).
How do I handle subscription cancellations?
How do I handle subscription cancellations?
Subscribe to the
subscription.canceled event in your Paddle webhook settings, then add a handler to suspend or delete licenses. The current integration doesn’t handle cancellations by default.Why does subscription_recurring sometimes unsuspend licenses?
Why does subscription_recurring sometimes unsuspend licenses?
Paddle may send different origin values depending on how a subscription is resumed. The integration handles both
subscription_recurring and subscription_update to cover all resume scenarios.Error Handling
All handlers provide detailed error context:- Identify partial successes
- Recover from failures manually
- Debug issues efficiently
Testing
Paddle provides webhook testing tools:- Sandbox mode: Test webhooks in Paddle’s sandbox environment
- Webhook replays: Replay past events from the Paddle Dashboard
- Local testing: Use ngrok or similar tools to tunnel webhooks to localhost