MenuPaddle

Revenue attribution

Paddle

Connect Paddle Billing with a read-only API key and a notification destination so ProductLense records transactions and adjustments net of Paddle's cut.

ProductLense reads your Paddle Billing customers, subscriptions, completed transactions and adjustments. Paddle is a merchant of record, so ProductLense records what the customer paid and treats everything Paddle keeps (its fee and the tax it remits) as the fee. ProductLense only reads: it never writes to your Paddle account, never refunds, cancels or changes anything.

What you need

FieldSecretWhere to find it
API keyYesPaddle → Developer tools → Authentication.
Webhook secret keyYesThe pdl_ntfset_... secret shown when you create the notification destination pointing at ProductLense.

Every plan includes one billing connection per site, Free too; Growth and Scale allow any number. See plans and limits.

Permissions

The API key needs read access to customers, subscriptions, transactions and adjustments. ProductLense calls GET /customers, /subscriptions, /transactions and /adjustments and nothing else.

Set up

  1. In Paddle, open Developer tools → Authentication and create an API key with read access to the four resources above.
  2. In ProductLense, open your site's Settings → Billing connections → Paddle, paste the key and click Connect and import history.
  3. Copy the webhook URL from the connection card.
  4. In Paddle, open Developer tools → Notifications → New destination, paste the URL and subscribe to the events below.
  5. Copy the destination's secret key into the Paddle connection in ProductLense.

Webhook

URL: https://api.productlense.app/api/webhooks/paddle/<connection-id> (ProductLense shows the exact URL after you save).

Events ProductLense uses:

  • transaction.completed, transaction.updated
  • adjustment.created, adjustment.updated
  • subscription.created, subscription.updated, subscription.canceled, subscription.activated, subscription.paused, subscription.resumed, subscription.past_due
  • customer.created, customer.updated

Verification: the Paddle-Signature header (timestamp plus h1 HMAC-SHA256 with your secret key). Deliveries older than 5 minutes are rejected.

What ProductLense reads

  • Customers: email, name and custom data.
  • Subscriptions: status, billing interval and amount.
  • Payments: completed transactions.
  • Refunds and chargebacks: refund and chargeback adjustments.
  • History: the last 12 months on first connect, then a nightly reconcile at 03:00 UTC from the last sync minus 48 hours.

How fees are derived

Text
fee = grand_total − earnings

That is Paddle's fee plus the tax it collects and remits, so net revenue equals what Paddle pays out to you. When a transaction has no earnings figure, ProductLense uses Paddle's fee plus tax. Refund and chargeback adjustments are netted at your earnings share, and a chargeback adds its chargeback fee, so a full refund cancels the original charge exactly. Fees are reported by Paddle, not estimated.

Match payments to visitors

ProductLense reads the user id from the customer's custom_data: pl_user_id, user_id, userId or uid. Use the same id you pass to identify. A ProductLense visitor id in pl_visitor_id or visitor_id is also accepted. Without either, ProductLense falls back to the customer email, matched to the email trait sent with identify, or to a user id that is that email.

When you create the Paddle customer (Node, Paddle API)
await fetch('https://api.paddle.com/customers', {
  method: 'POST',
  headers: { Authorization: `Bearer ${process.env.PADDLE_API_KEY}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({
    email: user.email,
    custom_data: { pl_user_id: user.id },
  }),
});

See how payments are attributed.

    ↑ ↓ to move, Enter to open