Store Builder

Webhooks

Register a URL to be called the moment something happens, and know the three things that will surprise you.

Manage → Settings → Webhooks.

"Register a URL to receive events as they happen, instead of polling the API."

This is why a store is reachable through the API at all rather than through a polling loop. An agency running fifty stores registers fifty times with fifty calls, instead of clicking through fifty settings screens.

Adding an endpoint

Add endpoint.

Endpoint URL — your system's address, e.g. https://example.com/hooks/web-builder.

Description — an internal label, e.g. "Order sync to the warehouse system".

Events — at least one. There are eight:

Event Fires when
order.created An order is placed
order.updated An order's status, payment or fulfillment changes
customer.created A customer is added
customer.updated A customer record changes
product.created A product is created
product.updated A product changes
product.deleted A product is removed
page.published A page goes live

Enabled — the switch.

An endpoint subscribed to nothing would never fire, with no error anywhere to notice by — which is why the form requires at least one.

Three things that will surprise you

1. The signing secret is shown exactly once

"The signing secret is only shown after you save." And only then.

There is no route that reads it back — GET, list and update all return the endpoint with no secret field at all, not even an empty one. Lose it and the fix is to delete the endpoint and register a new one.

Why so strict: webhooks.read is grantable on its own and reaches the lowest role on a store. A GET that could return a signing secret would let that role forge deliveries into your own system.

2. Duplicates will happen

Delivery is at-least-once, never exactly-once. A delivery the platform believes failed — a timeout, a dropped connection, a 5xx — is retried in full, even when your system actually processed it and only the response back was lost.

If your receiver turns order.created straight into a charge, an email, or a stock decrement without checking anything first, it will eventually do it twice.

The defence: every delivery carries an id that is stable across every attempt (also the X-WB-Event-Id header). Record the ones already handled, and no-op a repeat.

3. There is no ordering

Deliveries go out in the order they become due, not the order the events happened in. A retry sits behind its backoff, so a fresher event for the same resource can arrive first.

Do not infer sequence from arrival order. If you need one, read the resource's own updatedAt.

Status

Status Means
Active Normal
Disabled You switched it off
Failing Three consecutive delivery failures

Failing does not mean dead: "Still retrying — one success clears this."

The retry schedule is seven attempts spanning about 32.6 hours: immediately, +1 minute, +5 minutes, +30 minutes, +2 hours, +6 hours, +24 hours. Long enough to outlast a deploy, an expired certificate or a night's outage; short enough that nothing is still being retried next week.

An endpoint is not disabled by this — it keeps receiving new events, because an integration that comes back on its own should catch up by itself rather than be switched off silently.

Checking whether it works

Send test event fires a real delivery at your URL.

View deliveries shows recent attempts with their status codes and errors. The Last success column in the list answers "is it alive" at a glance.

Note: the delivery history never includes the payload. If you need to know exactly what was sent, the envelope your receiver already got is it.

Blocked URLs

A URL pointing at a private, loopback or link-local address is refused immediately with 400 blocked_url. The address is checked again at dial time, because a hostname's DNS answer can change after the first check — and redirects are never followed.

There is nothing to debug: the answer comes back at once.

Read-only

If your role only has webhooks.read, the screen says so: "You can view registered endpoints, but not create or change them."

Verifying signatures

Every delivery carries an X-WB-Signature header. How to check it — including the detail people get wrong (the signed string uses Unix seconds, not the RFC3339 value in the header) — is in The public API.

Updated 22/08/2026