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 for them."

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

New endpoint.

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

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

Events — at least one. There are eleven:

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
course.enrolled A student is granted a course
course.revoked Course access is withdrawn
form.submitted A form submission is stored

form.submitted fires for every stored submission of every form on the site — contact, order, booking — never for a refused one. The full payload and how it relates to the inspector's action chains are in Form actions.

The next-to-last two belong to The Courses app, and they come as a pair on purpose: an integration that only hears enrolments keeps a refunded student in your LMS forever, and it has no way to poll for the absence of something.

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 appears once you save — and only to people who can edit

"The signing secret is shown once you save." Need it again later, open the endpoint's menu: Reveal signing secret returns the same one, Rotate signing secret mints a new one — and "the current secret stops working immediately", so update your receiver before the next event lands.

All three routes — create, reveal, rotate — require write access to webhooks. The list and the detail never carry the secret, not even as an empty field, because webhooks.read reaches the lowest role on a store — and a viewer who could read the signing key could 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 trying — 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. After the seventh, that delivery is marked Dead.

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; each is Pending, Delivered or Dead. The Last success column in the list answers "is it alive" at a glance.

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 see registered endpoints, but not create or change them."

Verifying signatures

Every delivery carries X-WB-Signature, along with X-WB-Timestamp, X-WB-Event-Id, X-WB-Event-Type and X-WB-Attempt. 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 26/09/2026