Revenue Connectors · Paddle
Connect Paddle to Admaxxer
Forward Paddle Billing's transaction.completed webhook to Admaxxer so every subscription, one-off purchase, and renewal shows up in your revenue attribution, blended MER, and cohort LTV. Five-minute setup, signed via the Paddle-Signature header (HMAC-SHA256), visitors stitched via custom_data.admx_visitor_id.
1. Prerequisites
- An active Paddle Billing account (Paddle Classic users should also use Paddle Billing's webhook events).
- The Admaxxer pixel installed on the site that opens Paddle Checkout. See the install index.
- An Admaxxer workspace with the website registered. Your Website ID is at Revenue Settings.
- Permission to create webhook endpoints in the Paddle dashboard (Developer Tools › Notifications).
2. Create a Paddle API key (read-only)
Admaxxer uses a read-only key for transaction lookups during webhook handling. Keep your sensitive secret keys in Paddle.
- In the Paddle dashboard, go to Developer Tools › Authentication › + New API key.
- Name it Admaxxer Revenue Read.
- Permissions: Read transactions, Read subscriptions, Read products. Nothing else.
- Copy the
pdl_live_apikey_...value and paste it into Admaxxer › Revenue Settings › Paddle.
3. Add the webhook endpoint
Paddle Billing sends signed webhook events to a single Admaxxer URL. Replace <YOUR_WEBSITE_ID> with the UUID shown in Revenue Settings.
https://admaxxer.com/api/pixel/webhooks/paddle/<YOUR_WEBSITE_ID>
- In the Paddle dashboard, go to Developer Tools › Notifications › + New destination.
- Description: Admaxxer Revenue.
- Type: Webhook (URL).
- URL: paste your Admaxxer webhook URL.
- Subscribed events:
transaction.completed
- Save. Paddle reveals a signing secret (
pdl_ntfsec_...). - Copy the secret and paste it into Admaxxer Revenue Settings › Paddle › Webhook signing secret.
The signing secret is what makes the Paddle-Signature header verifiable. Without it, Admaxxer rejects every inbound webhook with 401 invalid_signature.
4. Stamp the visitor ID on every checkout
Pass customData on the Paddle Checkout call. The pixel exposes window.admx.getVisitorId():
// Browser-side, when opening Paddle Checkout
Paddle.Checkout.open({
items: [{ priceId: 'pri_01abc...', quantity: 1 }],
customData: {
admx_visitor_id: window.admx.getVisitorId() || ''
},
customer: { email: 'jane@example.com' }
});
Server-driven Subscriptions API
// Node.js — paddle-node-sdk
const txn = await paddle.transactions.create({
items: [{ priceId: 'pri_01abc...', quantity: 1 }],
customData: {
admx_visitor_id: req.cookies['admx_vid'] || ''
}
});
The pixel writes the visitor ID to a 1p cookie (admx_vid) on first page view. Read it server-side when building the Paddle transaction; pass it client-side via window.admx.getVisitorId().
5. Verify the connection
- In Paddle, go to Developer Tools › Notifications, select your Admaxxer endpoint, and click Send test event.
- Choose
transaction.completedand send. - In Admaxxer, open Revenue Settings. The "Last 50 webhook deliveries" panel shows the test with status
ok. - Run a real test purchase in Paddle's sandbox. Inspect the resulting Transaction in Paddle and confirm
custom_data.admx_visitor_idis non-empty. - Within 3 seconds, the order appears in the Admaxxer attribution dashboard, joined to the visitor's acquisition source.
6. Troubleshooting
- Webhook returns
401 invalid_signature - Signing secret mismatch. Re-copy the
pdl_ntfsec_...value from Paddle Notifications into Admaxxer Revenue Settings. Don't paste your API key — only the notification signing secret validates inbound payloads. - Order appears as unattributed
custom_data.admx_visitor_idwas empty on the Transaction. Confirm the pixel fires beforePaddle.Checkout.open()runs. Inspect the Transaction in the Paddle dashboard and check thecustom_datafield.- Subscription renewals not appearing
- Renewals fire
transaction.completed, not a separate event. Confirm your endpoint is subscribed totransaction.completedfor both new transactions and renewals (it's a single subscription that covers both). - Refunds not subtracting from MER
- Add
transaction.updated(withstatus=refunded) to the same endpoint. Admaxxer uses Paddle's status field on the transaction object to detect refunds.
Frequently asked
- Does Admaxxer work with Paddle Classic or only Paddle Billing?
- Paddle Billing is the recommended and best-tested integration. The webhook event names, signing-header format, and custom_data field used for visitor stitching all follow the Paddle Billing API. Paddle Classic users can still wire up a forward-compatible custom webhook, but the official guide is for Paddle Billing.
- Why use Paddle as merchant of record?
- Paddle handles global tax, VAT, and invoicing — you sell SaaS in 100+ countries without registering for tax in each one. Admaxxer joins Paddle's transaction.completed events to your pixel-side acquisition data so the same MER, cohort LTV, and ad-level LTV that you'd get from Stripe-direct also work for Paddle's MoR billing.
- How do I add custom_data on a Paddle Checkout?
- When opening Paddle Checkout via Paddle.Checkout.open(), pass customData: { admx_visitor_id: window.admx.getVisitorId() }. The field propagates to the Transaction record, which is what transaction.completed webhooks include. For server-driven Subscriptions API calls, set custom_data on the Transaction the same way.
- What happens with subscription renewals?
- Each renewal fires its own transaction.completed event with a fresh transaction ID. Admaxxer records each as an independent revenue event but attributes them all back to the visitor who created the original subscription, so cohort LTV correctly reflects the total monthly value.
- How does Paddle-Signature verification work?
- Paddle signs every webhook with HMAC-SHA256 using your endpoint's secret. The Paddle-Signature header carries a timestamp (ts=...) and signature (h1=...). Admaxxer reconstructs the signed payload (timestamp + : + body), HMACs with the secret, and compares constant-time. Mismatches return 401. The 5-minute timestamp window blocks replay attacks.
Next steps
- All revenue connectors — back to the hub.
- Stripe, Lemon Squeezy, Polar, Dodo, WooCommerce, Shopify.
- Install the Admaxxer pixel — required for visitor stitching.
- Analytics docs — how Tinybird pipes consume revenue events.