BouncerBouncerDocs

Sessions

Understanding verification sessions in Bouncer

A session in Bouncer represents a single age verification attempt. Understanding the session lifecycle is crucial for integrating Bouncer effectively.

Session Lifecycle

Status Flow

created → pending → verification_started → completed
                            ↓
                    verification_kyc → completed

created or pending → completed (success: true)       re-verification shortcut
completed (success: false) → verification_started    user retries with their ID
any open status → cancelled                          device sessions only

Session Statuses

StatusDescription
createdSession created via API, user not yet redirected
pendingUser has visited the verification page
verification_startedUser has begun the liveness check
verification_kycUser is performing ID document scanning
completedVerification finished (check success field for result; success: false can still change while the session is open)
cancelledDevice sessions only: replaced by a newer dynamic QR scan on the same device

Session Parameters

When creating a session, you can configure:

ParameterRequiredDescription
age_targetYesTarget age to verify (8, 13, 16, 18, 21, 25, or 30)
redirect_urlYesWhere to send the user after a successful verification
webhook_urlNoURL to receive real-time status updates. Keep it to 255 characters or fewer
force_kycNoRequire ID verification. The verification cookie can still skip it: to check a document every time, also send force_verification: true (see KYC)
force_verificationNoRequire full verification every time; do not use verification cookie to skip
metadataNoCustom data to attach (e.g., order ID)
expiration_timeNoSession lifetime in seconds, counted from creation (60-3600)

See the Create Session API for complete request/response details.

Session Expiration

Sessions have a configurable expiration time, counted from when the session is created (expires_at is issued_at plus expiration_time):

  • Default: 300 seconds (5 minutes)
  • Minimum: 60 seconds
  • Maximum: 3600 seconds (1 hour)

After expires_at, the verification page shows Session expired and no new scan can start. A scan that reached Bouncer before expires_at can still be decided after it, and then validation.completed is sent. There is no expired status: the status API keeps returning the last status reached. If a user's session expires, you'll need to create a new one from your site: for sessions created through the API, the Start a new session button on the expired screen does not create one.

Verification Flow

Age Estimation Flow

  1. User visits verification page
  2. Liveness check is performed
  3. System estimates age from facial features
  4. If liveness is confirmed and estimated age ≥ target age → SUCCESS (unless the session requires an ID document)
  5. If estimated age < target age, or no estimate is returned → Continue to the KYC flow, on the same page

KYC Flow

When KYC is required (the age estimate did not reach the target, or force_kyc: true):

  1. After the face scan, user scans their ID document
  2. System checks that it is a physical document, that its photo matches the user's face, and reads the birth date
  3. Age calculated from document birth date (if the date cannot be read, from an age estimate on the document photo)
  4. If age ≥ target age AND all checks pass → SUCCESS
  5. Otherwise → FAILURE. While the session is open, the user can tap Verify age with your ID on the failure screen and try again, so a failure can later become a success

Failure Reasons

A session can only fail at the ID document check: a face scan alone never fails it. The API does not return a reason (success is false, with no reason field), and the user sees a generic failure screen. Common reasons include:

ReasonDescription
UnderageUser's verified age is below the target
Face mismatchFace doesn't match ID photo
Not a physical documentThe document was not recognized as a physical ID document

Bouncer may add detail in a metadata.facetec block. It is reserved: its content is not part of the API contract and can change, so do not build logic on it.

Polling vs Webhooks

You can check session results two ways:

Polling

Query the Get Session Status API periodically until status is completed and success is true, or until expires_at plus a short grace period has passed. A completed session with success: false can still become true while the session is open, and an abandoned session never reaches completed.

Configure a webhook_url when creating the session to receive real-time notifications. Treat every webhook as possibly the only delivery for that event: confirm the result with the status API, and poll if a webhook does not arrive. The same event can reach you more than once, and one session can send validation.completed with success: false and later with success: true, so process webhooks idempotently by session id and never downgrade a session you have seen as success: true. See Webhooks for details.

Best Practices

  1. Always set a redirect_url: It is required, and it is where the user goes after a successful verification (there is no redirect after a failure)
  2. Use webhooks and polling together: React to webhooks, and confirm with the status API, polling if a webhook does not arrive
  3. Handle expiration gracefully: Provide users a way to restart verification
  4. Store session IDs: Map sessions to your internal user/order IDs
  5. Validate success server-side: Never trust client-side success indicators

On this page