# Webhooks

Webhooks let your systems react to events in Allegro in real time. When something happens — a new audience member joins, an entitlement is granted, a foreign key is attached — Allegro sends an HTTP `POST` request to a URL you control. You don't need to poll the API; Allegro pushes changes to you.

## Creating a Webhook[​](#creating-a-webhook "Direct link to Creating a Webhook")

1. Go to **Organization Settings → Developer → Webhooks**.
2. Click **Add Webhook**.
3. Enter the **Endpoint URL** — the HTTPS URL on your server that will receive deliveries.
4. Enter a **Description** to help you identify the webhook later.
5. Choose which **Events** to subscribe to. You can subscribe to individual events or to all events.
6. Click **Create**. Allegro immediately sends a [ping event](#ping) to your endpoint to confirm it is reachable.

note

Each organization can have up to **5 webhooks**. If you need more, delete an existing one first.

### Activating and Deactivating[​](#activating-and-deactivating "Direct link to Activating and Deactivating")

Every webhook has an **Active** toggle. Deactivating a webhook suspends deliveries without deleting the webhook or its delivery history. Reactivate it at any time to resume.

## Delivery Payload[​](#delivery-payload "Direct link to Delivery Payload")

Every delivery is an HTTP `POST` with a JSON body in the following envelope format:

```json
{
    "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "event": "audience_member.created",
    "created_at": "2024-10-15T14:32:00Z",
    "data": { ... }
}

```

| Field        | Type   | Description                                                                                                                            |
| ------------ | ------ | -------------------------------------------------------------------------------------------------------------------------------------- |
| `id`         | string | Unique identifier for the event (UUID). Matches the `X-Allegro-Event-Id` header.                                                       |
| `event`      | string | The event type (e.g. `audience_member.created`).                                                                                       |
| `created_at` | string | ISO 8601 timestamp of when the event occurred.                                                                                         |
| `data`       | object | The resource representation of the entity that changed. Shape varies by event — see [Events Reference](/developer/webhooks/events.md). |

### Request Headers[​](#request-headers "Direct link to Request Headers")

Every delivery includes the following HTTP headers:

| Header                    | Description                                                                                                 |
| ------------------------- | ----------------------------------------------------------------------------------------------------------- |
| `Content-Type`            | `application/json`                                                                                          |
| `User-Agent`              | `Allegro-Webhooks`                                                                                          |
| `X-Allegro-Event`         | The event type (e.g. `audience_member.created`).                                                            |
| `X-Allegro-Event-Id`      | The UUID of the event that triggered this delivery.                                                         |
| `X-Allegro-Delivery`      | Identifier for the delivery record. Stays the same across retries and manual redeliveries of that delivery. |
| `X-Allegro-Signature-256` | An HMAC-SHA256 signature of the request body (see below).                                                   |

## Signature Verification[​](#signature-verification "Direct link to Signature Verification")

Allegro signs every delivery using HMAC-SHA256. The signature is sent in the `X-Allegro-Signature-256` header in the format `sha256=<hex-digest>`.

The signature is computed over the **raw request body** using your webhook's **signing secret** as the key.

Always verify signatures

Verify the signature before processing any webhook payload. Without verification, your endpoint could accept forged requests from anyone on the internet.

### Finding Your Signing Secret[​](#finding-your-signing-secret "Direct link to Finding Your Signing Secret")

Open the webhook detail page (**Organization Settings → Developer → Webhooks → your webhook**). The signing secret is displayed there. Treat it like a password — do not commit it to source control.

### PHP Example[​](#php-example "Direct link to PHP Example")

```php
function verifyAllegroSignature(string $rawBody, string $secret, ?string $signatureHeader): bool
{
    // Header format: "sha256=<hex-digest>". Reject a missing or malformed header.
    if ($signatureHeader === null || !str_starts_with($signatureHeader, 'sha256=')) {
        return false;
    }

    $expected = 'sha256=' . hash_hmac('sha256', $rawBody, $secret);

    return hash_equals($expected, $signatureHeader);
}

// Usage (e.g. in a Laravel controller):
$rawBody = $request->getContent();
$signature = $request->header('X-Allegro-Signature-256');

if (!verifyAllegroSignature($rawBody, config('services.allegro.webhook_secret'), $signature)) {
    abort(401, 'Invalid signature');
}

```

### Node.js Example[​](#nodejs-example "Direct link to Node.js Example")

```js
import { createHmac, timingSafeEqual } from 'node:crypto';

function verifyAllegroSignature(rawBody, secret, signatureHeader) {
    if (!signatureHeader?.startsWith('sha256=')) return false;

    const expected =
        'sha256=' + createHmac('sha256', secret).update(rawBody).digest('hex');
    const actual = Buffer.from(signatureHeader);
    const expectedBuf = Buffer.from(expected);

    if (actual.length !== expectedBuf.length) return false;
    return timingSafeEqual(actual, expectedBuf);
}

// Usage (e.g. in an Express handler):
const rawBody = req.rawBody; // requires bodyParser with verify option
const signature = req.headers['x-allegro-signature-256'];

if (
    !verifyAllegroSignature(
        rawBody,
        process.env.ALLEGRO_WEBHOOK_SECRET,
        signature,
    )
) {
    return res.status(401).send('Invalid signature');
}

```

note

Use a **constant-time comparison** (`hash_equals` in PHP, `timingSafeEqual` in Node.js) to prevent timing attacks.

## Retries[​](#retries "Direct link to Retries")

When a delivery fails — your endpoint returns a non-2xx status code or does not respond within 10 seconds — Allegro retries automatically:

| Attempt | Delay after previous attempt |
| ------- | ---------------------------- |
| Initial | Immediate                    |
| Retry 1 | 60 seconds                   |
| Retry 2 | 300 seconds (5 minutes)      |

After **3 total attempts** (the initial delivery plus 2 retries), the delivery is marked **Failed** and no further retries occur. The webhook itself remains active and continues to receive future events.

tip

Respond to deliveries as quickly as possible. If processing takes time, accept the delivery immediately (return `200 OK`) and handle it in a background job.

## Viewing and Managing Deliveries[​](#viewing-and-managing-deliveries "Direct link to Viewing and Managing Deliveries")

Open a webhook from **Organization Settings → Developer → Webhooks** to see its recent deliveries. Deliveries are kept for **180 days**.

Each delivery record shows:

* The event type and delivery timestamp
* HTTP response status returned by your endpoint
* The full request payload and response body

### Redelivery[​](#redelivery "Direct link to Redelivery")

You can manually redeliver any past delivery from the delivery detail view. This is useful for replaying events after you fix a bug in your endpoint or if your server was temporarily unavailable.

### Ping[​](#ping "Direct link to Ping")

When you create an active webhook, Allegro sends a `ping` event to your endpoint to verify that it is reachable. The ping's `data` payload echoes the webhook's `id`, subscribed `events`, and `created_at` timestamp. Webhooks created inactive are not pinged.

## Related[​](#related "Direct link to Related")

* [Events Reference](/developer/webhooks/events.md) — full list of subscribable events and their payload shapes
* [Settings](/product/administration/settings.md) — how to access Organization Settings
