Stream session events

GET /api/verification/:sessionId/events — the Server-Sent Events stream, what it sends, how reconnection behaves, and when to prefer it over polling.

Last updated: 2026-09-04

Opens a Server-Sent Events stream for one verification session, so a waiting page updates the moment the session reaches a verdict instead of on the next poll.

GET https://api.eidas-pro.com/api/verification/{sessionId}/events

Like the status endpoint, this route takes no API key: it is opened by the shopper's browser, which cannot hold a merchant secret. The session id is the capability, and the same per-session ceiling of 120 requests per minute applies.

Opening the stream

const events = new EventSource(`https://api.eidas-pro.com/api/verification/${sessionId}/events`);

events.onmessage = (event) => {
    const update = JSON.parse(event.data);

    if (["verified", "rejected", "expired"].includes(update.status)) {
        events.close();
    }
};

The response is text/event-stream with caching and proxy buffering disabled, so updates are not held back by an intermediary.

What the stream sends

Three kinds of line arrive, in this order:

  1. A connection comment: connected, written immediately. Comments are not events; EventSource ignores them, and they exist to defeat proxies that hold an idle response open with nothing in it.
  2. A status message, sent straight away, carrying the session's current state. You never have to poll once first to learn where the session already is.
  3. Further status messages, one each time the session's state changes.

Every message is an unnamed event, so a browser reads them all through onmessage. There is no event: field to switch on.

The payload matches the shape the status endpoint returns — sessionId, verificationType, status, verified, an error object for rejected and expired, and completedAt:

data: {"sessionId":"0f3c1c2b-...","verificationType":"age","status":"pending"}

Between messages the server writes a : heartbeat comment every 30 seconds. It carries no data; its only job is to keep the connection from being reaped by an idle timeout somewhere in the middle. Ignore it — EventSource already does.

When the stream closes

  • On a verdict. After the session reaches verified, rejected, or expired, the final status message is sent and the connection is closed a moment later, once the client has had time to receive it.
  • Already finished when you connect. If the session was already terminal, you still get its status message first, then the close. Connecting late is safe.
  • On a server restart. A graceful shutdown sends one last message — {"type":"shutdown","message":"Server is shutting down"} — before closing. Its shape is different from a status update, so check for a status field before treating a message as one.

Reconnection

EventSource reconnects on its own when a connection drops. Two things are worth knowing about what happens next:

  • The server sends no retry: interval, so the browser's default backoff applies.
  • There is no event id and no replay. A reconnect does not resume where the last one stopped — but it does not need to, because the handler sends the session's current state as the first message on every connection. You get where the session is, not the events you missed.

That makes the stream self-healing for a state machine like this one, where only the latest state matters. If your logic depends on observing every intermediate transition, use the current state and your own record of what you have already seen, not the stream's ordering.

A terminal message means the stream is finished. Close the EventSource yourself when you see one, or the browser will keep reconnecting to a session that will never change again.

Stream or poll?

Prefer the stream when the waiting page is a browser you control: it removes the delay between a verdict and the shopper seeing it, and one open connection is cheaper than a request every two seconds.

Poll the status endpoint instead when the client cannot hold a long-lived connection — a server-side job, a runtime with no EventSource, or a network path that terminates idle connections aggressively.

Either way, both routes are unauthenticated conveniences for the waiting UI. The verdict your server acts on comes from the result endpoint.

Failures

StatuscodeCause
400VALIDATION_ERRORThe path segment is not a UUID.
404NOT_FOUNDNo session with that id.
429RATE_LIMIT_EXCEEDEDPer-session or per-IP ceiling reached. Wait the number of seconds in the Retry-After header.

All three use the standard envelope — see errors and status codes. Validating the session id as a UUID before you open the stream avoids the 400 entirely.