The public contract.

Everything on this page is an illustrative public shape, published so a developer can size the integration before a call. It is deliberately not an endpoint inventory: the authoritative paths, field sets and headers are agreed per client, and infrastructure detail does not belong on a marketing site.

ILLUSTRATIVE · PUBLIC SURFACE ONLY · SHAPES SUBJECT TO AGREEMENT

Create a verification session.

The first of the two calls. Your server declares what it requires and what it is willing to receive; the response carries the one URL you send the person to.

Request fields — illustrative
FieldMeaning
assurance_levelThe level you require. One of humanity, low, substantial, high. Enforced server-side.
age_gate_minThe age gate to apply, if you want an age answer. A number you choose.
return_fieldsThe field set your server is willing to receive. Anything you omit is never sent.
redirect_urlWhere the person comes back to. It signals return, never the verdict.
webhook_urlOptional. Where the signed result is pushed, if you take the push path.

Authentication is a bearer client token, held server-side. It is scoped to your client, and the tokens issued to subjects under it are isolated from every other client’s.

Request

POST /v1/verification-sessions
Authorization: Bearer <your client token>
Content-Type: application/json

{
  "assurance_level": "substantial",
  "age_gate_min":    18,
  "return_fields":   ["verified", "meets_age", "age_gate_min"],
  "redirect_url":    "https://your-app.example/verify/return",
  "webhook_url":     "https://your-app.example/hooks/jerix"
}

Illustrative shape.

Response

201 Created

{
  "session_id": "vs_8K31QD…",
  "url":        "https://<verification-host>/s/8K31QD…",
  "expires_in": 900
}

Illustrative shape. A session is single-use and expires; a reused or expired session is refused.

Fetch a result.

The second call, for a backend that reads rather than receives. The payload contains exactly the field set you declared, and nothing adjacent to it.

Request and response

GET /v1/verification-sessions/{session_id}
Authorization: Bearer <your client token>

200 OK

{
  "verified":        true,
  "meets_age":       true,
  "age_gate_min":    18,
  "assurance_level": "substantial"
}

Illustrative shape. The live third-party integration takes the first three fields and nothing else.

Still in progress

200 OK

{
  "status": "pending"
}

Illustrative shape. A session that has not resolved has no verdict to report, and does not invent one.

Result fields — illustrative
FieldMeaning
verifiedThe verdict.
meets_ageWhether the holder clears the gate you declared. Never a date of birth.
age_gate_minThe gate that was applied, echoed back.
assurance_levelThe level the capture earned, frozen onto the credential.
subject_tokenA token for recognising the same person again, scoped to your client alone.

Larger field sets exist and are configured per client. No field set returns an image, a face embedding or chip data, because none of those is retained to return.

The signed webhook.

The push path. The signature is the whole point of it: an unsigned result arriving at your endpoint is a result anyone could have sent you.

Delivered to your endpoint

POST /hooks/jerix
X-Jerix-Signature: v1=<hex>
X-Jerix-Timestamp: <unix seconds>
Content-Type: application/json

{
  "event":        "verification.completed",
  "session_id":   "vs_8K31QD…",
  "verified":     true,
  "meets_age":    true,
  "age_gate_min": 18
}

Illustrative shape. Header and event names are agreed per client.

Verify over the raw body

Compute the signature over the bytes you received, before any JSON parsing or re-serialisation. A payload that round-trips through a parser is no longer the payload that was signed.

Reject a stale timestamp

Bound how old a delivery you will accept. That bound, plus the signature, is what makes a captured request useless to replay.

Expect a redelivery

Treat the handler as idempotent and key it on the session. A delivery that your endpoint failed to acknowledge will arrive again.

Rate limiting and replay prevention apply on our side as well, and every verification is written into a tamper-evident audit chain.

Assurance levels.

Four levels. Your server declares the one it requires; ours enforces it. A level is earned by how a capture happened, which is why it cannot be requested into existence.

The four levels
LevelEarned byTypical use
humanityA selfie with a detected face.Anti-bot. It establishes a person, not an identity.
lowA web capture.Low-risk signup, where the cost of a wrong answer is small.
substantialAn attested native capture, signed on the device with a single-use nonce.Standard onboarding.
highAn attested native capture plus a passport NFC chip read, with the signature chain verified to a national root.Banking, large loans, anything where the verdict is the control.

The step-up refusal.

When a capture earns less than you required, the result is a refusal that names what is missing — not a verdict quietly issued at a lower level. Your code never has to notice a downgrade, because there is never one to notice.

The refusal carries the step up, so the honest thing to do with it is usually to create a second session at the same level and send the person back for the capture that reaches it.

Worth knowing when you choose a required level: an Israeli ID card is a photo-only verification, because that chip is government-locked and cannot be read. Only a passport chip read reaches high.

Refusal

409 Conflict

{
  "verified":           false,
  "refusal":            "assurance_below_required",
  "required_assurance": "high",
  "earned_assurance":   "substantial",
  "step_up":            "nfc_chip_read"
}

Illustrative shape. You can see this against every level on the quickstart bench.

What this page deliberately does not publish.

A security officer will check for this, so it is stated rather than left to inference.

No endpoint inventory

The four shapes above are the public contract. A full route list, internal services and admin surfaces are not published, and the paths here are illustrative rather than authoritative.

No configuration or infrastructure detail

No environment-variable names, no hostnames — the verification host above is a placeholder — no deployment topology, no thresholds. Those reach a client under agreement, not through a marketing page.

No client names

The first third-party integration has been live since 30 August 2026. It is a gaming ticket platform, and that is the whole of what we will say about it.

No specimen that is a real person

Any document rendered on this site carries the state code UTO, which ICAO reserves for specimens. The identifiers in every payload above are synthetic.

OIDC discovery, token and userinfo endpoints

The standards-shaped surface an enterprise would place in front of an existing sign-in.

Not shippedSSO / OIDC / Entra. The signing core ships and runs in production; the four endpoints do not exist, so there is nothing to document here yet. Integrate over REST until they do.

Need the authoritative contract rather than the illustration? That is a conversation, and it is a short one. Ask us for it.

We will run these calls against a live session with you.

Bring a backend and a real passport. Twenty minutes, and the trust chain resolves offline in front of you.

Request a walkthrough