Event Queue
The event queue is a Redis List-based pipeline for delivering events from Allegro to external consumers in real time. When enabled, every event tracked by the SDK is pushed onto a per-tenant Redis List. External consumers poll the queue to read events, then issue a separate delete call to remove them.
Each destination that receives a tracked event is independent, and each is
controlled by its own feature flag: the Redis queue described here is gated by
UseRedisEvents, while writing events to the database is gated separately by
StoreEventsInDatabase. A tenant streaming events off Redis can therefore turn
off database storage without affecting the queue.
How It Works
Feature Flag
The queue is opt-in per tenant via the UseRedisEvents Pennant feature flag.
Event Ingestion
When an event is tracked via the SDK and the UseRedisEvents flag is active,
Allegro pushes it onto the tenant's event queue. Each tenant has its own
isolated queue. Storing the same event in the database is handled independently
by the StoreEventsInDatabase flag, so the queue receives events whether or not
database storage is enabled.
Reading Events (get)
Consumers call GET /api/platform/events to read up to 10,000 events from the
front of the queue. This is a non-destructive read — events remain in the
queue until you explicitly delete them.
Deleting Events (delete)
After processing the events, call DELETE /api/platform/events?count=N where
N is the count value returned by the preceding GET. Passing the exact
count prevents a race condition: any events that arrived between the GET and
the DELETE are left untouched and will be returned on the next GET.
API Endpoints
All endpoints are under the /api/platform prefix and require Sanctum
authentication (api middleware + auth:sanctum).
GET /api/platform/events
Read up to 10,000 events from the front of the queue. Non-destructive — events
are not removed until DELETE is called.
If the UseRedisEvents feature flag is not active for the current tenant,
returns an empty result.
Response 200 OK:
{
"data": {
"count": 2,
"events": [
{
"id": "9b1f...",
"type": "page_view",
"session_id": "7c2a...",
"audience_member_id": "4d8e...",
"device_id": "1a6b...",
"page_hostname": "example.com",
"page_path": "/articles/hello",
"page_title": "Hello, world",
"property_slug": "magazine",
"utm_source": "newsletter",
"user_agent": "Mozilla/5.0 ...",
"ip_address": "1.2.3.4",
"data": { "any": "event-specific values" },
"created_at": "2026-02-25T18:00:00+00:00",
"updated_at": "2026-02-25T18:00:00+00:00"
}
]
}
}
The exact set of keys varies per event — see Event Payload below for the full field list and which fields are always present.
Empty queue response:
{
"data": {
"count": 0,
"events": []
}
}
Event Payload
Each entry in the events array is the event as it was recorded at tracking
time, serialized directly from its stored attributes. The queue carries this
raw event — not an enriched or derived form.
A field appears in the payload only if it was set on the event at tracking
time — not based on whether the value is meaningful. Required and
always-derived fields are set on every event (though some, such as user_agent
and ip_address, may be null). Optional fields are set only when the SDK sent
them, or when they were derived from data that was sent; an optional field that
was never sent is omitted entirely rather than emitted as null. (A field a
client explicitly sends as null is still present, as null.) As a result,
payloads vary in shape from one event to the next.
Always present
| Field | Type | Description |
|---|---|---|
id | uuid | Unique event identifier. |
type | string | Event type (e.g. page_view, click, purchase). |
session_id | uuid | The customer session the event belongs to. |
user_agent | string | null | Request User-Agent header. null if the request had none. |
ip_address | string | null | Originating IP address. null if it could not be determined. |
property_slug | string | null | Slug of the property the request was made on. null when the request used a plain organization host with no property context. |
created_at | ISO 8601 string | When the event was recorded. |
updated_at | ISO 8601 string | Equal to created_at for queued events. |
Present when set
These appear only when the tracking call supplied them (directly or via the tracked URL).
| Field | Type | Source |
|---|---|---|
audience_member_id | uuid | The authenticated audience member, when known. |
device_id | uuid | The originating device, when known. |
page_hostname | string | Host parsed from the tracked URL. |
page_path | string | Path parsed from the tracked URL. |
page_title | string | Page title. |
utm_source | string | UTM parameter parsed from the tracked URL's query string. |
utm_medium | string | UTM parameter parsed from the tracked URL's query string. |
utm_campaign | string | UTM parameter parsed from the tracked URL's query string. |
utm_term | string | UTM parameter parsed from the tracked URL's query string. |
utm_content | string | UTM parameter parsed from the tracked URL's query string. |
content_type | string | Type of content the event relates to. |
content_id | string | Identifier of the content the event relates to. |
publisher | string | Publisher associated with the content. |
referer | string | Referring URL. |
object_type | string | Type of the object the event acted on. |
object_id | string | Identifier of the object the event acted on. |
context | string | Free-form context label supplied by the integration. |
conversion_pv_id | string | Page-view event ID attributed as the conversion source. |
url_in_click | string | Destination URL for click / link-click events. |
data | object | Arbitrary event-specific key/value data, returned as a nested object. |
url fieldThe tracked page URL is never stored or emitted as-is. It is broken apart into
page_hostname, page_path, and any utm_* query parameters, and the original
URL is then discarded.
The queue reflects the event exactly as captured. Attributes populated by later,
asynchronous processing — such as the parsed user-agent breakdown stored in
user_agent_parsed — are not part of the queue payload.
DELETE /api/platform/events
Remove exactly count events from the front of the queue. The count parameter
is required and must match the count returned by the preceding GET call
— this prevents accidentally deleting events that arrived after the read.
Query parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
count | integer ≥ 1 | Yes | Number of events to remove. Use the count value from the GET response. |
Response 204 No Content — events removed.
Response 422 Unprocessable Content — count is missing or invalid.
Recommended Consumer Pattern
loop:
GET /api/platform/events
if count == 0 → sleep, continue
process each event
DELETE /api/platform/events?count={count}
Read all events first, process them, then delete — passing the exact count
from the GET response. Because GET is non-destructive, events are safe to
re-read if your consumer needs to retry before issuing the DELETE. Using the
explicit count ensures events that arrived between your GET and DELETE are
never accidentally removed.