Start monetizing your project ->
Monetizing your app: Paddle payments integration #
Building the product is half the battle. Getting paid is the other, and it arrives with tax tables, subscription states, failed renewals, and fraud. Paddle absorbs that mess as a merchant of record, and BYOB wires it into your app so thoroughly that monetization becomes a build step rather than a second project.
Think of the integration as a cash register that files its own taxes. You define what you sell. The register handles checkout, receipts, global tax, and the paper trail, then taps your app on the shoulder whenever money actually moves.
[!TIP] Try it: Invoice Generator
TLDR #
- Automated reconciliation of products, prices, and client tokens.
- Secure webhook handling to update durable entitlement state in the database.
- Strict separation of Sandbox and Production environments.
How does product syncing stay consistent? #
Copying price IDs from a dashboard into code by hand is slow and breaks silently. BYOB reconciles instead. You define products and pricing tiers, amounts, currencies, billing intervals, and the agent lists existing Paddle products and prices, matches them by stable catalog fields stored in each product's custom_data under a catalog_key, and creates only what is missing. Resulting price IDs (pri_...) and the public client token flow into project environment through secure tooling. No clipboard, no drift.
Idempotency is the property that makes this safe to rerun. Run sync twice and the second pass finds everything already matched, creating nothing. Catalog definitions stay the source of truth while Paddle stays the system of record, and neither role leaks into the other.
How do webhooks update entitlement state safely? #
Payments happen on Paddle's servers. Your app learns about them through webhooks, and BYOB generates the SvelteKit +server.ts endpoints that receive them. SvelteKit gives full control over the response in such API routes, with handlers per HTTP verb, as the routing docs describe. Generated handlers do three jobs in order.
First, they verify the Paddle-Signature header before trusting a single byte. Paddle signs every webhook with HMAC SHA256 using a per-destination secret, and their signature verification guide stresses the two rules that matter: use the raw untransformed request body, and reject timestamps older than five seconds to blunt replays. The generated code follows both.
Second, they act only on events that prove money moved: transaction.paid, transaction.completed, and subscription.activated. Note the trap the original post called out: subscription.created proves provider contact, not customer payment. Gating premium access on creation hands out product for intent. Gate on completion.
Third, they write durable entitlement state to your database, Cloudflare D1 or Supabase, unlocking features instantly. D1 fits this role neatly: serverless SQLite queryable from Workers and Pages with point-in-time recovery, as the D1 docs describe. Entitlement rows updated inside the webhook handler become the single source of truth every later request checks.
Should you start with inline or hosted checkout? #
Conversion lives or dies at the payment step, so BYOB supports both Paddle shapes. Inline checkout embeds the payment frame directly in your pricing page for a continuous branded flow. Hosted checkout redirects to Paddle's pages, better for complex invoicing or mobile flows where Paddle's optimized screens outperform a custom embed.
Paddle's inline checkout guide shows the mechanics: initialize Paddle.js with a client-side token, set displayMode to inline with a frame target, pass items as price IDs with quantities, and listen to checkout events for live totals. Their guide also recommends starting in overlay mode for speed since both modes share the same JavaScript methods, advice worth taking. Ship hosted first, embed later once revenue justifies the polish. Price IDs stay identical across both, so switching costs nothing downstream.
Environment separation #
Test money and real money must never meet. BYOB enforces the split through environment-aware keys: sandbox tokens and price IDs during development and preview, live credentials in production. Paddle's docs recommend building against a sandbox account and switching to live only when ready, with Paddle.Environment.set("sandbox") selecting the mode explicitly. Sandbox and live systems stay fully separate, so a test price ID in production fails loudly instead of charging quietly.
Paddle webhook notification settings must use the deployment URL, not the preview URL. Preview URLs follow the active workspace and shift underneath you. Incoming webhooks need an endpoint that stays put.
The table below picks the checkout shape that fits what you sell.
| Choice | Use it when | Tradeoff to accept |
|---|---|---|
| Hosted checkout | You want to charge this week | Less control over page style |
| Inline checkout | Brand and conversion matter most | More setup and testing |
| One time payment | You sell lifetime access | Revenue lands once |
| Subscription | You sell ongoing value | You manage renewals and churn |
| Trial | You sell confidence | You track expiry and conversion |
Pricing models beyond the first sale #
Once checkout works, packaging decides revenue shape. Stripe's usage-based billing docs catalogue the industry patterns: flat subscriptions, pay as you go, prepaid credit burndown, fixed fees with overage. Paddle supports the subscription and one-time variants natively through its catalog, and BYOB's reconciliation handles the catalog side while webhooks handle state transitions like trials, pauses, past-dues, and cancellations. Design the packaging deliberately. The integration will carry whatever model you choose, but it cannot choose one for you.
Summary #
Monetization stops being a second project when four pieces click together: catalog sync that never duplicates, checkout that matches your brand ambition, webhooks that verify before trusting, and environments that keep play money away from real money. BYOB generates all four around your product definition.
Go from free tier to paid SaaS in an afternoon. The register is already wired. Just stock the shelves.
What we learned building this #
Checkout code lives in SvelteKit server routes under src/routes where endpoints verify provider signatures before touching entitlement state. Sandbox keys stay separate from live keys until launch, mirroring the environment split above. Webhook handlers update durable state first and render receipts second.
Who this is for (and who should skip it) #
This guide helps builders turning a BYOB app into a paid product with real subscriptions. If you are ready to define prices, take cards, and handle renewals, the sync and webhook flow above is your path.
Skip it if your site takes no money yet. Build the product and the audience first, then return here when validation says charge.
- Best for startups turning a BYOB app into paid subscriptions.
- Best for developers wiring checkout and renewal webhooks.
- Best for small business owners defining first prices and trials.