Guides · Free check · $9 fix pack

Guides

Cloudflare is blocking your Stripe webhook (403, challenge page or Access login)

Your domain runs through Cloudflare (orange-cloud proxy). Stripe's event deliveries show a 403, or a 302, and your server logs show nothing. Cloudflare answered before your code ran.

Why it happens

A webhook is a server-to-server POST. Cloudflare's challenges check "whether a visitor to your site is a real human" by evaluating the browser, and a Challenge Page returns "a full HTML page for the user's browser to render and solve" (Cloudflare docs: Challenge Pages). Stripe has no browser. Stripe lists 401, 403 and 405 as what you see "when the destination URL has access restrictions", and says "we consider redirect responses to webhook requests as failures" (Stripe docs: Receive events). So a challenge page (a 4xx in Stripe's log) or a Cloudflare Access login redirect (a 302) is a failed delivery, every time.

Three Cloudflare features do this to webhooks: Bot Fight Mode (free plan), Super Bot Fight Mode or a WAF custom rule with a challenge or block action, and Cloudflare Access in front of the app.

1. Find out which one

curl -i -X POST -H 'content-type: application/json' -d '{}' https://yourdomain.com/api/webhooks/stripe
# Your own code: a 400 (unsigned request rejected).
# Cloudflare challenge: text/html with "cf-mitigated: challenge".
# Cloudflare Access: a 302 to a login page.

A request from your laptop is not scored the same way as Stripe's servers, so a clean curl result doesn't prove Stripe gets through. Security Events and Stripe's delivery log are the real evidence.

2a. Bot Fight Mode (free plan): you can't skip it with a rule

Cloudflare is explicit: "You cannot bypass or skip Bot Fight Mode using WAF custom rules or Page Rules", because it "operates in a separate evaluation pipeline where Skip, Bypass, and Allow actions have no effect" (source). Your options:

2b. Super Bot Fight Mode or a WAF custom rule: add a skip rule

On Pro and above, "custom rules are executed before Super Bot Fight Mode", and a custom rule with the Skip action lets a request "bypass the Super Bot Fight Mode phase" (Cloudflare docs: Super Bot Fight Mode). The same Skip action can skip all remaining custom rules, rate limiting rules and managed rules (Cloudflare docs: Skip options). Scope it to the webhook path and Stripe's webhook IPs, and put it above the rule that challenges:

(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})
Action: Skip -> All remaining custom rules, All Super Bot Fight Mode rules

IP list copied from Stripe's page on Oct 20, 2026. Check the current list before you paste it, or keep it in a Cloudflare IP list.

Skipping a phase doesn't skip products that run outside the Ruleset Engine, such as Browser Integrity Check; those need the "Skip products" option, and Bot Fight Mode can't be skipped at all (source).

2c. Cloudflare Access: add a Bypass application for the webhook path

If the whole app sits behind Access, Stripe gets the login redirect. Cloudflare's documented pattern for an endpoint that must stay public is a separate Access application for just that path, with a Bypass policy; Bypass "disables any Access enforcement for traffic that meets the defined rule criteria" (Cloudflare docs: Access policies). Create an application for yourdomain.com/api/webhooks/stripe with a Bypass policy. Bypass can't use identity selectors like email, but it can use the IP ranges selector, so you can include only Stripe's webhook IPs instead of Everyone. Note that bypassed requests are not logged by Access (source).

3. Keep the signature check, then confirm

Every exemption above lets more traffic reach your code without Cloudflare's checks, so the signature check has to work. Stripe recommends both: "IP allowlisting" and "Signature verification" (source). If you're not sure yours rejects forged events, see can someone fake a Stripe payment.

  1. Resend one failed event from the Stripe Dashboard and check for a 2xx (source).
  2. Check Security Events: no new challenges on the webhook path.
  3. Recover what was missed while it was blocked: Stripe retries live deliveries for up to three days (source), and failed events from the last 30 days can be listed and processed (Stripe docs: Process undelivered events).
Check yours in 10 seconds (free).

Paste your webhook URL. WebhookProof sends 3 harmless test requests and tells you whether Stripe can reach it and whether it rejects unsigned events. If it finds a problem, the $9 fix pack gives you the exact copy-paste fix for your stack (refundable for 14 days).

Run the free check

FAQ

Why does Cloudflare return 403 to Stripe webhooks?

A challenge (from Bot Fight Mode, Super Bot Fight Mode or a WAF rule) needs a browser to solve it. Stripe sends a server-to-server POST, cannot solve it, and Stripe counts the 403 as a failed delivery.

Can I skip Bot Fight Mode for my Stripe webhook path?

Not with a rule. Cloudflare says Skip, Bypass and Allow actions in WAF custom rules or Page Rules have no effect on Bot Fight Mode. Turn it off, or add IP Access rules that allow Stripe's webhook IPs, since Bot Fight Mode does not trigger when an IP Access rule matches first.

How do I let Stripe through Cloudflare Access?

Create an Access application for only the webhook path with a Bypass policy (optionally limited to Stripe's webhook IP ranges). Keep verifying the Stripe signature in your code.

Where are Stripe's webhook IP addresses?

On Stripe's Domains and IP addresses page (docs.stripe.com/ips), under Webhook notifications, also downloadable as text and JSON. Stripe announces changes seven days ahead on its API announce mailing list.

Sources

More guides

Stripe webhook not working? Check these 7 things in order · A customer paid but didn't get access. What went wrong? · No signatures found matching the expected signature for payload · Stripe webhook failing with a 307 or 308 redirect

Last reviewed 2026-10-20. WebhookProof is an independent tool, not affiliated with Stripe, Inc.. Quotes are from the linked documentation.