Skip to content

Verification sessions

A verification session (public id vs_...) is the unit of work for a single customer verification attempt. You create it via the API, the customer opens it through the Web SDK or a hosted redirect, and it advances through a fixed, forward-only status machine.

created → opened → processing → completed | failed | expired | canceled

A session only ever moves forward — it never returns to an earlier state.

  • created — minted by your API call; not yet opened by a customer.
  • opened — the customer has loaded the hosted flow.
  • processing — capture is done and verification is running.
  • completed — verification finished and a VIC was minted. Emits verification_session.completed.
  • failed — verification ran but did not pass. Emits verification_session.failed.
  • expired — the session’s TTL elapsed before it completed. Emits verification_session.expired.
  • canceled — you canceled it via the API (see below).

Reaching completed, failed, or expired delivers the matching webhook event to your registered endpoint. canceled emits no webhook — it’s your own action, so there’s nothing to notify you of.

You can cancel a session only while it is still created or opened — before the pipeline has begun its work. Once a session is processing (or already in a terminal state), a cancel request is rejected with 409 not_cancelable.

Every session has a TTL, chosen at mint time with the ttl field:

ttl valueDuration
1h1 hour
24h24 hours (default)
3d3 days
7d7 days

If a session isn’t completed within its TTL it transitions to expired. Omit ttl to get the 24h default.

The client token is single-use-by-visibility

Section titled “The client token is single-use-by-visibility”

The one-time client_token (pbvs_...) — the value your frontend hands to PersonaBlocks.create() — is returned exactly once, on the create response. It is not included when you later retrieve or list the session: every subsequent read returns url: null and no client_token.

The mint call accepts a customer object with emailAddress and phoneNumber. Today these are validated but not yet persisted or used to prefill the flow — sending them has no effect on what the customer sees.

They’re part of the request contract so that when prefill ships, it becomes active without any change on your side: you can start sending them now, but don’t build logic that depends on them being reflected back or pre-filling the customer’s fields yet.