> For the complete documentation index, see [llms.txt](https://docs.empe.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.empe.io/develop/verifier/api-reference/verification-sessions.md).

# Verification Sessions

A **verification session** tracks a single OpenID4VP exchange from the moment you create an authorization request until the holder's presentation is verified (or the session errors out). When you create an authorization request, the Verifier returns a `verificationSessionId`; you use that identifier to read the session's current state, or to subscribe to live updates over a **Server-Sent Events (SSE)** stream.

This page documents the two session endpoints: reading a session once with `GET /verification-sessions/{sessionId}`, and watching it in real time with `GET /verification-sessions/{sessionId}/events`.

***

## Overview

* A session is created for you by the authorization-request endpoints (see [Defining What Credentials to Request](/develop/verifier/server-side-vp-query.md)). You do not create sessions directly.
* Every session belongs to a registered verifier and carries a **state** that advances as the holder interacts with the request.
* You can observe a session two ways:
  * **Poll** the session with `GET /verification-sessions/{sessionId}` whenever you need its latest state.
  * **Subscribe** to `GET /verification-sessions/{sessionId}/events` and react to `session` events as the Verifier pushes them, which avoids polling.
* Both endpoints require a valid **OIDC JWT Bearer token** (`Authorization: Bearer <token>`). They carry no specific role requirement (see [Authentication](/develop/verifier/authentication.md)).

***

## Session States

A session moves through the following states. Read the current value from the session's **`state`** field.

* **`RequestCreated`** — the authorization request has been created and is waiting for a wallet to pick it up. This is the initial state.
* **`RequestUriRetrieved`** — a wallet has fetched the request URI and is in the process of responding.
* **`ResponseVerified`** — the holder returned a presentation and the Verifier successfully verified it. This is the terminal success state.
* **`Error`** — the session failed (for example, an invalid presentation was supplied). The **`errorMessage`** field describes what went wrong. This is the terminal failure state.

Treat `ResponseVerified` and `Error` as final outcomes; once a session reaches either, no further state changes occur.

***

## Get a Verification Session

**`GET /verification-sessions/{sessionId}`**

Returns the verification session identified by `sessionId`. Use this to read the session's current state on demand.

### Path Parameters

* **`sessionId`** (string, required) — the verification session identifier returned when the authorization request was created.

### Response Body

A `200 OK` response returns the session record:

* **`id`** — the session identifier.
* **`verifierId`** — the identifier of the verifier that created the session (may be a DID).
* **`state`** — the current session state (see [Session States](#session-states)).
* **`authorizationRequestId`** — the authorization request identifier, present for hosted requests.
* **`authorizationRequestUri`** — the `openid4vp://...` URI the wallet opens to fulfill the request.
* **`authorizationResponseRedirectUri`** — the redirect URI supplied when the request was created, if any.
* **`expiresAt`** — ISO timestamp when the request expires, if set.
* **`errorMessage`** — the last error observed in the session lifecycle, present when `state` is `Error`.

**Example response**

```json
{
  "id": "18b760b1-4ab8-4d38-9d42-6b4c25a4d2e0",
  "verifierId": "verifier-empe",
  "state": "RequestCreated",
  "authorizationRequestId": "1b8a6a8b-2ac1-4f0b-9d9c-6b9c859b1af2",
  "authorizationRequestUri": "openid4vp://?request_uri=...",
  "authorizationResponseRedirectUri": "https://verifier.example.com/callback",
  "expiresAt": "2026-06-22T12:34:56.789Z"
}
```

Once the holder has presented an `EmployeeBadge@1.0:sd-jwt` credential and the Verifier has checked it, the same call returns `"state": "ResponseVerified"`.

***

## Watch a Verification Session (SSE)

**`GET /verification-sessions/{sessionId}/events`**

Opens a **Server-Sent Events (SSE)** stream for the session. The Verifier immediately emits the session's current state, then pushes a new event every time the state changes — so you can drive UI updates without polling.

### Path Parameters

* **`sessionId`** (string, required) — the verification session identifier.

### Event Types

The stream emits two kinds of events, distinguished by the SSE `event:` field:

* **`session`** — carries the full session record as its `data` payload. The same fields as the [`GET` response](#response-body) are included, serialized as JSON. The first `session` event reflects the session's current state at subscription time; each subsequent one corresponds to a state change.
* **`ping`** — a heartbeat with the `data` payload `keepalive`, emitted every **15 seconds**. It carries no session data; its only purpose is to keep the connection alive and let you detect a dropped stream. Ignore `ping` events in your handler.

**Example stream**

```
event: session
data: {"id":"18b760b1-4ab8-4d38-9d42-6b4c25a4d2e0","verifierId":"verifier-empe","state":"RequestCreated","authorizationRequestId":"1b8a6a8b-2ac1-4f0b-9d9c-6b9c859b1af2","authorizationRequestUri":"openid4vp://?request_uri=...","expiresAt":"2026-06-22T12:34:56.789Z"}

event: ping
data: keepalive

event: session
data: {"id":"18b760b1-4ab8-4d38-9d42-6b4c25a4d2e0","verifierId":"verifier-empe","state":"RequestUriRetrieved","authorizationRequestId":"1b8a6a8b-2ac1-4f0b-9d9c-6b9c859b1af2","authorizationRequestUri":"openid4vp://?request_uri=...","expiresAt":"2026-06-22T12:34:56.789Z"}

event: session
data: {"id":"18b760b1-4ab8-4d38-9d42-6b4c25a4d2e0","verifierId":"verifier-empe","state":"ResponseVerified","authorizationRequestId":"1b8a6a8b-2ac1-4f0b-9d9c-6b9c859b1af2","authorizationRequestUri":"openid4vp://?request_uri=...","expiresAt":"2026-06-22T12:34:56.789Z"}
```

The stream stays open after a terminal state; close it from the client once you observe `ResponseVerified` or `Error`.

### Consuming the Stream with `EventSource`

In the browser, use the native [`EventSource`](https://developer.mozilla.org/en-US/docs/Web/API/EventSource) API. Because `session` and `ping` are **named** events, register a listener for each with `addEventListener`; the default `onmessage` handler only fires for unnamed events and will not receive them.

```javascript
const sessionId = "18b760b1-4ab8-4d38-9d42-6b4c25a4d2e0";
const source = new EventSource(
  `https://verifier.example.com/verification-sessions/${sessionId}/events`
);

source.addEventListener("session", (event) => {
  const session = JSON.parse(event.data);
  console.log("Session state:", session.state);

  if (session.state === "ResponseVerified") {
    console.log("Holder verified — grant access.");
    source.close();
  } else if (session.state === "Error") {
    console.error("Verification failed:", session.errorMessage);
    source.close();
  }
});

source.addEventListener("ping", () => {
  // Heartbeat — connection is alive; nothing to do.
});

source.onerror = (error) => {
  // The connection dropped; EventSource reconnects automatically.
  console.warn("SSE connection error:", error);
};
```

The browser's `EventSource` does not let you set custom request headers, so it cannot attach an `Authorization: Bearer` token directly. Because this endpoint requires a valid token, the browser must not connect to it directly in production. Instead, terminate the SSE stream behind your own backend: hold the Bearer token there, subscribe to the Verifier's stream with a server-side SSE client (or HTTP client that streams the response), and relay the `session` and `ping` events to the browser over a route on your own origin. See [Front-End Integration](/develop/verifier/frontend-integration.md) for a full backend-relay example. Only in local development with `AUTH_DISABLED=true` can the browser connect to the endpoint directly.

***

## Notes

* Sessions are created by the authorization-request endpoints; this page covers reading and watching them. See [Defining What Credentials to Request](/develop/verifier/server-side-vp-query.md) for how a session begins.
* Authentication is an OIDC JWT Bearer token; these endpoints require a valid token but no specific role.
* The SSE stream is the recommended way to react to verification outcomes in near real time; fall back to polling `GET /verification-sessions/{sessionId}` where a long-lived connection is impractical.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.empe.io/develop/verifier/api-reference/verification-sessions.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
