> For the complete documentation index, see [llms.txt](https://savefee.gitbook.io/savefee/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://savefee.gitbook.io/savefee/webhooks/overview-and-setup.md).

# Overview and setup

## The delivery model

When something happens to an order or a broadcast, SaveFee sends a `POST` to your callback URL with a JSON body and a signature header. Your endpoint answers `2xx` to acknowledge.

```
event occurs  →  POST to your callbackUrl  →  your 2xx  →  done
                                          ↘  no 2xx   →  retried
```

## Registering your callback URL

The callback URL belongs to an **API key**. Set it when you create the key in the dashboard, or add it later from **Edit API key**.

Requirements:

* **`https://` only.** Plain `http://` is rejected.
* **Publicly resolvable.** Private and loopback addresses (`127.0.0.1`, `localhost`, `10.0.0.0/8`, `192.168.0.0/16`, `::1`) are rejected.
* No credentials in the URL.

To stop deliveries entirely, revoke the key and create a new one without a callback URL.

## The signing secret

Creating a key with a callback URL also produces a signing secret that starts with `whsec_`. **It is shown once, at creation time, and cannot be retrieved again.** Store it with the same care as the API key itself — you need it to verify that a delivery really came from SaveFee.

## Your endpoint's obligations

| Requirement                                   | Why                                                             |
| --------------------------------------------- | --------------------------------------------------------------- |
| Answer `2xx` within **5 seconds**             | Slower than that counts as a failure and is retried.            |
| Verify the signature before trusting the body | Anyone can POST to a public URL.                                |
| Read the **raw** request body                 | Re-serialising JSON changes the bytes and breaks the signature. |
| Deduplicate on the delivery id                | Retries reuse the same id, so you may receive one twice.        |
| Do the real work **after** responding         | Acknowledge first, process asynchronously.                      |

{% hint style="info" %}
Keep polling `GET /v1/orders/{orderId}` as a fallback alongside webhooks. Your endpoint may be mid-deployment when an event fires, and polling makes your integration correct either way.
{% endhint %}
