Answer first, get paid without hand-wiring billing #
Paddle Billing is a merchant-of-record platform that handles global taxes, subscriptions, and invoicing for SaaS products. As stated in the Paddle developer docs (https://developer.paddle.com/), Paddle acts as merchant of record across 200 plus countries, taking on tax calculation and remittance so sellers do not build that machinery per market. BYOB integrates with it natively so you can move from a free tier to paid plans without manually copying price IDs, building signature checks from scratch, or mixing test payments with real money.
The integration has four load-bearing parts. Products and prices reconcile idempotently through catalog keys. Checkout works inline or hosted. Sandbox and production stay strictly separated. Webhooks verify authenticity and update durable entitlement state only when payment really happened.
This post is a learn/define explainer of the merchant-of-record concept and how the four integration parts fit. If you want the do/procedural steps instead — reconcile the catalog, launch checkout, and verify webhooks — see Monetizing Your App.
Think of Paddle as a cashier who also files your taxes. The cashier takes the money, prints the receipt, and handles the paperwork with every jurisdiction your customers live in. Your app just needs to hear the till ring, confirm the ring is genuine, and unlock the door. Everything below is about hearing that ring reliably.
What does merchant of record mean for a BYOB SaaS? #
A merchant of record is the seller on the transaction: Paddle Billing acts as merchant of record across 200-plus countries per the Paddle developer docs, taking on tax calculation, remittance, subscription renewals, and invoicing. Scope: BYOB integrates Paddle natively so checkout and webhook reconciliation work without weeks of manual billing code. Constraint: the merchant-of-record model trades control for coverage.
Building the product is half the work. Collecting money across countries, handling subscription renewals, and issuing invoices is the other half. A merchant of record takes on that sales layer so your app does not need bespoke tax, subscription, and invoicing logic for every market. The distinction matters legally: the merchant of record is the seller on the transaction, which is why tax compliance travels with the platform instead of landing on your startup.
In BYOB, that shows up as an agent-assisted flow. You define products and pricing tiers with amounts, currencies, and billing intervals. The agent lists existing Paddle products and prices, reuses matches by stable catalog fields, and creates only what is missing. The resulting price IDs and the public client token are written to project environment through secure env tooling. There is no manual copy-paste from a dashboard into code, which means no stale IDs drifting between your pricing page and your billing backend.
That reconciliation is idempotent because it is driven by a catalog key stored in each product's custom data. Running sync twice does not duplicate products. It converges on the same catalog. Sync is a stamp, not a printer: pressing it again deepens the same impression instead of making a second page.
| Checkout | Placement | Strength | Tradeoff |
|---|---|---|---|
| Inline overlay | Inside your pricing page | Seamless flow | You handle edge cases |
| Hosted page | Redirect to Paddle | Handles complex invoicing | Leaves your page |
| Sandbox | Preview and local dev | Safe testing | Not real money |
| Production | Deployment URL | Real charges | Needs verified webhook |
How do subscription plans avoid ID sprawl? #
Avoid subscription ID sprawl in BYOB in 3 steps: declare tiers once in a catalog with amounts, currencies, and intervals, let the agent reconcile against existing Paddle products by stable catalog fields, and persist canonical IDs to environment state. Prerequisite: a product catalog treated as source of truth. Constraint: never hand-copy price IDs from dashboards into code, since one stale ID breaks upgrades silently.
Manually threading price IDs through pricing pages, checkout buttons, and entitlement checks is tedious and error-prone. One stale ID breaks upgrades silently, and silent breaks in billing are the most expensive kind because customers experience them as betrayal.
The BYOB pattern avoids that by treating your declared catalog as the source of truth. The agent compares declared tiers against what already exists in Paddle, matches on stable fields rather than display names alone, and persists the canonical IDs back into environment state. Your pricing page, checkout calls, and server checks then read the same reconciled values. The full loop is documented in the monetization guide (https://byob.studio/blog/byob-paddle-payments).
This is payment orchestration at the catalog layer. Product definition, provider state, and app environment stay aligned through repeated runs instead of drifting after every pricing edit. Change a price once in the catalog, sync, and every surface follows.
How does inline versus hosted checkout compare? #
Choose inline Paddle checkout in BYOB for simple self-serve upgrades where friction is the enemy, and hosted checkout for complex invoicing or mobile flows where Paddle's page handles edge cases better. Both end in the same server-side truth: entitlement is granted only when a verified webhook confirms payment. Constraint: checkout is the front door, never the deed registry.
Conversion and complexity pull in opposite directions, so BYOB supports both Paddle checkout shapes. Try it: Invoice Generator
Inline checkout embeds the checkout UI directly in your pricing page. The buyer never leaves your flow, which suits simple self-serve upgrades where friction is the enemy. Paddle's overlay checkout docs (https://developer.paddle.com/build/checkout/build-overlay-checkout) describe the embedded shape: Paddle.js renders the checkout inside your page while Paddle still processes the transaction as merchant of record.
Hosted checkout redirects to a Paddle-hosted page. That suits complex invoicing or mobile flows where Paddle's hosted experience handles edge cases better than an embedded form. Localization, tax display quirks, and payment method variety all come free with the hosted page.
Both paths end in the same server-side truth. The browser experience differs, but entitlement is never granted by button clicks alone. It is granted when a verified webhook confirms payment and the database updates. Checkout is the front door. The webhook is the deed registry.
How do webhook verification and durable entitlement work? #
When a user upgrades, money moves on Paddle's servers. Your app learns about it through a webhook that must grant access. That callback is also the attack surface, so BYOB generates server webhook endpoints that do three jobs in order.
First, they verify the provider signature to prove the payload really came from Paddle. Every Paddle webhook carries a Paddle-Signature header with a timestamp and one or more signatures. As stated in Paddle's verification docs (https://developer.paddle.com/webhooks/about/signature-verification), you rebuild the signed payload from timestamp plus raw body, compute HMAC-SHA256 with the endpoint secret, and compare against the header value, rejecting mismatches outright. The SDK helpers also check the timestamp to blunt replay attacks. A sketch of the manual path:
// Paddle webhook endpoint: verify first, trust later
import crypto from 'node:crypto';
function verifyPaddle(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(';').map(s => s.split('=')));
const signed = `${parts.ts}:${rawBody}`;
const expected = crypto.createHmac('sha256', secret).update(signed).digest('hex');
const actual = (parts.h1 || '').trim();
return actual.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(actual), Buffer.from(expected));
}Second, they parse only completion events as proof of payment: transaction paid, transaction completed, and subscription activated. Subscription creation alone does not count, because it proves provider contact rather than customer payment. This ordering mistake is the single most common billing bug in new SaaS apps, and it is entirely avoidable once you know the event taxonomy.
Third, they update durable entitlement state in your database, so premium features unlock instantly and survive restarts. Durable matters. Entitlement kept only in memory or client state disappears or can be forged. Entitlement written to the database after a verified event becomes the consistent gate your routes and components can check.
How do sandbox and production stay separate, and what is the deployment-URL rule? #
Mixing test payments with real money causes the worst billing bugs. BYOB enforces environment separation through environment variables and key management. Local development and preview branches route to the Paddle Sandbox. Production uses the real keys. Never share keys across that boundary, and never let a developer guess which environment a key belongs to. Names should scream their environment.
The operational rule that breaks most first setups is endpoint stability. Paddle webhook notification settings must use the deployment URL, not the preview URL. Preview URLs follow the active workspace and are not stable endpoints for incoming webhooks. The deployment URL is the stable address Paddle can reliably call back. Treat that as a launch checklist item alongside signature verification and completion-event parsing. If upgrades work in testing but never unlock in production, the endpoint and environment mismatch is the first place to look.
Test the full loop in sandbox before touching production: create the product, run checkout with a test card, watch the webhook arrive, confirm entitlement flips in the database, then promote. Billing you have rehearsed is billing you can trust.
How do you go from free tier to profitable without billing boilerplate? #
Monetization with this stack compresses to a repeatable loop. Declare subscription plans once. Let the agent reconcile products and prices idempotently. Offer inline checkout for seamless upgrades or hosted checkout for complex invoices. Keep sandbox and production keys separated. Verify webhook signatures, accept only real payment events, and write entitlement durably.
Done in that order, billing stops being weeks of integration work and becomes part of the normal build rhythm: define the offer, sync the catalog, test in sandbox, deploy, and let verified webhooks unlock value automatically. Revisit pricing quarterly with the same loop. Catalog keys make price changes as safe as the first sync, and sandbox lets you rehearse new tiers before customers see them. Billing stays boring, which is exactly what money infrastructure should be. Your first paid tier can be live before the week ends. The cashier handles the money and the paperwork. You handle the product. Everybody works the job they are good at.
Who this is for (and who should skip it) #
Paddle Billing in BYOB fits founders selling SaaS globally without hand-wiring tax, invoicing, and renewal logic per country. Pick a different route if you must own the full billing stack or need a provider BYOB does not natively sync. Limit: merchant of record trades control for coverage.
This fits if you want to sell a BYOB SaaS globally without building tax, invoicing, and renewal logic per country. Native Paddle checkout plus webhook entitlement keeps the app lean.
Pick a different route if you must own the full billing stack or need a provider BYOB does not natively sync. Merchant of record trades control for coverage.
- Best for founders selling SaaS without hand-wiring tax, invoices, and renewals across countries.
- Best for developers syncing products idempotently with inline or hosted checkout.
- Best for freelancers separating sandbox tests from production money with verified webhooks.
What we learned building this #
Paddle billing in BYOB syncs products idempotently through catalog keys in custom data and writes canonical price ids and the public client token to project env, so pricing pages and checkout read the same values. The subscription settings and the Paddle integration guide (https://byob.studio/blog/byob-paddle-payments) document inline and hosted checkout plus webhook verification that updates durable entitlement only on transaction paid events. Sandbox and production stay separated through distinct env vars, and notification settings use the deployment URL rather than preview URLs.