Skip to content
TryWebhook
New URL

Payments · Free · No signup

Test and debug Square webhooks

Point a Square webhook subscription at a throwaway URL, take a sandbox payment, and read the delivery as it arrived — including the signature that covers the notification URL as well as the body.

No signup · No email · Ready in about a second

At a glance

Square webhooks in brief

Category
Payments
Where to configure
Square Developer Dashboard → your application → Webhooks → Subscriptions
Signature header
x-square-hmacsha256-signature
Secret
Signature key (shown on the webhook subscription)
Retries
Retried with exponential backoff over the following hours. Failed events are listed in the Developer Dashboard's Webhooks log and can be resent from there.
Response deadline
10 seconds.
Treated as success
Any 2xx. Square records everything else as a failure and schedules a retry.

Cross-checked against Square's own webhook documentation. Providers change these; if something here is stale, tell us.

The payload

What Square actually sends

Shape-accurate, with obviously fake identifiers. These are the same samples the inspector's Send test webhook panel fires, so you can read one here and then send the identical bytes to your own URL.

POST/w/{your-bin-id}523 B

Square signs the notification URL together with the body.

3 headers
square-environment
Sandbox
square-initial-delivery-timestamp
2026-06-15T10:04:00.000Z
user-agent
Square-Webhooks/1.0
Body · application/json · 1 line
{"merchant_id":"MLFAKEMERCHANT01","type":"payment.updated","event_id":"00000000-1111-2222-3333-444444444444","created_at":"2026-06-15T10:04:00.000Z","data":{"type":"payment","id":"FAKEPAYMENTID0000000000","object":{"payment":{"id":"FAKEPAYMENTID0000000000","status":"COMPLETED","source_type":"CARD","amount_money":{"amount":2900,"currency":"USD"},"location_id":"LFAKELOCATION01","order_id":"FAKEORDERID000000000000","created_at":"2026-06-15T10:03:58.000Z","updated_at":"2026-06-15T10:04:00.000Z","receipt_number":"FAKE"}}}}

No sample carries a signature header. A valid one can only be produced with your own signing secret, and a fabricated one would make the Signature tab report a mismatch that isn't real. Send a genuine delivery when you want to test verification.

Verification

Verifying a Square signature

Signed payload

A base64 HMAC-SHA256 over the notification URL concatenated directly with the raw request body, keyed with the subscription's signature key. The URL is part of the signed data, which is unusual.

Implemented as: Configure the header, hash, encoding, and signed-payload template yourself.

Square has no dedicated tab, but its scheme is expressible in the Custom HMAC tab. Configure it like this:

Header name
x-square-hmacsha256-signature
Hash
SHA-256
Encoding
base64
Signed payload
https://trywebhook.com/w/YOUR-BIN-ID{body}

Replace `YOUR-BIN-ID` with the id from your own webhook URL. Square signs the notification URL exactly as configured — if you registered a trailing slash or a query string, include it here too, or the digest will not match.

Square has no dedicated tab because its signed string starts with the notification URL, which is different for every bin. The Custom HMAC tab handles it — set the signed payload to your own bin URL immediately followed by `{body}`, using the exact URL you gave Square, including the scheme and any query string.

Events

Events worth subscribing to first

Not the full catalogue — the handful that carry most integrations. Subscribing to everything is the fastest way to a handler that times out.

EventFires when
payment.updatedA payment changed state. Fires for `APPROVED` and again for `COMPLETED`, so read `data.object.payment.status` rather than assuming the event means paid.
order.createdAn order was created, from any source — online, point of sale, or the API.
invoice.payment_madeAn invoice was paid, in full or partly. `invoice.updated` also fires, with less specific information.
refund.updatedA refund changed state. `COMPLETED` is the one that means the customer has their money.
subscription.updatedA Square subscription changed plan, status, or billing anchor.

Creating a subscription against a test URL

Create a URL above, then open the Square Developer Dashboard, pick your application, switch to Sandbox, and go to Webhooks → Subscriptions → Add subscription. Paste the URL, choose the API version and the events, and save. Square shows the signature key on the subscription — copy it.

Then press Send Test Event on the subscription. Square delivers a synthetic payload with a real signature, which is enough to get verification working before any money is involved. For a genuine event, take a sandbox payment through the Payments API or the sandbox Point of Sale.

Why the URL is in the signature

Most providers sign the body. Square signs the notification URL followed immediately by the body, with no separator:

https://trywebhook.com/w/your-bin-id{"merchant_id":"MLFAKEMERCHANT01","type":"payment.updated",...}

HMAC-SHA256 that with the signature key and base64-encode it.

The design intent is to bind a delivery to the endpoint it was addressed to, so a payload captured from one subscription cannot be replayed into another. The practical consequence is that verification depends on a value your server does not receive in the request. Reconstructing the URL from the incoming request is the wrong move — behind a proxy it will differ in scheme or host, and the digest will fail for reasons the body gives no hint about.

const SQUARE_NOTIFICATION_URL = 'https://api.example.com/webhooks/square'; // exactly as configured
const signed = SQUARE_NOTIFICATION_URL + rawBody;

Hard-code it, or read it from configuration alongside the signature key. Those two values belong together.

Configuring the Custom HMAC tab

The settings table above gives the exact values. The only field you have to change is the signed payload: replace YOUR-BIN-ID with the id in your own URL. Everything before {body} is treated as a literal, so what you type must be the URL Square has stored, byte for byte.

Reading the payload

{
  "merchant_id": "MLFAKEMERCHANT01",
  "type": "payment.updated",
  "event_id": "00000000-1111-2222-3333-444444444444",
  "created_at": "2026-06-15T10:04:00.000Z",
  "data": { "type": "payment", "id": "FAKEPAYMENTID0000000000", "object": { "payment": { ... } } }
}

Route on type. Then note the double nesting: data.type names the resource, and data.object is an envelope with that name as its key. So the payment is at data.object.payment and an order would be at data.object.order.

merchant_id matters if your application is used by more than one Square seller — it is the only thing in the payload identifying whose account this came from. event_id is your idempotency key.

Statuses, not events

Square’s event names are coarse and its status fields are precise. A single card payment walks through several states and emits payment.updated at each:

payment.updated  →  status: APPROVED    (authorised, money not taken)
payment.updated  →  status: COMPLETED   (captured)

Anything that provisions on the event name will run twice. The rule that holds across Square’s whole event catalogue: the event tells you something changed, and the status field inside tells you what it changed to. Only the second one is a business decision.

Failure modes

Where Square integrations usually break

The URL is part of the signature

Square signs `notificationUrl + body`, so the signed string depends on the URL you configured. Moving an endpoint from `http` to `https`, adding a trailing slash, or sitting behind a proxy that rewrites the path all break verification while the body is untouched. Pass the configured URL to your verifier as a constant, not one reconstructed from the request.

Sandbox and production keys differ

The sandbox application has its own subscriptions and its own signature keys. So does each subscription — two subscriptions in the same app do not share a key.

The legacy SHA-1 header still ships

`x-square-signature` is the old HMAC-SHA1 header and is deprecated. Verify `x-square-hmacsha256-signature` and ignore the other; a verifier that falls back to the SHA-1 one has quietly downgraded its own security.

The object is nested twice

The resource is at `data.object.payment`, not `data.object`. The extra level exists so one event type can carry differently named objects, and `data.type` tells you which key to look under.

payment.updated fires more than once

A single card payment typically produces two or three `payment.updated` events as it moves through `APPROVED` and `COMPLETED`. Provisioning on the event rather than on the status inside it charges once and delivers twice.

Answers

Square webhook questions

Why does my Square signature verification fail when the body is clearly correct?+

Because the notification URL is part of the signed string, and yours does not match what Square has stored. Compare the subscription's URL character for character with the one your verifier is using — including the scheme, any trailing slash, and any query string.

Can I verify a Square signature in TryWebhook?+

Yes, through the Custom HMAC tab. Set the algorithm to SHA-256, the encoding to base64, the header to `x-square-hmacsha256-signature`, and the signed payload to your bin URL followed immediately by `{body}`. The settings table above has the exact values.

How do I test Square webhooks without taking real payments?+

Use a sandbox application. It has its own subscriptions, its own signature keys, and test card numbers, and it fires real webhooks. The Developer Dashboard also has a Send Test Event button on each subscription.

What is Square-Environment for?+

It tells you whether the event came from `Sandbox` or `Production`. Worth logging, and worth asserting on if the same endpoint serves both — a sandbox event processed as production is a fake order in your real database.

Which event should I provision on?+

`payment.updated` with `status: COMPLETED` for card payments, or `order.updated` if you need line-item detail. Check the status field in every case; the event name alone never means the money has settled.

Other providers

Testing something else?

One click

Point Square at a URL and watch the payload land.

Square Developer Dashboard → your application → Webhooks → Subscriptions — paste the URL, trigger an event, and read exactly what arrived.

No signup · No email · Ready in about a second