Skip to main content
Version 0.1Draft

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.

info

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 doEndpoint
Search for events between two timestampsGET /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": {}
}
}
FieldNotes
idStable unique identifier for this event. Use it as the dedup key if you store events on your side.
timestampWhen LuxID generated the event. ISO local date-time, no timezone (e.g. 2026-05-27T09:53:44.609).
typeWhat kind of event this is. The type determines what the payload carries.
versionThe schema version of payload for this type. Different versions of the same type can have slightly different payload fields.
sphere, subscriber, application, subscriptionOptional context fields filled in when applicable. Use them to scope your reaction.
payloadType-specific data. Treat as object; defensively handle missing fields.
note

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 paramDefaultNotes
from(required)Inclusive lower bound.
to(required)Exclusive upper bound.
page0Zero-based page index.
pageSize10Maximum 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:

  1. 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.
  2. Every minute (or whatever cadence makes sense), call GET /events/search?from=<checkpoint>&to=<now>. Start at page=0 and keep advancing pages until (page+1) * pageSize >= total.
  3. 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.
  4. Advance the checkpoint to the to value you sent (not to the timestamp of the last event you saw - clock skew and pagination edge cases can leave a small gap).
  5. 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

StatusWhenWhat to do
400Missing/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.
403Your 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.
404The 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 id field gives you a natural primary key; the timestamp lets you partition by day.
  • Reconciliation jobs. A nightly job reconciles subscription state on your side against the subscription.created and subscription.deleted events (planned). Anything missing on either side gets fixed.
  • Triggers for downstream workflows. Your back-end watches for subscription.created events to open a welcome flow, or for user.signed-in to 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.

Updated 2026-05-18