Every endpoint, parameter, and response schema for Nexiel Screen. Fetch the same spec as a machine-readable document at GET /openapi.json.
Requests to a production deployment require a bearer token. Mint one via the standard OAuth2 client-credentials grant against https://auth.nexiel.io/realms/nexiel/protocol/openid-connect/token using the client_id/client_secretpair from your dashboard's API Keys page — see this API's own quickstart for the exact curl command.
/healthReports the service-level mode (sandbox by default). This is distinct from a screening request's own mode (see POST /v1/screen). Returns 503 with status "draining" during the brief shutdown window between receiving SIGTERM and the process actually exiting, so a load balancer can stop routing new requests to this instance before it stops listening.
/v1/screenBearer auth (production mode)Runs the 4-layer hybrid matching engine (exact, full-text, Levenshtein, and phonetic, plus an AI/vector layer that is shadow-mode only and not yet used for live decisions) against `name`, `dob`, and `nationality`, and independently, if `walletAddresses` is supplied, an exact-match wallet-address lookup against sanctioned cryptocurrency addresses (currently OFAC SDN only, exact-list matching only, no exposure or clustering analysis, no entity attribution beyond what the source list states). The two checks are genuinely independent: a request may supply either, both, or neither. The returned top-level `classification` is the more severe of the two, and `wallet` always reports exactly which addresses were checked and which matched, even when none were supplied. In sandbox mode (the default, see the top-level API description) neither check ever touches real ETL-sourced data. `meta.humanReviewRequired` is the EU AI Act human-in-the-loop flag for POSSIBLE_MATCH results (wallet screening never produces POSSIBLE_MATCH: an address match is always CONFIRMED_MATCH, never an ambiguous score). `Idempotency-Key` is enforced server-side (see the header description): a repeated key with the exact same request returns the original response without re-screening, and the same key with a different request (including a different set of walletAddresses) returns a 409. Authenticated (production-mode) requests are also per-client rate limited with a token bucket: exceeding it returns a `429` with a `Retry-After` header. Separately, a per-client, self-baselined anomaly signal is evaluated on every authenticated request, covering three dimensions: request volume (this hour's count against that client's own trailing-24h baseline), geography (a country never seen before for that client, once at least one other country is already on record), and behavior shift (this hour's mix of check kinds against that client's own trailing-24h mix, measured as total variation distance). Volume is the one signal with a real, automatic enforcement action today: a genuine spike temporarily reduces that client's own rate limit for a bounded cooldown window, recorded as a `CLIENT_AUTO_THROTTLED` audit event. It self-expires and is never a permanent block. Geography and behavior shift are logged for operators only and never throttle or block a request, a deliberate choice in line with the EU AI Act's human-in-the-loop requirement, not a temporary gap. If your client has configured a source restriction (an IP allowlist and/or an allowed request domain), a request from outside it returns `403 client_access_restricted` regardless of an otherwise-valid credential — off by default; contact us to enable it.
idempotency-key (header)stringClient-supplied idempotency key. Enforced server-side for 24h: resending the exact same request with the same key returns the ORIGINAL response verbatim, without re-running the screen or re-emitting an audit_log/shadow_scores entry. Reusing the same key with a DIFFERENT request body is a 409 (`idempotency_key_conflict`) rather than silently overwriting or ignoring the mismatch, so use a new key per distinct request. Omitting the header is safe. No dedup is applied, and every request is screened independently, as before.
namestringrequireddobstringnationalitystringwalletAddressesstring[]Cryptocurrency wallet addresses to screen against sanctioned-address lists (currently OFAC SDN only), exact-match only, in any raw form (mixed-case EIP-55 checksummed hex, bech32, legacy Base58Check, and so on), normalized server-side before comparison. Independent of name, dob, and nationality: a request may supply either, both, or neither.
mode"sandbox" | "live"A name with no relation to any seeded entity
{
"name": "Zzqxw Unrelated Nobody"
}Exact name + DOB + nationality match against a sandbox entity
{
"name": "Anatoly Sandboxovich Testperson",
"dob": "1960-01-01",
"nationality": "RU"
}Close name match with a contradicting DOB (fuzzy layers surface it, human review required)
{
"name": "Anatoly Sandboxovich Testperson",
"dob": "1999-09-09"
}CLEAR: no candidates above threshold
{
"classification": "CLEAR",
"candidates": [],
"wallet": {
"classification": "CLEAR",
"matches": [],
"checkedAddresses": []
},
"meta": {
"mode": "sandbox",
"sandboxOverride": false,
"humanReviewRequired": false,
"decisionId": "41",
"engineVersion": "0.1.0-provisional",
"gatesHash": "212b018655f47f1514c4b404a02e643ef027b5039964d5c68dcdd5ec0dff8f3b",
"ensembleWeightsHash": "4a2723f74864b3371c860bbb93c3d6fbfde7dcc21e99e1242ddad3ff366cf69d",
"listSnapshotIds": []
}
}CONFIRMED_MATCH: exact-match short circuit
{
"classification": "CONFIRMED_MATCH",
"candidates": [
{
"entityId": "a33e0af1-d984-451b-b0b5-7c6c3759b977",
"source": "sandbox",
"listRef": "SANDBOX-1",
"entityType": "INDIVIDUAL",
"isPep": false,
"pepCategory": null,
"pepFunctionalCategory": null,
"pepStatus": null,
"pepJurisdiction": null,
"linkedPeps": [],
"matchedVia": [
"exact",
"fts",
"phonetic",
"trigram"
],
"classifyResult": {
"score": 100,
"classification": "CONFIRMED_MATCH",
"floored": false,
"exactMatchShortCircuit": true,
"explain": {
"levenshtein": 1,
"phonetic": 1,
"dobNat": {
"dob": 1,
"nationality": 1,
"combined": 1
},
"vector": null,
"weightSet": "launch"
},
"engineVersion": "0.1.0-provisional"
}
}
],
"wallet": {
"classification": "CLEAR",
"matches": [],
"checkedAddresses": []
},
"meta": {
"mode": "sandbox",
"sandboxOverride": false,
"humanReviewRequired": false,
"decisionId": "42",
"engineVersion": "0.1.0-provisional",
"gatesHash": "212b018655f47f1514c4b404a02e643ef027b5039964d5c68dcdd5ec0dff8f3b",
"ensembleWeightsHash": "4a2723f74864b3371c860bbb93c3d6fbfde7dcc21e99e1242ddad3ff366cf69d",
"listSnapshotIds": []
}
}POSSIBLE_MATCH: humanReviewRequired is true (EU AI Act human-in-the-loop gate)
{
"classification": "POSSIBLE_MATCH",
"candidates": [
{
"entityId": "a33e0af1-d984-451b-b0b5-7c6c3759b977",
"source": "sandbox",
"listRef": "SANDBOX-1",
"entityType": "INDIVIDUAL",
"isPep": false,
"pepCategory": null,
"pepFunctionalCategory": null,
"pepStatus": null,
"pepJurisdiction": null,
"linkedPeps": [],
"matchedVia": [
"exact",
"fts",
"phonetic",
"trigram"
],
"classifyResult": {
"score": 87,
"classification": "POSSIBLE_MATCH",
"floored": false,
"exactMatchShortCircuit": false,
"explain": {
"levenshtein": 1,
"phonetic": 1,
"dobNat": {
"dob": 0.1,
"nationality": 0.5,
"combined": 0.3
},
"vector": null,
"weightSet": "launch"
},
"engineVersion": "0.1.0-provisional"
}
}
],
"wallet": {
"classification": "CLEAR",
"matches": [],
"checkedAddresses": []
},
"meta": {
"mode": "sandbox",
"sandboxOverride": false,
"humanReviewRequired": true,
"decisionId": "43",
"engineVersion": "0.1.0-provisional",
"gatesHash": "212b018655f47f1514c4b404a02e643ef027b5039964d5c68dcdd5ec0dff8f3b",
"ensembleWeightsHash": "4a2723f74864b3371c860bbb93c3d6fbfde7dcc21e99e1242ddad3ff366cf69d",
"listSnapshotIds": []
}
}Required `name` field missing (schema validation failure)
{
"error": "bad_request",
"message": "body must have required property 'name'"
}No Authorization header sent while the service runs in production mode
{
"error": "unauthorized",
"message": "missing or malformed Authorization header (expected \"Bearer <token>\")"
}Token is expired, or its Keycloak client was revoked (introspection active=false)
{
"error": "unauthorized",
"message": "token is expired, revoked, or otherwise not active"
}The same Idempotency-Key was already used for a different request
{
"error": "idempotency_key_conflict",
"message": "Idempotency-Key was already used with a different request body/params. Use a new, unique key for a genuinely different request, or resend the exact original request to get back its cached result."
}Client's per-client rate limit (token bucket) was exhausted
{
"error": "rate_limit_exceeded",
"message": "rate limit exceeded for this client; retry after 2s. This is a per-client request-rate limit (CLAUDE.md Security Requirements), not an error in your request — resend after the given delay.",
"retryAfterSeconds": 2
}/v1/screen/{decisionId}Bearer auth (production mode)Read-only. `decisionId` is `meta.decisionId` from a prior POST /v1/screen response. Scoped strictly to the calling API key's own client_id. A decisionId that is real but belongs to a different client 404s exactly like one that does not exist at all. `meta.humanReviewRequired` reflects whether your own review is still outstanding (true only while classification is POSSIBLE_MATCH and `customerReviews` is empty), never the stale value frozen at decision time.
decisionId (path)stringrequiredaudit_log.client_seq of a SCREENING_DECISION belonging to the calling client. See meta.decisionId on POST /v1/screen.
/v1/screen/{decisionId}/reviewBearer auth (production mode)Under the EU AI Act, a POSSIBLE_MATCH result always requires human review before any action is taken on it, and is never auto-cleared. That human is you, the regulated client. Nexiel never reviews or resolves your matches on your behalf (see /legal: you retain full and final responsibility for your own compliance decisions). `decisionId` is `meta.decisionId` from a prior POST /v1/screen response. Only ever accepted for a decision that (a) belongs to the calling client (404 otherwise, identical to a decisionId that does not exist at all, never a 403 that would confirm another client's data exists) and (b) is currently classified POSSIBLE_MATCH (409 `screening_decision_not_reviewable` otherwise, since a CLEAR or CONFIRMED_MATCH decision was never awaiting review in the first place). Never mutates the original decision's `classification`, which stays exactly as originally computed, part of the frozen decision artifact. Your review is recorded as its own, separate, immutable audit event. Re-review is allowed (submitting again records a new review, nothing is overwritten). Every one of your past reviews for this decision is returned in `customerReviews`, most recent first. `Idempotency-Key` is enforced server-side exactly like POST /v1/screen's own header.
decisionId (path)stringrequiredaudit_log.client_seq of a SCREENING_DECISION belonging to the calling client. See meta.decisionId on POST /v1/screen.
idempotency-key (header)stringClient-supplied idempotency key. Enforced server-side for 24h: resending the exact same request with the same key returns the ORIGINAL response verbatim, without recording a second review event. Reusing the same key with a DIFFERENT request body/decisionId is a 409 (`idempotency_key_conflict`).
decision"confirmed_match" | "false_positive" | "escalated"requirednotesstring/v1/wallet-risk/scoreBearer auth (production mode)Preview, sandbox-only surface. Not yet a billed, generally available product, and there is no pricing tier for this route yet. Looks up the given (network, address) against the real, ingested GraphSense TagPacks corpus (live mode) or a small, clearly fake synthetic fixture set (sandbox mode, the default, see the top-level API description) and returns a 0-100 risk score plus the exact evidence tags behind it. Honest scope: this detects only an address directly present in the ingested corpus. There is no blockchain-transaction-hop exposure propagation (no transaction-graph data is ingested at all), so an address that received funds from a tagged address is invisible to this engine unless it also carries its own direct tag. `sameActorAddresses` is not exposure propagation either. It only surfaces other addresses the corpus already tags under the same declared actor. A null `score` and `classification: "UNTAGGED"` means "no evidence found in this corpus," an absence of evidence, never proof the address is safe. This is explicitly not Chainalysis, TRM, or Elliptic-equivalent coverage. `frozenDecisionArtifact` pins exactly which engine version, risk-weights config, and TagPacks ingestion snapshot produced this score. `tagpackEtlRunId` is always null in sandbox mode (synthetic data has no ETL lineage to cite). `Idempotency-Key` is enforced server-side exactly like POST /v1/screen's own header. Authenticated (production-mode) requests share that same route's per-client rate limit and anomaly tracking.
idempotency-key (header)stringClient-supplied idempotency key. Enforced server-side for 24h: resending the exact same request with the same key returns the ORIGINAL response verbatim, without re-running the score or re-emitting an audit_log entry. Reusing the same key with a DIFFERENT request body is a 409 (`idempotency_key_conflict`).
networkstringrequiredChain/network code (e.g. "BTC", "ETH"). Free text, normalized (trimmed and upper-cased) server-side before lookup.
addressstringrequiredThe wallet address to score, in any raw form. Normalized server-side in a network-aware way: case-insensitive hex networks like ETH/BSC are lowercased, and Base58Check chains are compared byte-exact and case-sensitive, since their checksum depends on case.
mode"sandbox" | "live"Sandbox synthetic LOW-risk fixture (a fake "exchange"-tagged address)
{
"network": "BTC",
"address": "1SandboxLowRiskExchangeFAKE00001"
}Sandbox synthetic HIGH-risk fixture (a fake terrorism-financing-tagged address)
{
"network": "BTC",
"address": "1SandboxHighRiskTerrorismFAKE003"
}LOW: a single, low-severity synthetic tag (sandbox mode)
{
"network": "BTC",
"address": "1SandboxLowRiskExchangeFAKE00001",
"addressLookup": "1SandboxLowRiskExchangeFAKE00001",
"score": 6,
"classification": "LOW",
"matchedTags": [
{
"network": "BTC",
"address": "1SandboxLowRiskExchangeFAKE00001",
"label": "Sandbox Synthetic Exchange (fake — for API testing only, not a real entity)",
"category": "exchange",
"abuse": null,
"concepts": [],
"actorId": null,
"confidence": "service_data",
"confidenceLevel": 50,
"categoryWeight": 12,
"contributionScore": 6,
"isSanctionsConcept": false,
"source": null,
"packFile": "sandbox/synthetic-fixtures",
"packTitle": "Nexiel Sandbox Synthetic Fixtures (fake data — never from GraphSense TagPacks)",
"lastmod": null,
"isClusterDefiner": false
}
],
"excludedTags": [],
"sameActorAddresses": [],
"frozenDecisionArtifact": {
"engineVersion": "0.1.0",
"riskWeightsHash": "be3b2339f08e725fa510d37c5fdc0b4364a1143601dcd209cf355b946146f298",
"tagpackEtlRunId": null
},
"meta": {
"mode": "sandbox",
"sandboxOverride": false
}
}HIGH: a maximum-severity synthetic tag (sandbox mode)
{
"network": "BTC",
"address": "1SandboxHighRiskTerrorismFAKE003",
"addressLookup": "1SandboxHighRiskTerrorismFAKE003",
"score": 100,
"classification": "HIGH",
"matchedTags": [
{
"network": "BTC",
"address": "1SandboxHighRiskTerrorismFAKE003",
"label": "Sandbox Synthetic Terrorism-Financing Wallet (fake — for API testing only, not a real entity)",
"category": null,
"abuse": "terrorism_financing",
"concepts": [],
"actorId": null,
"confidence": "ledger_immanent",
"confidenceLevel": 100,
"categoryWeight": 100,
"contributionScore": 100,
"isSanctionsConcept": false,
"source": null,
"packFile": "sandbox/synthetic-fixtures",
"packTitle": "Nexiel Sandbox Synthetic Fixtures (fake data — never from GraphSense TagPacks)",
"lastmod": null,
"isClusterDefiner": false
}
],
"excludedTags": [],
"sameActorAddresses": [],
"frozenDecisionArtifact": {
"engineVersion": "0.1.0",
"riskWeightsHash": "be3b2339f08e725fa510d37c5fdc0b4364a1143601dcd209cf355b946146f298",
"tagpackEtlRunId": null
},
"meta": {
"mode": "sandbox",
"sandboxOverride": false
}
}UNTAGGED: no evidence found (absence of evidence, never proof of safety)
{
"network": "BTC",
"address": "1SandboxNoDataAtAllFAKE0000000007",
"addressLookup": "1SandboxNoDataAtAllFAKE0000000007",
"score": null,
"classification": "UNTAGGED",
"matchedTags": [],
"excludedTags": [],
"sameActorAddresses": [],
"frozenDecisionArtifact": {
"engineVersion": "0.1.0",
"riskWeightsHash": "be3b2339f08e725fa510d37c5fdc0b4364a1143601dcd209cf355b946146f298",
"tagpackEtlRunId": null
},
"meta": {
"mode": "sandbox",
"sandboxOverride": false
}
}/v1/onboarding/kyb-applicationsNormalizes free-text signup input (via a pluggable InputDrafter: a real Anthropic-backed implementation in production, a deterministic rule-based test double in sandbox mode and tests), runs the same real registry verification, UBO/director plausibility check, and entity plus person sanctions/PEP screening a real KYB application would, and drafts exactly one `kyb_onboarding_drafts` row. It never creates a real client or KYB application. `recommendation` is advisory only (SUBMIT_RECOMMENDED, NEEDS_INFO_RECOMMENDED, or DO_NOT_SUBMIT_RECOMMENDED), deliberately spelled nothing like a real kyb_applications.status value. A human reviewer must explicitly act on this draft before any real KYB application exists for it, and that application always starts NEEDS_REVIEW regardless of how clean this draft looked. Only a second, independent human decision can ever approve or reject it. `advisoryFlags` are purely informational normalization notes, never a gate. `Idempotency-Key` is enforced server-side, scoped to this applicant (registryCountry and registryNumber) since no client identity exists yet at this point in the flow. This endpoint has no client identity to authenticate or rate-limit by yet, so abuse protection here is a pre-auth, source-IP-keyed token bucket with a deliberately low burst and hourly budget, rather than the per-client limiter every authenticated route in this API uses. Exceeding it returns a `429` with a `Retry-After` header, the same contract as `POST /v1/screen`'s own rate limit.
idempotency-key (header)stringClient-supplied idempotency key, scoped to this applicant (registryCountry and registryNumber). Resending the exact same submission with the same key returns the ORIGINAL result verbatim, without submitting a second KYB application. Reusing the same key with a materially different submission is a 409. Omitting the header is safe (no dedup applied).
legalNamestringrequiredregistryCountrystringrequiredregistryNumberstringrequiredpersonsobject[]requiredrolestringrequiredfullNamestringrequireddobstringnationalitystringownershipPercentagenumber | stringcontrolBasisstringcontactEmailstring/v1/kyb-applications/{applicationId}/review-draftsBearer auth (production mode)Reads the application's already-produced evidence (registry check, UBO plausibility, entity and person screening, all from the application's real workflow, never re-derived here) and persists a new draft recommendation (`APPROVE_RECOMMENDED`, `REJECT_RECOMMENDED`, or `ESCALATE_RECOMMENDED`) with a plain-English rationale. This is advisory only: it never changes the application's real review status, and the human reviewer's own decision is the only thing that can. 404 if the application does not exist. 409 if it is not currently NEEDS_REVIEW (for example, already decided).
applicationId (path)stringrequired/v1/kyb-applications/{applicationId}/review-drafts/latestBearer auth (production mode)Read-only: returns the most recently generated draft for this application without generating a new one. 404 if none has been generated yet.
applicationId (path)stringrequired/v1/screen/gdpr/exportBearer auth (production mode)Scoped strictly to the authenticated bearer token's own client_id, never another client's data. Includes this key's own audit_log entries and, if this key is linked (via client_api_keys) to a KYB/CDD record, that client's clients, kyb_applications, kyb_ubos, and kyb_checks rows in full. This is self-declared UBO/director data the client itself submitted: Article 15 access is never legally constrained, only Article 17 erasure is. `kyb.linked: false` means no such record is on file for this specific API key (for example, a key minted before this linkage existed), reported explicitly, never silently omitted.
/v1/screen/gdpr/erasure-requestsBearer auth (production mode)Deletes only idempotency_keys rows for this caller (already PII-free cached responses). Never touches kyb_ubos, kyb_applications, or kyb_checks: EU AML Directives require retaining self-declared UBO/director CDD records for the life of the business relationship plus a statutory period. Erasing them requires a documented legal determination that the period has lapsed, made by the founder or engaged counsel, never by this endpoint. Also never touches audit_log, an append-only hash chain. `requiresLegalReview` is non-null exactly when this caller has a linked KYB/CDD record, and reports counts only, never the underlying data.
/v1/screen/usageBearer auth (production mode)Scoped strictly to the authenticated bearer token's own client_id, never another client's usage. `requestVolume` comes from this service's existing per-client, per-service, hourly request-volume tracking (the same tracking anomaly detection also uses). `decisions` comes from this service's existing audit_log SCREENING_DECISION events. Defaults to a trailing 90-day window ending now when `from` and `to` are omitted. The widest single request this endpoint accepts is 366 days.
from (query)stringStart of the reporting window (inclusive), UTC calendar date. Defaults to 90 days before `to`.
to (query)stringEnd of the reporting window (exclusive), UTC calendar date. Defaults to today.
/v1/sealBearer auth (production mode)Seals a PDF document on behalf of a KYB-approved client company, using that company's own CSC (Cloud Signature Consortium) API v2.2 credential at its QTSP (Qualified Trust Service Provider), never a shared Nexiel credential. A QSeal cryptographically attributes the seal to whoever's certificate signs it, so using any credential other than the requesting client's own would misattribute the seal. Gated by, in order: real Keycloak authentication, the existing account-active check (which includes KYB-approved status), this client having a provisioned seal credential (`clients.qseal_credential_id`), and, as the QSeal-specific check, `authorizingRepresentativeId` resolving to a real declared UBO/director/senior-managing-official on file for this client's own APPROVED KYB application. Any one such declared person may authorize a seal alone (a single-signer model). `frozenDecisionArtifact` pins exactly which CSC credential, QTSP, engine version, and CSC API spec version produced this seal. Nexiel never stores the document itself, only SHA-256 hashes of the original and sealed bytes. No real QTSP account exists yet, so this route currently always returns 503 `qseal_not_configured`. This is real, tested scaffolding built against the published CSC API v2.2 specification, ready to point at a real QTSP sandbox once credentials exist. `Idempotency-Key` is enforced server-side exactly like every other mutating endpoint in this service.
idempotency-key (header)stringClient-supplied idempotency key. Enforced server-side for 24h: resending the exact same request with the same key returns the ORIGINAL response verbatim, without re-sealing the document or re-emitting a qseal_operations/audit_log entry. Reusing the same key with a DIFFERENT request body is a 409 (`idempotency_key_conflict`).
documentstringrequiredBase64-encoded PDF document to seal.
authorizingRepresentativeIdstringrequiredThe kyb_ubos.id of the declared UBO/director/senior-managing-official (on file for this client's own APPROVED KYB application) authorizing this seal. Must be a real row already on file. This endpoint never accepts a free-text name or other caller-asserted identity.
/v1/signBearer auth (production mode)Signs a PDF document on behalf of a declared representative of a KYB-approved client company, using that representative's own, individually-provisioned CSC (Cloud Signature Consortium) API v2.2 credential at its QTSP (Qualified Trust Service Provider), never a shared Nexiel credential. Contrast POST /v1/seal, which attributes a document to the LEGAL PERSON (the company) via one shared credential -- a QES attributes it to the NATURAL PERSON signing, via that person's own credential, per eIDAS Art. 3(12). Gated by, in order: real Keycloak authentication, the existing account-active check (which includes KYB-approved status), `signerId` resolving to a real declared UBO/director/senior-managing-official on file for this client's own APPROVED KYB application, and that signer having their own individually-provisioned QES credential (`kyb_ubos.qes_credential_id`). An optional `pin` / `pinObjectId` pair is forwarded to the QTSP as the CSC API `authData` object to authorize this specific signature (eIDAS Art. 26 "sole control") and is never logged or persisted anywhere in this codebase. `frozenDecisionArtifact` pins exactly which CSC credential, QTSP, engine version, and CSC API spec version produced this signature. Nexiel never stores the document itself, only SHA-256 hashes of the original and signed bytes. No real QTSP account exists yet, so this route currently always returns 503 `qes_not_configured`. This is real, tested scaffolding built against the published CSC API v2.2 specification, ready to point at a real QTSP sandbox once credentials exist. `Idempotency-Key` is enforced server-side exactly like every other mutating endpoint in this service.
idempotency-key (header)stringClient-supplied idempotency key. Enforced server-side for 24h: resending the exact same request with the same key returns the ORIGINAL response verbatim, without re-signing the document or re-emitting a qes_operations/audit_log entry. Reusing the same key with a DIFFERENT request body is a 409 (`idempotency_key_conflict`).
documentstringrequiredBase64-encoded PDF document to sign.
signerIdstringrequiredThe kyb_ubos.id of the declared UBO/director/senior-managing-official (on file for this client's own APPROVED KYB application, with their own provisioned QES credential) signing this document AS THEMSELVES. Must be a real row already on file. This endpoint never accepts a free-text name.
pinstringThe signer's own PIN (or other CSC "explicit" auth-mode value), forwarded to the QTSP to authorize this specific signature and never logged or persisted by Nexiel. Omit for a non-interactive-mode credential.
pinObjectIdstringThe CSC authentication-object id `pin` answers (e.g. "PIN"), per the credential's own credentials/info authInfo.objects[].id. Required together with `pin`.