Preview Hostnames Are Not Webhook Endpoints
You wire Polar (or Stripe) to a Vercel preview URL. Sandbox checkout looks green. The paid webhook lands. You merge the PR feeling done.
A day later the next push replaces that preview hostname. Provider UI still shows the old endpoint as configured. Your production app never sees the event. Buyers pay. Entitlements stay locked.
That success story was a trap.
Why preview URLs fail as webhook targets
Vercel preview deployments get fresh hostnames. A URL like myapp-git-feature-team.vercel.app is not a stable public origin. It dies when the deployment is replaced, when the branch is deleted, or when a newer preview takes its place.
Payment providers do not chase your latest preview. They keep calling the exact URL you registered. When that hostname is gone, you get 404s, timeouts, or silent misses while the dashboard still looks "set up."
Checkout can still succeed. The browser flow does not need your webhook. Entitlements do.
Sandbox org plus preview hostname is a double miss
Two mistakes often stack:
- You registered the webhook on the sandbox org while your live product uses the production org.
- You pointed even the right org at an ephemeral preview hostname.
Wrong secret plus dead hostname means your handler never verifies a real live event. Fix one without the other and you still go live blind.
What to register instead
Register a stable production origin only:
https://your.domain/api/webhooks/polar
Use your real custom domain (or a long lived production *.vercel.app production alias you control), not a PR preview. Point Polar live webhooks at that path. Keep the live webhook secret in Vercel Production env only.
For sandbox, use a separate sandbox endpoint and a separate sandbox secret. Do not reuse the live secret on a preview URL "just for a quick test."
How to test without ephemeral previews
Local and PR work still needs a reachable URL. Prefer one of these:
- Polar CLI, a tunnel, or a local forward that you start on purpose for that session.
- A dedicated staging subdomain you own (
staging.your.domain) that you redeploy on purpose. - A long lived preview alias you treat as staging, not the auto generated git branch hostname.
Never paste the auto generated PR preview URL into the provider webhook settings and walk away.
Checklist before go live
Before you treat Polar as production ready:
- Live access token only on the server (never in
NEXT_PUBLIC_vars). - Live product IDs in Production env.
- Live webhook secret in Production env, matching the provider live endpoint.
- Webhook URL is your stable production origin path.
-
success_urland cancel URL point at production routes buyers can reopen. - After any env edit on Vercel, trigger a fresh Production deploy so the running app actually sees the new values.
Pair this with the earlier notes on expired checkouts (abandoned carts are not declines) and sandbox versus live webhook secrets.
Soft sell
If you want a small lab to practice sandbox and live webhook shapes offline, Dual Mode Webhook Lab is $14.
If you want a longer go live checklist for Next.js on Vercel with Polar checkout, webhook, and entitlement notes, the Next.js / Vercel Production Launch Kit is $19.
Support: gumbosveins@gmail.com
More in this series
- The Next.js / Vercel production env mistakes that break launches
- Polar sandbox vs live webhooks: why checkout works and entitlements do not
- Build a Vercel env matrix offline before you merge
- Stop pasting Polar webhook secrets into online signature debuggers
- The Checkout Is Not the Entitlement
- Polar Access Tokens Do Not Belong in NEXT_PUBLIC_
- Expired Polar Checkout Sessions Are Not Failed Payments
Top comments (0)