---
title: Receive order webhooks
description: Subscribe a URL to order events, answer the activation ping, protect the endpoint with basic auth and handle deliveries and failures.
---

Goal: your server learns when an order is created, updated, closed or shipped, without polling. You need a public HTTPS endpoint and a token with `hub.write` plus read access to the topic's resource (`orders.read` for order topics).

## 1. Answer the activation ping

When you subscribe, Bolder first sends one `POST` to your URL with an `X-Hook-Ping` header and a body whose `topic` is `activation`. The subscription only becomes active if your endpoint answers `2xx` with the same value in an `X-Hook-Pong` header. Deploy the handler before you subscribe:

```js
import express from 'express'

const app = express()

app.post('/webhooks/bolder', express.json(), (req, res) => {
  const ping = req.get('X-Hook-Ping')
  if (ping) return res.set('X-Hook-Pong', ping).sendStatus(200)

  const event = req.body
  console.log(event.topic, event.item_id)
  res.sendStatus(200)
})

app.listen(3000)
```

## 2. Subscribe

```js
import { createBolder } from 'bolder-api-client'

const bolder = await createBolder({ token: process.env.BOLDER_TOKEN, shopId: 1234 })

const hook = await bolder.webhooks.create({
  topic: 'order',
  url: 'https://myapp.com/webhooks/bolder',
  auth: { type: 'basic', username: 'bolder', password: process.env.WEBHOOK_PASSWORD }
})
```

This calls `POST /v2/webhooks?shop_id=1234`; `POST /v2/sellers/{seller_id}/webhooks` does the same. Subscriptions belong to the seller (the account), not to a single shop.

By default a subscription doesn't receive events caused by the app that created it (an order your integration created through the API, for example). Pass `notify_origin: true` to receive those too.

Topics are hierarchical: `order` receives every order event, `order.updated` receives all its subtopics (`order.updated.closed`, `order.updated.shipped`, ...), and `order.created` only that one. The full list of topics is in the [Webhooks reference](/api/v2).

## 3. Verify deliveries

Deliveries are not signed. To make sure a request comes from Bolder, subscribe with `auth.type: basic` (as above): every delivery, the activation ping included, then carries those credentials in the `Authorization` header. Check them before anything else (register this middleware before the route):

```js
const expected = 'Basic ' + Buffer.from(`bolder:${process.env.WEBHOOK_PASSWORD}`).toString('base64')

app.use('/webhooks/bolder', (req, res, next) => {
  if (req.get('Authorization') !== expected) return res.sendStatus(401)
  next()
})
```

Use HTTPS so the credentials are not sent in clear text.

## 4. Handle the payload

Each delivery is a JSON `POST` with the event:

| Field | |
|---|---|
| `topic` | The event topic, singular (`order.updated.closed`). |
| `item_type`, `item_id` | The record the event is about (`order`, `123`). |
| `changes` | Changed fields as `{field: [old, new]}`. |
| `payload` | Extra data for the event, if any. |
| `created_on` | When the event happened. |
| `shop_id`, `shop_subdomain` | The shop it happened in. |
| `_embedded.item` | The record itself, as the v2 API returns it. |

Answer `2xx` quickly (requests time out after 30 seconds) and do slow work in a background job. Deliveries can arrive more than once and out of order: use `item_id` and `created_on` to keep your records consistent, or fetch the order again with `GET /v2/orders/{id}`.

## Failures

- A failed delivery is retried up to 10 times over about 24 hours.
- Answering `410 Gone` disables the subscription at once.
- After 100 failed attempts in a row (retries included) the subscription is marked as failed and stops receiving events. Timeouts and `502`, `512` and `523` errors don't count towards that limit.
- When a subscription stops, a `webhook.disabled` event is sent and the merchant gets an alert.
- Fix the endpoint, then call `PUT /v2/webhooks/{id}/reactivate` for a failed subscription. One disabled by a `410` has to be subscribed again.
- `GET /v2/webhooks/{id}/history` lists the recent events of the subscription's topic.

## Next

- [Webhooks reference](/api/v2): every topic and what triggers it.
- [Create an order and take payment](/guides/create-an-order)
