Event Hub
What the Event Hub is
The Event Hub exposes the time-ordered stream of user-related events that LuxID generated for your partnership's applications. You query it by time range, paginate through the results, and react to the events that matter to your business. Events include things like a user signing in, a subscription being created or revoked, a claim being changed, and similar lifecycle moments.
The Event Hub is a pull API: you ask for events between two timestamps and read what you get back. It is not a push/webhook system - LuxID does not call your endpoints. Webhook-based delivery is a separate concern documented at Webhooks and events API; the Event Hub described here is the underlying query interface.
The single endpoint:
| What you want to do | Endpoint |
|---|---|
| Search for events between two timestamps | GET /events/search?from=...&to=...&page=...&pageSize=... |
The event shape
Every event has a common envelope. Beyond the common fields, each event has a payload whose shape depends on the event's type and version:
{
"id": "7095cea0-becf-4ec8-9ed1-2c0b86adbfa5",
"timestamp": "2026-05-27T09:53:44.609",
"type": "ClaimValuesChanged",
"version": "1.0",
"sphere": "d0d8269f-7df9-4bf1-9e2d-03a14f668893",
"subscriber": "8849579f-d7ec-494b-b654-45f8f97aee0d",
"application": "your-application-id",
"subscription": "fd1d2404-eef3-4e88-a7d2-8d41689b8f71",
"payload": {
"claims": {}
}
}
| Field | Notes |
|---|---|
id | Stable unique identifier for this event. Use it as the dedup key if you store events on your side. |
timestamp | When LuxID generated the event. ISO local date-time, no timezone (e.g. 2026-05-27T09:53:44.609). |
type | What kind of event this is. The type determines what the payload carries. |
version | The schema version of payload for this type. Different versions of the same type can have slightly different payload fields. |
sphere, subscriber, application, subscription | Optional context fields filled in when applicable. Use them to scope your reaction. |
payload | Type-specific data. Treat as object; defensively handle missing fields. |
The current catalogue of event types is not enumerated in the OpenAPI document - the swagger only declares the envelope. Ask your LuxID Account manager for the up-to-date list of event types, the payload shape per type, and the version history.
Search by time range
The mandatory parameters are from and to. Both are ISO local date-times with no timezone (for example 2026-05-27T00:00:00); the trailing-Z (UTC) and offset (+02:00) forms are rejected with 400 Failed to convert. The window must be 24 hours or less - a wider range returns 400 BAD_REQUEST "Attribute from and to has wrong format". The range is from inclusive, to exclusive.
curl -sS \
-H "X-Client-Id: $LUXID_CLIENT_ID" \
-H "X-Client-Secret: $LUXID_CLIENT_SECRET" \
"https://api-uat.luxid.lu/services/luxid-partner-api/events/search?from=2026-05-27T00:00:00&to=2026-05-27T23:59:59&page=0&pageSize=50"
Response (today the only event type emitted is ClaimValuesChanged; other types are planned - see the caution at the top of Events and Event Hub):
{
"page": 0,
"pageSize": 50,
"total": 1,
"items": [
{
"id": "7095cea0-becf-4ec8-9ed1-2c0b86adbfa5",
"timestamp": "2026-05-27T09:53:44.609",
"type": "ClaimValuesChanged",
"version": "1.0",
"sphere": "d0d8269f-7df9-4bf1-9e2d-03a14f668893",
"subscriber": "8849579f-d7ec-494b-b654-45f8f97aee0d",
"application": "your-application-id",
"subscription": "fd1d2404-eef3-4e88-a7d2-8d41689b8f71",
"payload": { "claims": {} }
}
]
}
The envelope is the standard pagination envelope described in Getting Started: page, pageSize, total, items.
| Query param | Default | Notes |
|---|---|---|
from | (required) | Inclusive lower bound. |
to | (required) | Exclusive upper bound. |
page | 0 | Zero-based page index. |
pageSize | 10 | Maximum number of events per page. |
There is no documented upper bound on pageSize in the OpenAPI document. In practice, pick a value that keeps response sizes reasonable (50-200) and paginate.
Polling strategy
A typical polling integration looks like this:
- Persist a checkpoint on your side: the timestamp of the last event you processed. Initialise it to "now minus one hour" (or whatever back-fill makes sense for you) on first boot.
- Every minute (or whatever cadence makes sense), call
GET /events/search?from=<checkpoint>&to=<now>. Start atpage=0and keep advancing pages until(page+1) * pageSize >= total. - Process each event idempotently, keyed on
event.id. If the same event id ever appears twice (a poll overlap or a retry), your processor should detect it and no-op. - Advance the checkpoint to the
tovalue you sent (not to thetimestampof the last event you saw - clock skew and pagination edge cases can leave a small gap). - Back off and retry on 5xx and on rate-limit responses; do not advance the checkpoint until the page batch succeeded.
This is more conservative than a webhook setup, but it is also resilient to your back-end being offline: the checkpoint advances only when you have successfully processed everything in the window.
Idempotency: why event.id matters
A polling loop will inevitably re-fetch the same event at some point - retries, restarts, an operator running the loop manually for a back-fill. Your handler must be safe to call twice with the same event. The simplest version: store event.id in a "processed events" table or set; check it on entry; skip if already there. Combine this with a "last seen timestamp" per event id if you also need to ignore very old replays.
Errors you may see
| Status | When | What to do |
|---|---|---|
400 | Missing/invalid from or to, a window wider than 24 hours, malformed pagination, or a non-local time format. | Use ISO local date-times (no Z/offset), keep the window to 24 hours or less, and recheck the parameter values. |
403 | Your credentials are valid but you are not entitled to read events for the implied scope. | Confirm with your LuxID Account manager that the Event Hub is enabled for your partnership. |
404 | The endpoint or a scoped resource was not found. | The /events/search path is fixed; a 404 here usually points to a misconfigured base URL. |
Typical use cases
These illustrate what the Event Hub is designed for once the broader event catalogue is emitted. Today only ClaimValuesChanged is available (see event types), so the subscription and sign-in examples below are forward-looking.
- Audit trail mirroring. Pull events daily into your data lake or SIEM. The
idfield gives you a natural primary key; thetimestamplets you partition by day. - Reconciliation jobs. A nightly job reconciles subscription state on your side against the
subscription.createdandsubscription.deletedevents (planned). Anything missing on either side gets fixed. - Triggers for downstream workflows. Your back-end watches for
subscription.createdevents to open a welcome flow, or foruser.signed-into refresh a "last seen" timestamp on a partner-side record (both planned).
Webhook delivery
If you would prefer a push model rather than polling, the webhook layer documented at Webhooks and events API delivers the same events to a URL you host. The data shape on the wire is the same as the Event Hub envelope; the difference is who initiates the call.