TillpingPre-launch
Menu

Fix guides

Stripe webhook blocked by Cloudflare (403 or "Just a moment")

Short answer: If your domain runs through Cloudflare, Cloudflare checks every request before your app sees it. Stripe is a bot, not a browser. So a bot check, a firewall rule or a challenge page can stop it. Stripe then logs a 403 (sometimes a 503) and your code never runs. Find the Cloudflare feature that stops it, and let only your webhook path through. Keep checking Stripe's signature in your code.

Signs you have this problem

  • Stripe's Event deliveries tab shows 403 or 503 for your endpoint.
  • Your app has no log line for those events.
  • The reply is an HTML page with "Just a moment..." or the word Cloudflare, not your app's own message.
  • Your app is on Vercel, Netlify, Lovable or similar, but your domain's DNS is on Cloudflare with the orange cloud (proxied) on.

Step 1: Check that Cloudflare is the one saying no

Send a test POST yourself and read the headers:

curl -i -X POST https://yourapp.com/api/webhooks/stripe

Look for these lines:

HTTP/2 403
cf-mitigated: challenge
server: cloudflare
cf-ray: 8f1c...

Cloudflare's docs say every challenge page has the cf-mitigated: challenge header. If you see it, Cloudflare answered, not your app.

Your laptop may not get the same answer as Stripe. Cloudflare can treat Stripe's servers as bots and let you through. So also check Cloudflare itself. In the dashboard, go to Security → Analytics → Events. Filter by your webhook path. Each blocked request shows which feature stopped it, in the Service field.

Step 2: Fix it, based on what blocked it

Bot Fight Mode (the free bot setting)

This is the usual cause on the free plan. Cloudflare's docs say you cannot skip Bot Fight Mode with a custom rule or a Page Rule. You have two choices:

  1. Turn it off. Go to Security → Settings, filter by Bot traffic, and turn Bot fight mode off.
  2. Allow Stripe's webhook IPs. Cloudflare says Bot Fight Mode will not trigger if an IP Access rule matches the request first. Add an Allow IP Access rule for each Stripe webhook IP (list below). Be careful: an Allow rule also skips your custom rules, rate limits and managed rules for those IPs.

A custom rule you made (block, challenge, country or network)

Don't delete the rule. Change it so it no longer matches the webhook path. Open the rule, wrap what is there in brackets, and add this at the end:

(your existing expression) and not (http.request.uri.path eq "/api/webhooks/stripe")

Use the exact path from your Stripe settings. All your other rules still protect that path.

Managed rules, Super Bot Fight Mode, rate limits or Browser Integrity Check

Add a custom rule with the Skip action. Keep it narrow: this path, POST only, and only Stripe's webhook IPs.

(http.request.uri.path eq "/api/webhooks/stripe"
 and http.request.method eq "POST"
 and ip.src in {3.18.12.63 3.130.192.231 13.235.14.237 13.235.122.149
   18.211.135.69 35.154.171.200 52.15.183.38 54.88.130.119 54.88.130.237
   54.187.174.169 54.187.205.235 54.187.216.72 35.157.207.129 3.69.109.8
   3.120.168.93})

These are Stripe's webhook IPs as listed on 2026-10-25. Stripe can change them. Copy the current list from https://stripe.com/files/ips/ips_webhooks.txt before you save.

Then tick only what blocked Stripe in Step 1. For example: All Super Bot Fight Mode rules, All managed rules, or Browser Integrity Check. Move the rule to the top of the list. Keep Log matching requests on, so you can see it work in Security Events.

Step 3: Send a test event

In the Stripe Dashboard, open the failed event and click Resend. You want a 2xx, or a 400 from your own code if something else is wrong. Stripe also retries live events by itself for up to three days. Test events in a sandbox are only retried three times over a few hours.

Don't stop checking the signature

Letting Stripe past Cloudflare also lets anyone with that path try. Your code must still check the Stripe-Signature header against the raw body and reply 400 when it does not match. If that check fails, see our guide: Stripe webhook signature verification failed.

Other payment providers

The same thing happens with Lemon Squeezy, Paddle and others. Use the path fix above. Only allow by IP if your provider publishes a list of webhook IPs.

Check it with a free scan

Paste your webhook address into the free Tillping scan: https://tillping.online/#scan. No account is needed. Only scan an address you own or are allowed to test.

It sends a few safe test requests (not real payment events). If the reply has the cf-mitigated header, or is a 403 or 503 "Just a moment" challenge page, the scan says Cloudflare is showing a challenge to bots. If a plain 403 comes back, it shows that too and tells you to make sure real events get through.

Our test comes from a different network than Stripe. So a clean scan does not prove Stripe gets in. Stripe's Event deliveries tab is the final word.

Sources

Run the free check

Paste your webhook address and see what your endpoint answers. No account. No keys.

Check my webhook

Join the early-bird list

Tillping launches soon. Join the early-bird list and we will email you when it's live.

We send one email to confirm. You can leave at any time.