---
title: "Webhooks"
description: "Receive signed delivery state changes on your backend."
---

# Webhooks

Configure your webhook URL and secret in the dashboard. Entrega sends a signed `POST` whenever delivery state changes are enqueued.

## Headers

| Header | Value |
| --- | --- |
| `content-type` | `application/json` |
| `x-entrega-signature` | `sha256=<hex hmac>` |
| `user-agent` | `Entrega-Webhooks/1.0` |

## Payload

```json
{
  "id": "evt_12f0b71f-4d51-449b-9d42-81fdb1d2d5ee",
  "event": "delivery.in_transit",
  "occurred_at": "2026-04-29T18:10:00Z",
  "delivery_id": "f1d7a3f7-7a1f-4994-9c1f-68fe3c50a4f7",
  "delivery_reference": "DLV-2026-00042",
  "data": {
    "status": "in_transit"
  }
}
```

## Verify the signature

The signature is an HMAC-SHA256 over the exact JSON request body using your webhook secret.

```js
import crypto from "node:crypto"

function verifyEntregaSignature(rawBody, signature, secret) {
  const expected = "sha256=" + crypto
    .createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex")

  return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))
}
```

## Retries

Return any `2xx` status to acknowledge a webhook. Non-`2xx` responses and network failures are retried with exponential backoff for up to 10 attempts.

## Recommended handler

1. Verify `x-entrega-signature`.
2. Store the webhook `id` for idempotency.
3. Enqueue internal processing.
4. Return `200` quickly.
