deniz.in

Markets

Weather

Loading weather

· via dev.to (home feed)

Paddle's approved-domain check only gates the browser checkout, not server-side billing

A dev.to post finds Paddle's approved-domain list gates only the browser checkout overlay, not webhooks or API sessions, letting one billing account serve many sites.

Paddle's approved-domain check only gates the browser checkout, not server-side billing

What the approved-domain list actually covers

A developer writing on dev.to has documented a finding about Paddle's billing platform that reshaped how they handle payments across a portfolio of small products — browser extensions, SaaS tools and a game, each on its own subdomain. Their working assumption had been that every site collecting money needed its own entry on Paddle's approved-domain list, implying a review cycle for each new subdomain.

According to the post, the list gates far less than that. It controls where the Paddle.js checkout overlay can run in a browser, and nothing else. The author lists three server-side operations that carry no domain check at all: verifying webhook signatures, opening a customer portal session with the API key, and the merchant's own endpoints that receive forwarded events. Across the whole payment flow, only the opening of the checkout overlay is tied to an approved domain.

One webhook for every product

That discovery let the author collapse billing into a single setup: one Paddle account, one approved domain at the apex, and one webhook endpoint on that apex serving the entire product family. The endpoint verifies Paddle's signature, reads a single field identifying the originating site, and routes accordingly — events for the apex are handled locally, events for other sites are forwarded to them untouched, and events naming an unknown site are answered with a 200 and dropped. The author learned the last rule the hard way: replying with a 500 puts the provider into a retry loop whose backoff you will tire of first.

Two constraints keep the design clean. The dispatcher holds no knowledge of price IDs or plans — mapping prices to entitlements stays in whichever site owns the event — so adding a product never means editing shared code. Each satellite site exposes a single internal endpoint, protected by a shared bearer secret compared with timingSafeEqual, that accepts a forwarded event without re-verifying Paddle's signature, since the apex already did. Superseded direct webhook routes were left as stubs returning 410, so stale dashboard configurations fail visibly instead of limping along.

Handing checkout to the apex domain

A satellite cannot open the checkout overlay on its own unapproved domain, so it redirects instead. It signs a short-lived payload — the satellite's identity, a local user ID, email, line items with price IDs and quantities, the environment, a success URL, an expiry no more than five minutes out, and a nonce — as base64url-encoded JSON plus an HMAC-SHA256 tag, then sends the buyer to the apex with a 302. The apex verifies the token and opens the overlay with exactly its contents.

The author singles out the details that make this safe. The success URL is validated against a host allowlist, because a signed but unvalidated redirect target becomes an open redirect that looks trustworthy. The environment flag travels inside the token, so the apex selects its sandbox or production client token based on what the token says rather than its own runtime — otherwise a sandbox test could eventually surface as a real charge. Nonces are not stored server-side; the author argues genuine replay protection comes from webhook idempotency keyed on event ID, which already exists downstream. Subscription management mirrors the pattern: satellites sign a payload with customer and subscription IDs, and only the apex — the sole holder of the API key — creates the hosted portal session, so there is a single secret to rotate rather than one for each site.

The costs of consolidation

The trade-offs are commercial rather than technical. The parent account is the merchant of record for every product, so checkout pages, invoices and receipts all carry the parent's name, with no way to white-label them away. Products cannot present themselves as independent companies; the handoff has to read honestly as one shared checkout for a group of related products. The author also admits a smaller wart: two satellites spell their environment selector variables differently, and nothing in the system detects the inconsistency before it causes confusion.

Why it matters

For merchants, the practical lesson is that Paddle's approved-domain list is a browser-presentment control, not a server-side enforcement boundary. Anyone treating it as a gate on where billing traffic may originate is relying on the wrong line of defence. The protections that matter in this setup are the ones the author built themselves: signature verification at a single trusted point, short-lived signed handoffs, allowlisted redirects and centralised key custody. The broader takeaway from the post is to check precisely what a vendor's restriction covers before designing around it — the author spent months routing around a review process that, in the end, touched only a single line of browser code.

  • #paddle
  • #payments
  • #webhooks
  • #billing
  • #security

Related posts