You do not write a webhook. Result receives every payment event, verifies
its signature, handles retries and out-of-order delivery, and writes the
result into
billing_customers and billing_subscriptions in your own
backend. Those tables already exist. Do not create them, do not write to
them, and do not build a payment webhook endpoint.Pricing page
formattedTotal is display-ready. Paddle accounts localize it
to the visitor’s country with tax applied; connected Stripe accounts format
the price and currency stored in Stripe. Server-side you get amount and
currencyCode to format yourself.
Checkout
PAYMENTS_SIGN_IN_REQUIRED rather than opening a checkout, because a payment
with no user attached can never grant access and there is no way to repair it
after the money has moved. Send buyers through sign-in first.
Gating features
active, trialing and past_due. past_due
means a renewal payment failed and automatic recovery is under way, which
usually succeeds. Show a banner linking to the billing portal rather than
cutting the customer off:
Managing a subscription
Portal links are single-use and short-lived. Mint one per click, open it in a
new tab, and never cache or iframe it. Changes a customer makes there arrive
back in your database on their own.
changePlan() exists.
It bills the difference immediately, prorated to the minute.
Test mode
Test-mode accounts use test cards, never a real one:
Any future expiry and any name work.
Paddle accounts go live with the switch in Finance > Payments. Stripe accounts
connect the live Stripe account from Payments > Settings. Your running app
follows the account connection, so neither path needs an app environment
variable change or redeploy.
Before you can go live
Paddle’s merchant-of-record setup requires three pages, publicly reachable without a login:- Terms and conditions, stating that Paddle.com is the reseller and Merchant of Record for all orders.
- A refund policy with a window between 14 and 90 days.
- A privacy notice.
Reading the tables directly
Useful for dashboards and joins:billing_customers, billing_subscriptions and billing_plans are
read-only to signed-in users and scoped to their own rows.