Webhook Test Events Always Return 403 and Never Hit My Server

Hi everyone,

I’m struggling to get Square webhooks to reach my endpoint. When I send test events like “payment.created” from the Developer Dashboard, Square immediately returns 403 Forbidden and I never see any incoming request in my server logs.

What I’ve verified so far:
• My webhook URL is correctly registered in the Dashboard (including trailing slash).
• A manual curl -X POST to that same URL (with an empty JSON body) returns 200 OK every time.
• I’m tunneling my local server through Cloudflare and the tunnel is active.
• I’m using the exact signature key from my webhook subscription and validating with the official is_valid_webhook_event_signature helper.
• I’ve disabled all authentication, CSRF, and firewall rules on that path to rule out middleware blocking.

Even with logging at the very top of my handler (before signature checks), I see nothing when I send a test event. It’s as if Square never even attempts the delivery.

Has anyone else encountered this behavior when using tunnels or local development environments? Are there any known quirks, extra headers, or Dashboard settings I might be missing? Any pointers would be greatly appreciated—thanks in advance!

:waving_hand: I’m Square Dev AI, here to help answer your question!
Based on the information you’ve provided, the following documentation will help answer your question:

Additional Documentation

Square Developer Tools
Developer Console
Square Sandbox

If this documentation helped you find a solution, please check the box indicating that this reply solves the problem.
Otherwise one of our Developer Advocates will provide additional assistance shortly.

It seems like you’ve done a thorough job of checking the common issues. One thing to consider is whether your server is set up to handle HTTPS requests, as Square webhook notifications require an HTTPS URL. If you’re using a local development environment, you might need to set up SSL on your local server or use a service like ngrok to create a secure tunnel to your local server.

Also, ensure that your server is not blocking POST requests from Square’s IP addresses. Square’s IP addresses are dynamic and can change, so it’s not recommended to whitelist specific IP addresses. Instead, you should validate incoming webhook notifications by checking the signature in the ‘Square-Signature’ header of the request. This signature is generated using your webhook’s signature key, which you can find in the Developer Dashboard.

Lastly, make sure that your server is responding with a 2xx status code within 10 seconds of receiving the webhook notification. If your server takes too long to respond, Square might consider the delivery attempt as failed.

This answer was reviewed by @Bryan-Square.