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
- Go to Organization Settings → Developer → Webhooks.
- Click Add Webhook.
- Enter the Endpoint URL — the HTTPS URL on your server that will receive deliveries.
- Enter a Description to help you identify the webhook later.
- Choose which Events to subscribe to. You can subscribe to individual events or to all events.
- Optionally choose which Properties the webhook is scoped to. Leave every property unchecked to receive events from the whole organization — see Property Scoping.
- Click Create. Allegro immediately sends a ping event to your endpoint to confirm it is reachable.
The endpoint must be a public https:// URL. Allegro rejects URLs whose host
resolves to a private, loopback, link-local, or otherwise reserved address —
including cloud metadata endpoints such as 169.254.169.254. This is checked
both when you save the webhook and again before every delivery. Allegro also
does not follow redirects, so the URL you register is the exact URL that
receives each POST.
Each organization can have up to 5 webhooks. If you need more, delete an existing one first.
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.
Property Scoping
If your organization uses properties, you can limit a webhook to a subset of them. Open the webhook's Properties section (Organization Settings → Developer → Webhooks → your webhook) and check the properties whose events you want.
Leaving every property unchecked means organization-wide — the webhook receives matching events from every property. That is the default, and it is how all existing webhooks behave, so adding properties to your organization never changes an existing webhook's deliveries.
Every delivery reports the property it came from in the envelope's property
field, so an organization-wide webhook can still tell properties apart without
being scoped to any of them.
The originating property comes from the request context the event fired in,
not from the record itself. Audience members, entitlements, purchases,
interactions, and templates belong to the organization, not to a property — so
an event fired outside a property host has property: null, and Allegro
delivers it only to organization-wide webhooks.
Events with no property include:
- Changes made in the Allegro dashboard.
- API requests made against the organization host rather than a property host, which includes most API key traffic.
- Console commands, bulk imports, and queued background work.
If your endpoint needs to see every event, leave the webhook unscoped and branch
on the property field yourself.
Delivery Payload
Every delivery is an HTTP POST with a JSON body in the following envelope
format:
{
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"event": "audience_member.created",
"created_at": "2026-08-12T14:32:00+00:00",
"property": "magazine",
"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. |
property | string | null | Slug of the property the event fired on. null when the event fired without property context — see Property Scoping. |
data | object | The resource representation of the entity that changed. Shape varies by event — see Events Reference. |
property is additiveThe property field was added to every envelope, including on webhooks that are
not scoped to any property. Existing consumers keep parsing deliveries
unchanged.
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-Attempt | Which attempt this request is, starting at 1. Increments on every automatic retry and manual redelivery. |
X-Allegro-Signature-256 | An HMAC-SHA256 signature of the request body (see below). |
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.
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
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
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
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');
}
Use a constant-time comparison (hash_equals in PHP, timingSafeEqual in
Node.js) to prevent timing attacks.
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.
Every attempt is recorded individually. Each one keeps its own response status, response headers, response body, duration, and failure reason, so a delivery that failed twice before succeeding still shows both failures rather than only its final outcome. The full attempt history for a delivery is visible in the dashboard under the webhook's deliveries list.
Use X-Allegro-Attempt to tell a retry from a new event. X-Allegro-Delivery
stays constant for every attempt of the same delivery, so it remains the right
header to key idempotency on.
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
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
- The property the event fired on, when it had one
- HTTP response status returned by your endpoint
- The full request payload and response body
The property shown on a delivery is read back out of the delivered payload, so it always matches what your endpoint received. Deliveries cannot be filtered by property.
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
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.
Pings ignore property scoping — a property-scoped webhook
is still pinged, so you can confirm the endpoint is reachable before any real
event arrives. Because webhooks are created from the organization dashboard, a
ping normally carries property: null.
Related
- Events Reference — full list of subscribable events and their payload shapes
- Settings — how to access Organization Settings