Setting up evidence pack encryption

Every aml-identitycheck in Nexiel Verify, and every screening decision in Nexiel Screen, produces an “evidence pack”: the identity details checked, the decision itself, and the exact matching engine version and thresholds behind it. Nexiel encrypts it to a key you control and hands it to you once. This page covers what that pack contains, how to register the key that reads it, and what happens if you lose that key.

What an evidence pack is, and why Nexiel does not keep it

AMLR (the EU Anti-Money Laundering Regulation) requires the obliged entity, meaning your organization, not Nexiel, to retain evidence of the customer due diligence and screening it relied on for a decision. Nexiel is infrastructure your organization uses to make that decision. It is not the obliged entity, and it should not become the place a growing pile of another company's regulated evidence sits indefinitely.

An evidence pack is how Nexiel resolves that split. Instead of storing the disclosed identity details and the decision Nexiel made on them, Nexiel packages both, plus the frozen decision artifact that pins the exact engine version and thresholds in force, encrypts the package to a public key you registered, and delivers the ciphertext to you. Only your own private key can decrypt it. Nexiel never has that key, so Nexiel has nothing left to keep, and nothing a breach of Nexiel's own systems could ever expose.

This applies only to AML-relevant checks: Nexiel Verify's aml-identity check type, and every Nexiel Screen decision. Nexiel Age's age-verification checks have no CDD or AML purpose at all, and are unaffected. They keep their existing boolean-proof-only design: a yes/no answer such as age_over_18 and nothing else, with no evidence pack to register a key for.

What is inside

Decrypted, an evidence pack holds:

The encryption itself is JWE Compact Serialization, ECDH-ES key agreement, A256GCM content encryption, on the P-256 curve, the same standards-based primitives (via the jose library) used elsewhere on this platform. Nothing about the scheme is proprietary or hand-rolled.

What Nexiel keeps instead

A single audit row per decision: the session or request id, your client id, the timestamp, the classification, the frozen-artifact hashes above, and a SHA-256 hash of the ciphertext that was delivered to you. That hash proves a specific evidence pack was generated and handed off. It reveals nothing about what was inside it. Nexiel never retains the plaintext, the claim values, or your private key.

Registering a key from the dashboard

Key registration lives on the customer dashboard, gated behind sign-in and an approved KYB status, the same account that already manages your API keys and request history:

You can register more than one active key at once, for example to roll in a replacement before revoking an old one. Revoke a key from the same page once you have confirmed its replacement is working and nothing still depends on it.

Losing the private key

Nexiel keeps no copy of your private key, so if you lose it, Nexiel cannot recover it for you. That costs you the ability to decrypt future evidence packs, the ones generated after the loss. It does not touch any evidence pack you already decrypted and saved yourself. That plaintext is your own record from the moment you received it, independent of whatever later happens to the key.

Screening and verification do not stop while you sort this out. A missing or revoked key is never an error condition for a decision itself, only for the evidence pack attached to it: Nexiel simply has nothing to encrypt to, and Screen and Verify decisions proceed normally either way. Generate and register a replacement key as soon as you can, and revoke the lost one from the same page. Any decision made in the gap between losing the old key and registering a new one produces no evidence pack at all, since Nexiel never holds a fallback plaintext copy to hand you once a key exists again.

Where the evidence pack arrives

Screen delivers it inline, in the same synchronous POST /v1/screen response as the decision itself, as an evidencePack field. Nothing about Screen ever needs a ciphertext store: it is generated and sent in the same request, and capturing it is your responsibility the moment you receive it.

Verify's aml-identityflow works differently, because the decision completes on the wallet's own callback, not on a request from your own backend. The wallet callback reply never carries the evidence pack: your own backend collects it afterward, with a follow-up GET /v1/verify/sessions/{sessionId} call. That ciphertext is delivered exactly once, then purged, either right after your first successful fetch or after 7 days if you never fetch it, whichever comes first.

See the Screen API quickstart and the Verify API quickstart for the full request/response examples.

Nexiel never sees or stores the private key

The key pair is generated in your own browser, and only the public half is ever exported for upload. The registration endpoint also checks the shape of anything it receives and rejects a JWK carrying a private-key component outright, a safeguard against a modified client, a compromised browser extension, or a bug ever sending one by mistake. Nexiel's own server code only ever calls the encrypt half of this scheme in production. There is no code path in production that decrypts an evidence pack, because there is no code path that ever holds the key such a decryption would need.

What generate-key-form.tsx runs in your browser
const keyPair = await crypto.subtle.generateKey(
  { name: 'ECDH', namedCurve: 'P-256' },
  true,
  ['deriveKey', 'deriveBits'],
);

// Downloaded to your device immediately, never sent anywhere.
const privateKeyJwk = await crypto.subtle.exportKey('jwk', keyPair.privateKey);

// Only this half is ever uploaded to Nexiel.
const publicKeyJwk = await crypto.subtle.exportKey('jwk', keyPair.publicKey);