Client SDKs

@nexiel/sdk (TypeScript) and nexiel-sdk(Python) are one client per service, generated request/response types kept fresh against each service's real openapi.json, real typed exceptions instead of raw thrown JSON, and built-in Authorization / Idempotency-Key header handling. Both wrap the same Screen API and Verify API documented elsewhere on this site. Nothing about the underlying routes or response shapes changes, only how much code you write to call them.

Not on npm or PyPI yet. @nexiel/sdk and nexiel-sdk are real, tested code generated from each service's own OpenAPI spec. Install either by cloning the repository and building from source in the meantime.

What waitForSessionCompletion adds

Both SDKs expose the raw Verify API primitives directly: initiateSession, getSession, listSessions, submitSessionResponse. Every real EUDI wallet integration needs the same thing after calling initiateSession: keep checking getSessionuntil the end user's wallet has responded. Without a helper for that, every integration hand-rolls its own poll loop. waitForSessionCompletion (TypeScript) and wait_for_session_completion (Python) are that loop, built in: they poll getSession on an interval until status leaves 'pending', and return the final session, including its decision once completed.

Quickstart: Nexiel Verify (AML identity)

This is the entire flow, start to finish. Compare it to a hand-rolled integration: you do not write the loop, pick the interval, or reason about the timeout. waitForSessionCompletion owns all three, with sensible defaults (poll every 2 seconds, give up after 2 minutes) you can override.

TypeScript
import { NexielVerifyClient } from '@nexiel/sdk';

const verify = new NexielVerifyClient({ baseUrl: 'https://compliance.nexiel.io' }); // sandbox mode: no apiKey needed

const session = await verify.initiateSession({
  clientId: 'your-client-id',
  checkType: 'aml-identity',
});

// Present session.authorizationRequest to the end user's wallet (a QR code
// or same-device deep link). See @nexiel/verify-widget for a drop-in UI.

const result = await verify.waitForSessionCompletion(session.sessionId);

if (result.status === 'completed' && result.decision) {
  console.log(result.decision.amlResult, result.decision.pepFlag, result.decision.sanctionedFlag);
  // The frozen decision artifact a regulator can use to re-derive exactly
  // what logic ran, months later.
  console.log(result.decision.frozenDecisionArtifact.gatesHash);
}
Python
from nexiel_sdk import NexielClient

nexiel = NexielClient(screen_base_url="https://compliance.nexiel.io", verify_base_url="https://compliance.nexiel.io")

session = nexiel.verify.initiate_session(client_id="your-client-id", check_type="aml-identity")

# Present session.authorization_request to the end user's wallet.

result = nexiel.verify.wait_for_session_completion(session.session_id)

if str(result.status) == "completed" and result.decision is not None:
    print(result.decision.aml_result, result.decision.pep_flag, result.decision.sanctioned_flag)
    print(result.decision.frozen_decision_artifact.gates_hash)

If the session is still 'pending' once the timeout elapses, both SDKs raise a dedicated error (NexielTimeoutError) carrying the session id, rather than returning a half-finished result you might mistake for a real outcome. The session itself may still complete later. Catch this, and either poll again or treat it as abandoned, whichever your product needs.

TypeScript: handling a slow wallet
import { NexielTimeoutError } from '@nexiel/sdk';

try {
  await verify.waitForSessionCompletion(session.sessionId, { timeoutMs: 30_000 });
} catch (error) {
  if (error instanceof NexielTimeoutError) {
    console.log(`Session ${error.sessionId} is taking longer than ${error.timeoutMs}ms. Keep the QR code up.`);
  } else {
    throw error;
  }
}

Quickstart: Nexiel Age

Nexiel Age is not a separate engine. It is the same Verify API, the same waitForSessionCompletion helper, and the same session shape as above. The only difference is checkType. Passing 'age-verification' instead of 'aml-identity' requests only the wallet's birthdate claim, for the sole purpose of computing an age_over_18 boolean server-side. That boolean is what you get back; the birthdate itself is discarded immediately and never stored, logged, or returned, and no name or nationality is ever requested. See the Age API docs for the full selective-disclosure walkthrough.

TypeScript
const session = await verify.initiateSession({
  clientId: 'your-client-id',
  checkType: 'age-verification', // the only change from the AML identity example above
});

const result = await verify.waitForSessionCompletion(session.sessionId);

if (result.status === 'completed' && result.decision) {
  console.log('age_over_18:', result.decision.booleanProofs['ageOver18']);
  // amlResult, pepFlag, sanctionedFlag, and frozenDecisionArtifact are all
  // null here: an age-verification check never runs the sanctions/PEP
  // matching engine, so there is nothing to screen and nothing to freeze.
}
Python
session = nexiel.verify.initiate_session(client_id="your-client-id", check_type="age-verification")
result = nexiel.verify.wait_for_session_completion(session.session_id)

if str(result.status) == "completed" and result.decision is not None:
    print("age_over_18:", result.decision.boolean_proofs["ageOver18"])

Error handling

Every non-2xx response raises a typed subclass of NexielApiError (NexielBadRequestError, NexielUnauthorizedError, NexielForbiddenError, NexielNotFoundError, NexielConflictError, NexielGoneError, NexielRateLimitError, NexielServerError), carrying the real HTTP status, a stable machine-readable code, and the parsed response body, never a raw JSON blob you have to shape-check yourself.

Nexiel Screen from the same SDK

Both SDKs also wrap Nexiel Screen's sanctions/PEP screening. POSSIBLE_MATCH always requires human review. The SDK never auto-clears it, and neither does the API underneath it.

TypeScript
import { NexielClient } from '@nexiel/sdk';

const nexiel = new NexielClient({ screenBaseUrl: 'https://compliance.nexiel.io', verifyBaseUrl: 'https://compliance.nexiel.io' });
const result = await nexiel.screen.screenName({ name: 'Jane Doe' });
console.log(result.classification); // 'CLEAR' | 'POSSIBLE_MATCH' | 'CONFIRMED_MATCH'

Related tools

Both SDKs regenerate their request/response types directly from each service's openapi.json on every release, so they can never silently drift out of sync with the APIs they wrap. See Verify API reference and Screen API reference for the full route-by-route documentation both SDKs are generated against.