Skip to main content

Paddle

Paddle

Connect Paddle to see which channel, campaign or page brought each payment — not just how much you earned.

Your Paddle dashboard tells you how much you earned. It cannot tell you which campaign earned it. Connecting Paddle joins the two: a payment arrives, and the dashboard already knows where that visitor came from.

What you get

  • Revenue beside your traffic, in the same date range and the same channels

  • Which channel brought the money — often not the one bringing the visitors

  • New and renewal revenue separately, so growth is not hidden inside recurring income

  • Refunds and chargebacks shown as they happen, and told apart from credits

  • Twelve subscription goals with no code — trials started and converted, renewals, upgrades, downgrades, pauses, cancellations and churn. Each is usable as a filter. See the subscription goals.

Two goals are Stripe-only, and the reason is Paddle's rather than ours. Paddle sends no event before a trial ends, so trial_will_end has nothing to be built from, and it handles 3-D Secure inside its own checkout — reporting only the outcome, which leaves payment_action_required without a counterpart. A declined card still arrives as payment_failed.

Connecting

Create an API key

In Paddle, go to Developer tools → Authentication → API keys and create a new key.

Set it to never expire, and tick exactly three permissions:

PermissionWhy we need it
Transactions (Read)The payments themselves — amounts, refunds, product names
Subscriptions (Read)MRR and churn. A cancelled subscription appears in no transaction, so without this the MRR curve has no churn in it
Notification settings (Write)To register one webhook, so payments reach us as they happen

Paddle ticks Notification settings (Read) for you when you select Write — you cannot grant or withhold it separately, so there is nothing to look for.

An expiring key fails silently. The key form defaults to an expiry date. When a key lapses, webhooks keep arriving and verifying — only the history import and the event-list sync stop, and neither of those announces itself.

screenshot coming

Paddle's new-API-key dialog with the three permissions ticked: Transactions (Read), Subscriptions (Read), Notification settings (Write), and the expiry set to never. Light theme, cropped to the permission list.

Paste it back

In TrueStat, open your site's Settings → Integrations, choose Paddle and paste the key. We check every permission before saving; if one is missing, the screen names it.

screenshot coming

Site settings, Integrations tab: the Paddle card with the API key field and the "Create a key in Paddle" link, before any connection. Light theme, cropped to the card.

Pass the visitor id at checkout

This is the step that makes attribution work. See below — the code depends on which checkout you use.

Linking a payment to a visitor

Without this, payments still appear — but under unattributed, because nothing connects the payment to the visit that led to it.

Our script stores a visitor id in a cookie. Pass it to Paddle as custom_data, and Paddle carries it through — including onto every renewal, which is why renewals stay attributed without any further work.

Which code you write depends on how your checkout opens. Pick the one that matches:

Checkout API

Your server creates the transaction, then hands it to a checkout.

Overlay checkout

Paddle.js opens the checkout in your page.

Other methods

Payment links and anything with nowhere to put custom data.

The field is spelled differently in each. custom_data in the REST API, customData in Paddle.js. Neither rejects the other — the wrong one is ignored, and the payment arrives unattributed with nothing to say why.

What the numbers mean

screenshot coming

The Revenue card with a Paddle connection: total, new versus renewal, and refunds, over the selected range. Light theme, cropped to the card.

Amounts include tax. A $82.50 plan sold into a 20% VAT country is recorded as $99.00, which is what Paddle reports as the transaction total — so the dashboard matches your Paddle dashboard rather than your net-of-tax figure.

Fees are recorded but not subtracted. Each payment carries what Paddle charged and what you earned. The revenue total is the gross, because that is the number Paddle shows you.

A real example, so the three figures make sense together:

Plan price$82.50
VAT (20%, this buyer was in Turkey)$16.50
Total — what the dashboard counts$99.00
Paddle's fee−$5.45
Earnings — what reaches you$77.05

The VAT is not yours: Paddle collects it and remits it. So earnings is the plan price minus the fee, not the total minus the fee — which is why $99.00 − $5.45 does not give $77.05.

New versus renewal is decided by where the money came from, not by the amount:

What happenedCounted as
A first payment through checkoutNew business
A renewalRenewal
An upgrade's prorated differenceRenewal — the customer already existed
An add-on charged to a subscriptionRenewal — same reason
A one-off purchase with no subscriptionNew business

An upgrade charges the difference, not the full new price. Moving from $24 to $99 halfway through a month bills about $37.50 — the remaining half of the $75 gap. That is the amount you see, and it counts as renewal revenue because the channel that won that customer had already won them.

A credit is not a refund. Paddle can apply a credit that covers an invoice entirely, leaving the customer paying nothing while the revenue is still real — the money arrived earlier, when the credit was issued. Those payments appear at their full value, and only actual refunds and chargebacks reduce your total.

Unpaid invoices are not revenue. A transaction Paddle has issued but not collected does not appear at all. If it is later paid, it appears then; if it is cancelled, it never does.

Your history comes with you

When you connect, we import what Paddle already has: your completed transactions and your live subscriptions, however far back they go. The panel shows the import running and the numbers fill in as it works.

screenshot coming

The Paddle card while the history import is running: the progress line naming how many payments have been imported so far. Light theme, cropped to the card.

What imported payments can and cannot tell you

They carry their attribution. This is a real advantage Paddle has: because custom_data lives on the transaction itself, a payment imported from a year ago still knows which visitor bought it, and appears in your channel breakdowns. Imported Stripe payments cannot do this — Stripe keeps checkout metadata on an event, and those expire after 30 days.

Plan changes in between are not recovered. We import when a subscription started and, if it happened, when it ended. The upgrades and downgrades in between are events, and Paddle's event stream keeps 90 days — so an upgrade from last year cannot be read by anyone.

Re-syncing later

If the numbers look wrong, or you want to pull history again after fixing something at Paddle, press Re-sync history.

screenshot coming

The connected Paddle card showing the last import's summary and the "Re-sync history" link. Light theme, cropped to the card.

Re-syncing never double-counts. A payment already imported is recognised and not written again, so your total does not move however many times you press it. What a re-sync does fix is a payment that is missing information — a fee it did not have, or a classification that has since been corrected.

Reading revenue in another currency

If your Paddle account settles in one currency and you would rather read the dashboard in another, pick it in the panel. Amounts are converted at today's rate for display, and stored in your account currency — so the total moves with the exchange rate, and the underlying figures keep matching Paddle.

Disconnecting

Disconnecting removes the webhook from your Paddle account and deletes the revenue collected so far from this dashboard. Your Paddle data is untouched.

Your traffic is untouched too: pageviews, sessions and your own goals stay exactly as they are. Only the payments, the subscription state and the subscription goals go.

If something is not working

Payments appear as unattributed. The checkout is not passing custom_data, or it is passing it under the wrong spelling — customData for Paddle.js, custom_data for the API. Open a recent transaction in Paddle and look for the field; if it is empty there, it never reached us.

The key was rejected on connecting. The screen names the missing permission. If it says the environment does not match, the key is a sandbox key on a live deployment or the reverse — the prefix tells you which: pdl_live_apikey_… against pdl_sdbx_apikey_….

Nothing arrives after connecting successfully. Check Notifications → Notification destinations in Paddle: ours is called "TrueStat — revenue attribution" and should be active. If it is missing, the key lost its write permission after connecting; reconnecting recreates it.

The MRR figure looks low. A subscription only counts toward MRR while it is active or past due. Trials count as pending rather than as revenue, and a cancelled subscription stops counting the day it actually ends rather than the day the cancellation was scheduled.

Was this page helpful?

Last updated September 8, 2026