Receive Square Webhooks Locally (Test Square Webhooks on localhost)

Receive Square webhooks locally and test them on localhost without deploying. Inspect the real payment.created payload, forward to your handler, and verify the HMAC signature.

You are building a Square integration — recording a sale, fulfilling an order, reconciling a refund — and you need to see your handler react to a real payment.created or order.updated event. The problem is immediate: Square will only POST to a public URL, and your handler is running on localhost:8080. Square has no way to reach it.

The usual workarounds are painful. Deploying to a staging server for every code change is slow. Pasting payloads from the docs into curl gives you a guess at the real request, not the real headers and body Square actually sends. What you want is to receive Square webhooks locally — real events, hitting your local handler, with a URL that does not change every time you restart.

This guide shows how to do exactly that.

Why receiving Square webhooks locally is tricky

A webhook is just an HTTP request that Square sends to a URL when something happens in a seller's account. Square sits on the public internet; your dev machine usually does not. It is behind a router, a corporate firewall, or both, with no public IP and no inbound ports open.

So you need something in the middle: a public endpoint Square can hit, that relays each request down to your laptop without you opening a single firewall port. That is what Webhook Relay does — and unlike a random tunnel URL, the endpoint is stable, so you configure Square once and never touch it again.

Step 1: Inspect the real payload with Webhook Bin

Before you write any handler code, find out what Square actually sends. Open the free Webhook Bin — no signup — and you get an instant public URL.

  1. Copy the Webhook Bin URL.
  2. In the Square Developer Dashboard, open your application and go to Webhooks → Subscriptions → Add Subscription (or Add Endpoint).
  3. Paste the URL into Notification URL, choose the API version, and select the event types you care about — for example payment.created, payment.updated, order.updated, refund.created, or invoice.payment_made.
  4. Save the subscription.

Now click Send Test Event and pick an event type. Square immediately fires a sample notification, and you will see it land in Webhook Bin right away. Inspect the captured request: the full JSON body (with its merchant_id, type, event_id, and nested data.object), and every header, including x-square-hmacsha256-signature and square-environment.

Now you know the exact shape of the data before writing a line of code. For more on this approach, see How to test webhooks and What is a webhook.

Step 2: Forward the events to localhost with the relay agent

Once you know the payload, route those same events into your local handler. Sign up for Webhook Relay, install the relay agent (CLI or Docker), and create a bucket — say square. The bucket gives you a stable public input endpoint.

Start forwarding to your local server:

relay forward --bucket square http://localhost:8080/webhook

The agent opens an outbound connection to Webhook Relay and streams every incoming request down to http://localhost:8080/webhook. Because the connection is outbound, there are no firewall ports to open and no public IP needed — this works from your laptop, behind a corporate proxy, or inside a Kubernetes cluster. Running in Docker? The same command works in the official webhookrelay/webhookrelayd image. Full details are in the localhost forwarding docs.

Now update the subscription's Notification URL to your Webhook Relay endpoint (or just create it there from the start). Hit Send Test Event again — or trigger a real action in the sandbox — and watch it arrive on localhost.

Square-specific configuration and quirks

A few Square details worth knowing:

  • Where to add it: webhook subscriptions live in the Square Developer Dashboard → your application → Webhooks → Subscriptions. Each subscription has its own notification URL, event list, and signature key.
  • Sandbox vs production: Square keeps separate credentials and subscriptions for the Sandbox and Production environments. Test against the sandbox first, then move the subscription to production — the signature key is different per environment, so update your handler's config accordingly. The square-environment header tells you which one sent the request.
  • Event types: subscribe to exactly the events you handle (payment.created, order.updated, refund.updated, customer.created, and so on). Branch on the type field in the JSON body rather than parsing the path.
  • Send Test Event: the dashboard's Send Test Event button delivers a representative payload for any subscribed event type without needing to actually take a payment — perfect for wiring up and debugging your handler.
  • Retries: if your endpoint does not return a 2xx quickly, Square retries with backoff. Returning 200 fast and processing asynchronously keeps deliveries clean.

Step 3: Verify the Square webhook signature

Square signs every notification. It computes an HMAC-SHA256 over the notification URL concatenated with the raw request body, using your subscription's signature key, then base64-encodes the result and sends it in the x-square-hmacsha256-signature header.

That URL-plus-body detail trips people up: you must use the exact notification URL configured on the subscription and the raw, unparsed request body (no re-serialized JSON, no added whitespace). Find the signature key under Webhooks → Subscriptions → your endpoint → Show (in the Signature Key box). Recompute the digest and compare in constant time before trusting the payload.

To sanity-check your implementation, paste a captured body, your signature key, and the received signature into the free HMAC signature verifier. For language-specific code and the common pitfalls (reading the body after a JSON parser has consumed it, forgetting to prepend the URL, timing-safe comparison), read Verify a webhook signature.

Replay and iterate

This is where local development gets fast:

  • Replay from Square by hitting Send Test Event again, or by re-triggering an action in the sandbox.
  • Replay from Webhook Relay — past requests are stored on your bucket, so you can resend a captured event without touching Square at all.
  • Iterate on your handler by editing code and replaying the same delivery until it behaves correctly. No commits, no pushes, no deploys just to test a code path.

Because the Webhook Relay endpoint is stable, you can stop and restart the agent, reboot your machine, or come back next week — the Square configuration never needs to change.

Get started

  1. Inspect the real payload in the free Webhook Bin — no signup needed.
  2. Create a Webhook Relay account, install the agent, and run relay forward --bucket square http://localhost:8080/webhook.
  3. Point your Square subscription's Notification URL at the stable endpoint, click Send Test Event, and watch it hit localhost.

You will be testing real Square events against your local handler in a few minutes — no deploys, no open firewall ports, and a URL you configure exactly once.