# Webhooks

Webhooks tell your system when something changes, so you don't have to poll. When an event you subscribed to happens, we send an HTTPS `POST` to your endpoint with a small JSON body: the event type, the id of what changed and its new status. Fetch the details with the API.

## Set up an endpoint

1. In the portal, open **Settings → API access** and go to **Add a webhook endpoint**.
2. Enter the endpoint URL: a public `https://` address of up to 2,000 characters, without a user name, password or `#` part. `localhost`, single-word host names, private and local IP addresses, and names ending in `.local`, `.internal`, `.lan`, `.localhost` or `.home.arpa` are refused.
3. Optionally add a description of up to 100 characters.
4. Tick the events you want: see [Webhook events](https://docs.rephut.com/developers/webhooks/events).
5. Click **Add endpoint**, then copy the signing secret (`whsec_...`) straight away. It is shown only once. Store it like a password.

You must have signed in within the last 10 minutes to add an endpoint or create a new secret. An account can have up to 5 endpoints, including turned-off ones. Webhooks need API access to be on for your account.

## Manage endpoints

Open an endpoint in **Settings → API access** to:

- change its URL, description and events (**Save changes**);
- **Create a new secret**: it replaces the old secret at once, with no overlap, so update your receiver straight after;
- **Send test event**: see [Webhook delivery and retries](https://docs.rephut.com/developers/webhooks/delivery#test-events);
- **Turn off** and **Turn on**;
- **Delete endpoint**;
- see **Recent deliveries**: the last 50 deliveries with their status, attempts and your endpoint's answer.

While your account is on hold you can't add or change endpoints or turn them on. You can still turn them off, delete them, create a new secret and send test events.

## What a webhook looks like

```text
POST /your/webhook/path HTTP/1.1
Content-Type: application/json
User-Agent: Fulfillbot-Webhooks/1.0
X-Webhook-Id: evt_3f9a1c2b7d4e5f60718293a4
X-Webhook-Event: order.status_changed
X-Webhook-Attempt: 1
X-Webhook-Signature: t=1762653600,v1=78e8462fdd961bd012879276064959675d3a21748eb85da05b69fb9f18e51c0d

{"id":"evt_3f9a1c2b7d4e5f60718293a4","type":"order.status_changed","createdAt":"2026-11-09T02:00:00.000Z","data":{"id":"cm3o7rd0e0001h2j3k4l5m6n","status":"SHIPPED"}}
```

This example is signed with the example secret `whsec_example_only_do_not_use`. Its timestamp is in the past, so to try your verification code with it, pass the example's time (`1762653600`) as the current time: the samples on [Verifying webhook signatures](https://docs.rephut.com/developers/webhooks/signatures) take an optional `now` argument for this. Never do that in production.

The table below describes the body of this example. `type` and `data` differ per event: see [Webhook events](https://docs.rephut.com/developers/webhooks/events).

| Field | Type | Description |
|---|---|---|
| `id` | string | Event id. Retries and every endpoint get the same id; use it to skip duplicates. |
| `type` | string | The event type. Always `order.status_changed`. |
| `createdAt` | string (date-time) | When the change happened (ISO 8601, UTC). |
| `data` | object | What changed: the id of the resource and its status after the change. For `webhook.test`, `id` is the endpoint id and `status` is `TEST`. |
| `data.id` | string | Order id. Fetch it with GET /v1/orders/{id}. |
| `data.status` | string | The status after the change (uppercase code). One of `NEEDS_ATTENTION`, `READY`, `BACKORDERED`, `RESERVED`, `WEIGHED`, `SHIPPED`, `CANCELLED`. |

Payloads never contain personal data, amounts, images or file links. Fetch the resource with its `GET` endpoint for the details.

## Headers

| Header | Value |
|---|---|
| `Content-Type` | `application/json` |
| `User-Agent` | `Fulfillbot-Webhooks/1.0` |
| `X-Webhook-Id` | The event id. The same on every retry and for every endpoint that gets the event; use it to skip duplicates. |
| `X-Webhook-Event` | The event type, for example `order.status_changed`. |
| `X-Webhook-Attempt` | Which attempt this is, 1 to 6. |
| `X-Webhook-Signature` | `t=<unix seconds>,v1=<hex HMAC-SHA256>`. See [Verifying webhook signatures](https://docs.rephut.com/developers/webhooks/signatures). |

## Next

- [Webhook events](https://docs.rephut.com/developers/webhooks/events): what each event means and when it is sent.
- [Verifying webhook signatures](https://docs.rephut.com/developers/webhooks/signatures): check that a request really comes from us.
- [Webhook delivery and retries](https://docs.rephut.com/developers/webhooks/delivery): timeouts, retries, ordering and duplicates.
- [Handle webhooks reliably](https://docs.rephut.com/developers/guides/reliable-webhooks): a design that doesn't lose events.
