Headers
Every header on a delivery, and what to do with it.
Every delivery carries the same seven headers. Nothing else is sent, and no header is ever omitted.
POST /webhooks/salaf HTTP/1.1
Content-Type: application/json
User-Agent: Salaf-Webhooks/1.0
X-Salaf-Signature: t=1754899200,v1=dd3c17ef08611a833fd18718fb90d48d278db0f7f1ced1c1812aad359a718de8
X-Salaf-Event: order.created
X-Salaf-Event-Id: evt_01J4X8G9ABCDEFGHJKMNPQRSTV
X-Salaf-Delivery: whd_01J4X8GB2CDEFGHJKMNPQRSTVW
X-Salaf-Api-Version: 2026-08| Header | Value | What to do with it |
|---|---|---|
X-Salaf-Signature | t=<unix>,v1=<hex>[,v1=<hex>] | Verify it before reading the body. Two v1 values mean a rotation is in progress; accept either. See Verifying signatures. |
X-Salaf-Event | order.created | Route on it if it saves you parsing the body first. It is always identical to type in the payload. |
X-Salaf-Event-Id | evt_ + ULID | Your de-duplication key. Identical to id in the payload. Stable across every retry of the same event. |
X-Salaf-Delivery | whd_ + ULID | This attempt's record. Changes between retries, unlike the event id. Quote it to support; never de-duplicate on it. |
X-Salaf-Api-Version | 2026-08 | The payload version pinned to your endpoint. Identical to api_version in the body. |
Content-Type | application/json | The body is always JSON, always UTF-8. |
User-Agent | Salaf-Webhooks/1.0 | Useful in access logs. Not an authentication signal — anyone can send it. |
What is not sent
- No authentication header. The signature is the authentication. Do not expect a bearer token, and do not put a secret in your webhook URL's query string — it would end up in logs and proxies. If your receiver needs an extra layer, put it behind mTLS or an allow-list, not a URL secret.
- No custom headers. There is no way to configure additional headers on an endpoint.
- No compression or chunking. Bodies are small and sent whole.
Your response
Only the status line is interpreted. 2xx is success; everything else is a
failure that gets retried.
The first kilobyte of your response body is stored, and shown to the
merchant in the delivery log — so a plain-text error message from your handler
is genuinely useful there. Header-shaped lines (Set-Cookie:,
Authorization:, X-Api-Key: and friends) are stripped before storage, in
case a framework echoes the request back in a debug response; but the simplest
protection is not to echo secrets in an error body in the first place.
Response headers you send are not read at all — including Retry-After. The
retry schedule is ours and is not negotiable per delivery.