Skip to content

Webhooks to your own systems

Send orders, stock and product changes to your own systems as signed HTTPS posts, check the signature, and how retries, the delivery log and automatic turning off work.

Reference3 min read

A webhook sends the events you choose to an address of yours, such as a warehouse system or an ERP, as they happen. Webhooks are in the Growth and Enterprise plans, with the management API. Admins add them under Webhooks.

Add a webhook

  1. Open Webhooks and select New webhook.
  2. Enter the address, starting with https://, such as https://erp.northwilds.com/hooks/commerce, and what it's for.
  3. Choose the events, such as Order placed and Order paid.
  4. Select Save, and copy the signing secret. It starts with whsec_ and is shown only once. The key button makes a new one; the old one stops working at once.

Send a test posts a commerce.webhook.test event straight away and shows the answer. Each shop can have 10 webhooks, and only gets events from its own shop.

What arrives

A POST with a JSON body:

JSON
{  "id": "1f6c6a52-4f7e-4a63-9c39-5d8b2b6c0c11",  "type": "commerce.order.paid",  "createdAt": "2026-10-30T09:14:02.118Z",  "organisationId": "6650c0ffee0000000000abcd",  "subject": { "resourceType": "order", "id": "6650c0ffee0000000000f00d" },  "data": { "orderId": "6650c0ffee0000000000f00d", "reference": "NW1042", "status": "open", "paymentStatus": "paid", "fulfilment": "unfulfilled", "total": 46700, "currency": "EUR", "lines": 3, "source": "checkout" }}

data is the same as the event's data in Events. Fetch anything more, such as the order's lines, from the API.

Orbit-Signature
What it holds
t=<unix seconds>,v1=<signature>
Orbit-Webhook-Id
What it holds
The delivery's id, the same on every retry. Use it to spot duplicates.
Orbit-Event
What it holds
The event type.
User-Agent
What it holds
CommerceOrbit-Webhooks/1

Answer with any 2xx status within 10 seconds. Do the work afterwards, not before you answer. Redirects aren't followed.

Check the signature

The signature is the hex HMAC SHA-256 of the time, a full stop and the raw body, with your signing secret as the key. Compare it in constant time, and refuse a time more than five minutes old.

TypeScript
import { createHmac, timingSafeEqual } from "node:crypto";export function verified(header: string, body: string, secret: string): boolean {  const parts = Object.fromEntries(header.split(",").map((part) => part.split("=") as [string, string]));  const time = Number(parts.t);  if (!time || Math.abs(Date.now() / 1000 - time) > 300) return false;  const expected = createHmac("sha256", secret).update(`${time}.${body}`).digest("hex");  return expected.length === parts.v1?.length && timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));}

Use the body exactly as it arrived, before parsing it.

Retries

A delivery that doesn't get a 2xx answer is tried again after 1 minute, then 5 and 30 minutes, then 2, 6, 12 and 24 hours, 8 tries in all. Recent deliveries under each webhook shows every delivery with its answer and time, and Send again for one that failed. Deliveries are kept for 30 days.

A webhook that has failed at least 10 times over 3 days is turned off, and Admins get a notification in Orbit. Fix your system, then turn it on again. Events while it was off aren't sent later.

Addresses

Webhooks only go to https addresses on the internet. Addresses that lead to a private network, such as 10.0.0.5 or a name that resolves to one, are refused.

Plans

On a plan without the management API, webhooks stop and no new events are queued, and nothing is lost from your settings. See Plans.

Was this page helpful?

Read next