Inyo

Verification Sessions

A session represents one identity verification. Creating it returns a widget_url you deliver to your customer, and a session_id you use to correlate the result.


Create a Session

Endpoint: POST /v1/sessions
Authentication: Bearer token with the sessions scope

curl --request POST \
  --url https://{FQDN}/v1/sessions \
  --header "Authorization: Bearer $ACCESS_TOKEN" \
  --header 'Content-Type: application/json' \
  --data '{
  "user_ref": "user-123",
  "language": "es",
  "delivery": { "mode": "webhook" }
}'
{
  "session_id": "9f1c8e42-7c3e-4f2b-9d7a-2b1e5c8f4a10",
  "status": "pending",
  "widget_url": "https://{FQDN}/verify/8Kd2mQ…"
}

Request Fields

FieldTypeRequiredDescription
user_refstring (1-255)YesYour identifier for the person being verified. Echoed back in every result
prefillobjectNoKnown data about the person β€” see Prefill
data_checkbooleanNofalse (default) verifies the document as presented. true additionally compares extracted data against prefill β€” see Data Checks
deliveryobjectNoHow the result reaches you. Defaults to {"mode": "webhook"}
languagestringNoWidget language, xx or xx-XX (e.g. en, pt, es, pt-BR). Falls back to your configured default
max_capture_attemptsinteger (1-10)NoOverrides your tenant default for this session only

Response Fields

FieldDescription
session_idUse this to correlate results and to call GET /v1/sessions/{session_id}
statusAlways pending on creation
widget_urlThe customer-facing link. Contains a single-use code valid for 48 hours

Prefill

prefill carries what you already know about the person. It has two distinct effects.

FieldEffect
document_typepassport, drivers_license, or identity_card. Locks the widget to this document β€” the type-selection screen is skipped, and a different document is rejected. Omit it to let the customer choose
document_numberValidated for format at this call (see below), and available for cross-checking
issuing_stateUS state code or name for driver's licenses; ISO 3166-1 alpha-3 country for passports and identity cards. Sharpens format validation
nationalityISO 3166-1 alpha-3. Used to resolve the jurisdiction when issuing_state is absent
first_name, last_nameAvailable for cross-checking
date_of_birthYYYY-MM-DD. Available for cross-checking
{
  "user_ref": "user-123",
  "prefill": {
    "document_type": "drivers_license",
    "issuing_state": "PA",
    "document_number": "31612967",
    "first_name": "Ana",
    "last_name": "Silva",
    "date_of_birth": "1988-03-04"
  }
}

Prefill fields other than document_type do not change the decision unless you set data_check: true. Without it, the values are carried for comparison and reported in the result, but a mismatch does not route the session anywhere.

prefill.document_number is validated at this call, however: a number that violates its jurisdiction's known format is rejected with 422 rather than accepted and failed later. Check a number before you get here with the validator endpoint.


Data Checks

Set data_check: true to verify that the document belongs to the person you expected β€” not just that the document is genuine.

{
  "user_ref": "user-123",
  "data_check": true,
  "prefill": {
    "first_name": "Ana",
    "last_name": "Silva",
    "date_of_birth": "1988-03-04"
  }
}

With data_check: true:

  • Extracted data is compared field by field against the prefill payload.
  • The result carries prefill_comparison (per-field outcomes, including fuzzy name-match scores) and prefill_mismatches (the field names that disagreed).
  • A mismatch adds a failing soft check, routing the session to in_review rather than declining it.

Names are compared with fuzzy matching against a configurable similarity threshold, so ordinary spelling and transliteration variance does not create false mismatches. data_check: true without a prefill payload is a 422 β€” there would be nothing to compare against.


Delivery

ModeFieldsBehavior
webhook (default)β€”The result is POSTed to your configured webhook_url
redirectredirect_url (required)The customer is returned to your URL with the outcome and a signature
{ "delivery": { "mode": "redirect", "redirect_url": "https://you.example/kyc-done" } }

Requesting webhook mode without a webhook_url configured for your tenant is a 422. See Receiving Results for signature verification in both modes.


Error Responses

All of these return 422 with a detail explaining the specific cause:

CauseNotes
delivery.mode is webhook but no webhook_url is configuredAsk Inyo to register your endpoint, or use redirect mode
delivery.redirect_url missing in redirect modeRequired whenever mode is redirect
document_type is not enabled for your tenantThe message lists the document types you may request
The document's issuing jurisdiction is not accepted for that document typeThe message lists the jurisdictions you accept
prefill.document_number failed format validationThe message names the rule that rejected it
data_check: true with no prefill payloadProvide at least one comparable prefill field

Authentication and authorization failures return 401 or 403 β€” see Authentication.


Retrieve a Session

Endpoint: GET /v1/sessions/{session_id}
Authentication: Bearer token with the sessions scope

This is the authoritative record of a verification. Poll it when you need a guarantee rather than a push, to reconcile a webhook you may have missed, or to read the outcome of a session that went to manual review.

curl --request GET \
  --url https://{FQDN}/v1/sessions/$SESSION_ID \
  --header "Authorization: Bearer $ACCESS_TOKEN"
{
  "session_id": "9f1c8e42-7c3e-4f2b-9d7a-2b1e5c8f4a10",
  "user_ref": "user-123",
  "status": "in_review",
  "step": "done",
  "delivery_mode": "webhook",
  "result": { "…": "the normalized result, updated in place" },
  "created_at": "2026-07-31T14:02:11.481Z",
  "updated_at": "2026-07-31T14:04:57.902Z"
}
FieldDescription
statuspending, approved, declined, in_review, or expired
stepHow far the customer got: document_front, document_back, selfie, or done
delivery_modewebhook, redirect, or sync (a server-to-server verification)
resultThe full normalized result once available, null before then. Updated in place when an analyst decides

Sessions are strictly tenant-scoped. Another tenant's session_id returns 404 β€” never a partial disclosure.


Validate a Document Number

Endpoint: POST /v1/validators/document-number
Authentication: none required

A stateless format check against the same registry the verification pipeline uses: US driver's-license formats for all 50 states and DC, per-country passport formats, and identity-card formats where the jurisdiction defines one. Nothing is stored and no verification is consumed. Useful for validating input in your own form before creating a session.

curl --request POST \
  --url https://{FQDN}/v1/validators/document-number \
  --header 'Content-Type: application/json' \
  --data '{
  "document_type": "drivers_license",
  "number": "31612967",
  "issuing_state": "PA"
}'
{
  "document_type": "drivers_license",
  "number": "31612967",
  "issuing_state": "PA",
  "valid": true,
  "rule": "us_dl:PA",
  "detail": "document number matches the PA license format"
}

valid is deliberately three-valued:

ValueMeaningHow to treat it
trueMatches the known format for that jurisdictionAccept
falseViolates the known formatReject before creating the session
nullNo rule exists for that jurisdictionAccept β€” an unknown jurisdiction is never a failure

rule identifies which rule was applied β€” us_dl:PA, passport:USA, passport:generic, or us_dl:unknown_state when a license was submitted without a resolvable state (which yields valid: null). issuing_state is a US state code or name for driver's licenses, and an ISO 3166-1 alpha-3 country code for passports and identity cards.


Next Steps