> ## Documentation Index
> Fetch the complete documentation index at: https://docs.baselayer.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Hosted Sessions and Direct Verifications

> Which routes, webhooks and states belong to a hosted enrollment session, and which to a direct verification.

Baselayer verifies an identity in one of two ways. Each has its own routes, its own webhooks and its own identifier, and nothing mixes the two:

* A **hosted enrollment session**: the applicant completes a journey you published, on Baselayer's page. Your server never touches their personal data.
* A **direct verification**: you send an identity you collected yourself, server to server.

Both end in the same pairwise references, `individual_ref` and, when a business is involved, `business_ref`.

## Side by side

| | Hosted enrollment session | Direct verification |
| - | - | - |
| Start | `POST /onboarding/sessions` | `POST /identities/verifications` |
| Identifier | `session_id` (the `id` that starting a session returns) | `verification_id` |
| Read it | `GET /onboarding/sessions/{session_id}` | `GET /identities/verifications/{verification_id}` |
| Full outcome | `GET /onboarding/sessions/{session_id}/results` | The verification itself |
| List | None in the API: track sessions by `session_id` or `reference_id` | `GET /identities/verifications` |
| Completed | `OnboardingSession.completed` | `Verification.completed` |
| Failed | `OnboardingSession.failed` | `Verification.failed` |
| Reviewer decision | `OnboardingSession.updated` | `Verification.updated` |
| `Idempotency-Key` | Not taken: a retry starts a second session; use `reference_id` to tell them apart | Required |
| Re-verify | Start a new session | `POST /identities/individuals/{individual_ref}/reverify` |

## Which route to poll

* **Hosted:** wait for `OnboardingSession.completed`, then read `GET /onboarding/sessions/{session_id}/results`. Before the session completes, the results route answers `409`. The webhook is a summary; the results are the source of truth.
* **Direct:** poll `GET /identities/verifications/{verification_id}` until `state` is terminal, or subscribe to `Verification.completed` and `Verification.failed`. Their payload is the verification exactly as that route returns it.

A `verification_id` never works on a session route, and a `session_id` never works on a verification route.

## States

A direct verification's `state` is one of `PENDING`, `EXECUTING`, `WAITING`, `COMPLETED`, `FAILED` or `EXPIRED`. A verification stopped internally reports `FAILED`.

The hosted session schema still lists `CANCELLED` for compatibility, but a session stopped internally reads `FAILED` on `GET /onboarding/sessions/{session_id}` and in its webhooks too. You can treat both resources' terminal states the same way.

## Re-verifying

To re-verify an individual you verified directly, call `POST /identities/individuals/{individual_ref}/reverify` with no body and a fresh `Idempotency-Key`. It answers `202` with a new direct verification; the `individual_ref` never changes. A retry with the same key returns the same verification; a key already used for a different request answers `422`. A new key while a verification is still running answers `409`.

`POST /identities/verifications` only starts new verifications. It does not take an `individual_ref`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.