This page exists for one purpose: giving an AI coding assistant (Cursor or anything similar) enough real, current detail about Nexiel's APIs to write correct integration code on the first try, instead of guessing at an endpoint shape from a model's training data. Everything below, the field names, the status values, the error format, matches Nexiel Verify's actual OpenAPI spec and SDK types today.
Copy the block below into Cursor or any other AI coding assistant to add Nexiel Age verification to a signup flow. It names the real request/response fields from POST /v1/verify/sessions and GET /v1/verify/sessions/{sessionId} (see the Verify API reference), so an assistant given it has no reason to invent a field name, and it says explicitly which package not to install, since that is exactly the kind of detail a model is likely to get wrong by pattern-matching against a typical hosted-SaaS SDK.
I need to add Nexiel Age verification (an EUDI wallet age-over-18 check) to my
app's signup flow. Nexiel Age has no separate API of its own: it is Nexiel
Verify's POST /v1/verify/sessions endpoint, called with "checkType":
"age-verification".
Environment variables:
- NEXIEL_VERIFY_BASE_URL: base URL of a running Nexiel Verify instance
(e.g. https://compliance.nexiel.io in production, or http://localhost:3001
against a local sandbox-mode instance). This platform is self-hosted per
deployment, not a shared SaaS endpoint - ask me for the real production
value rather than guessing one.
- NEXIEL_VERIFY_API_KEY: optional. Omit it entirely against a sandbox-mode
instance (no auth required there). Required in production, sent as
"Authorization: Bearer <token>".
Do NOT run "npm install @nexiel/sdk" or import from "@nexiel/sdk". That is a
private internal package, not published to the public npm registry, and
installing it from this project will fail. Call the REST API directly with
fetch instead.
Implement:
1. A server-side route "POST /signup/age-check/start" that:
- Calls "POST {NEXIEL_VERIFY_BASE_URL}/v1/verify/sessions" with JSON body
{ "clientId": "<our Nexiel client id>", "checkType": "age-verification" },
header "Idempotency-Key: <a fresh UUID per attempt>", and header
"Authorization: Bearer ${NEXIEL_VERIFY_API_KEY}" only if that env var is set.
- The response is { sessionId, templateVersion, authorizationRequest,
authorizationRequestUri, expiresAt }. Persist only sessionId and expiresAt
against the in-progress signup record - never store authorizationRequest
or authorizationRequestUri beyond this one response.
- Return { sessionId, authorizationRequestUri, expiresAt } to the client.
authorizationRequestUri is an "openid4vp://..." deep link: render it as a
QR code for desktop and as a tappable link for mobile, so the user's EUDI
wallet app can open it. Use whatever QR library the project already has,
or add a small well-known one - that part is ordinary web development,
nothing Nexiel-specific.
2. A poller that, once the QR code or link is shown, polls
"GET {NEXIEL_VERIFY_BASE_URL}/v1/verify/sessions/{sessionId}" through our own
backend (never directly from the browser, so NEXIEL_VERIFY_API_KEY never
reaches the client) every few seconds until status is no longer "pending":
- status "completed" and decision.booleanProofs.ageOver18 === true: let
signup proceed.
- status "completed" and decision.booleanProofs.ageOver18 === false: block
signup with a clear "you must be 18 or older" message. Do not record
anything about this attempt beyond what we already log for every signup.
- status "expired" or "failed": show a retry action that starts a brand new
session (step 1 again). A session in either of these states cannot be
resumed.
- Stop polling once expiresAt has passed even without a terminal status.
3. Data handling, do not skip this: persist only sessionId, the boolean result
(ageOver18), and a timestamp against the signup record. Never persist
authorizationRequest, authorizationRequestUri, or any wallet-disclosed claim
beyond that one boolean - an age-verification check never returns a
birthdate or name in the first place, so there is nothing else to
accidentally store.
4. Error handling: a non-2xx response is JSON { "error": "<stable_code>",
"message": "<human-readable>" }, with an additional "retryAfterSeconds"
field on 429 responses. Handle at least:
- 429: surface retryAfterSeconds and wait that long before letting the user
retry, rather than hammering the endpoint immediately.
- 400: this means our own request was malformed - log it as a bug, never
show it to the end user as "verification failed".
- Network failures: retry with backoff. Never treat a network error as a
failed age check.
Write this using [React Server Actions / Next.js API routes / Express / our
actual stack - ask me which one if you're not sure, rather than assuming].sessionId, authorizationRequestUri, expiresAt, decision.booleanProofs.ageOver18, and the pending / completed / failed / expiredstatus values are the exact field and enum names in Nexiel Verify's real, published OpenAPI spec, not paraphrased ones.@nexiel/sdk is a genuine, checked fact: it is a private package, not published to npm today. An AI assistant that has seen plenty of import from '@stripe/...'-shaped code elsewhere will otherwise happily suggest installing a package that returns a 404 the moment someone tries it.error, message, optional retryAfterSeconds) matches both services' real, documented error response shape, not a generic REST assumption.age-verification check: no birthdate or name field exists in that response to accidentally store in the first place.The same approach, real field names pulled from the actual reference docs, an explicit “don't install the private SDK” caveat, and an explicit persisted-fields list, works for any other Nexiel integration:
POSSIBLE_MATCHhuman-review requirement intact rather than letting an assistant “simplify” it into an auto-clear.POST /v1/verify/sessions route, checkType: "aml-identity" instead of "age-verification", documented on the Verify API quickstart.For an AI assistant that reads a site's llms.txt automatically rather than being handed a prompt by hand, Nexiel publishes one at the site root: nexiel.eu/llms.txt. It covers the same ground at a glance, which service owns which route, why Nexiel Age is not a separate API, why the SDK is a private internal package that is not npm install-able outside Nexiel's own systems, the idempotency contract, and the human-in-the-loop rule for POSSIBLE_MATCH, plus links to every quickstart and reference page on this site.