@sekyro/node 0.1.0-rc.6 → 0.1.0-rc.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/README.md +132 -5
- package/dist/chunk-O5GJ3YJV.js +1 -0
- package/dist/chunk-TAPXGI3Q.js +1 -0
- package/dist/client-DUMp_I-1.d.cts +1485 -0
- package/dist/client-DUMp_I-1.d.ts +1485 -0
- package/dist/connect/express/index.cjs +1 -0
- package/dist/connect/express/index.d.cts +35 -0
- package/dist/connect/express/index.d.ts +35 -0
- package/dist/connect/express/index.js +1 -0
- package/dist/connect/index.cjs +1 -0
- package/dist/connect/index.d.cts +29 -0
- package/dist/connect/index.d.ts +29 -0
- package/dist/connect/index.js +1 -0
- package/dist/connect/next/index.cjs +1 -0
- package/dist/connect/next/index.d.cts +43 -0
- package/dist/connect/next/index.d.ts +43 -0
- package/dist/connect/next/index.js +1 -0
- package/dist/connector-CMHuC-CU.d.ts +384 -0
- package/dist/connector-D1bhSLBl.d.cts +384 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +107 -1242
- package/dist/index.d.ts +107 -1242
- package/dist/index.js +1 -1
- package/package.json +37 -4
- package/sbom.cdx.json +47 -6
|
@@ -0,0 +1,1485 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire-level enums and shapes of the Sekyro AI partner API (`/api/v2`). These
|
|
3
|
+
* mirror the backend's frozen partner contract; they are plain string unions so
|
|
4
|
+
* a newer API value never throws at runtime — it simply widens the type in the
|
|
5
|
+
* next SDK release.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
/** Session lifecycle status. @public */
|
|
10
|
+
type SessionStatus = "created" | "in_progress" | "review_pending" | "completed" | "expired" | "failed";
|
|
11
|
+
/**
|
|
12
|
+
* Terminal verdict, orthogonal to {@link SessionStatus}. `null` until the session
|
|
13
|
+
* reaches a terminal status; `review` when a human reviewer must adjudicate.
|
|
14
|
+
* @public
|
|
15
|
+
*/
|
|
16
|
+
type SessionOutcome = "approved" | "review" | "rejected";
|
|
17
|
+
/**
|
|
18
|
+
* What a finished session proved: `1` a live, real person (human), `2` that
|
|
19
|
+
* person's identity (document, chip, registry or supplied data bound to the
|
|
20
|
+
* face), `3` an identity corroborated by an independent source. `0` on a
|
|
21
|
+
* rejected session.
|
|
22
|
+
* @public
|
|
23
|
+
*/
|
|
24
|
+
type VerificationLevel = 0 | 1 | 2 | 3;
|
|
25
|
+
/**
|
|
26
|
+
* How a session's {@link VerificationLevel} was proved: `live_only` (liveness
|
|
27
|
+
* only), `live_unique` (liveness plus a duplicate search), and the
|
|
28
|
+
* `*_biometric` values, where a face match bound the person to a document,
|
|
29
|
+
* its chip, the registry record or partner-supplied identity data, and
|
|
30
|
+
* `eid_authenticated`, where the person signed in with a national digital
|
|
31
|
+
* identity (level 3 without a Sekyro selfie).
|
|
32
|
+
* @public
|
|
33
|
+
*/
|
|
34
|
+
type VerificationAssurance = "live_only" | "live_unique" | "document_biometric" | "chip_biometric" | "registry_biometric" | "supplied_biometric" | "eid_authenticated";
|
|
35
|
+
/** The one billing unit a finished session consumed. @public */
|
|
36
|
+
type VerificationUnit = "human_verification" | "identity_verification";
|
|
37
|
+
/** The lowest and highest {@link VerificationLevel} the session's flow can reach. @public */
|
|
38
|
+
interface LevelTarget {
|
|
39
|
+
min: VerificationLevel;
|
|
40
|
+
max: VerificationLevel;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Device and network risk facts of a finished session (booleans and a level
|
|
44
|
+
* word, never scores).
|
|
45
|
+
* @public
|
|
46
|
+
*/
|
|
47
|
+
interface ResultRisk {
|
|
48
|
+
level: "low" | "medium" | "high";
|
|
49
|
+
vpn: boolean;
|
|
50
|
+
ipDocumentMismatch: boolean;
|
|
51
|
+
deviceTampered: boolean;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* What the liveness step verified about the capture itself: the device
|
|
55
|
+
* attestation, the capture proof and the injection signals.
|
|
56
|
+
* @public
|
|
57
|
+
*/
|
|
58
|
+
interface ResultCheckProofs {
|
|
59
|
+
attestation: "verified" | "missing" | "failed";
|
|
60
|
+
captureProof: "verified" | "missing";
|
|
61
|
+
injectionSignals: "clear" | "flagged";
|
|
62
|
+
}
|
|
63
|
+
/** Another subject the person's face already matched (duplicate search). @public */
|
|
64
|
+
interface ResultDuplicate {
|
|
65
|
+
subjectId: string;
|
|
66
|
+
externalRef?: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* How a `subject.reuse` session runs: `recheck` verifies the same person
|
|
70
|
+
* again (liveness and face match against the stored photo), `step_up` raises
|
|
71
|
+
* the subject to identity level with a flow that proves level 2 on every path.
|
|
72
|
+
* @public
|
|
73
|
+
*/
|
|
74
|
+
type SubjectReuseMode = "recheck" | "step_up";
|
|
75
|
+
/**
|
|
76
|
+
* Where the hosted flow sends the person when the session ends: an `https`
|
|
77
|
+
* URL on one of the app's web origins, or the app's `sekyro-<slug>://` scheme.
|
|
78
|
+
* `state` (up to 256 characters) is echoed back on the redirect.
|
|
79
|
+
* @public
|
|
80
|
+
*/
|
|
81
|
+
interface SessionLinkInput {
|
|
82
|
+
returnUrl?: string;
|
|
83
|
+
state?: string;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* How the person proves their identity on an optional-document app: type the
|
|
87
|
+
* national number, or photograph the document (`document_chip`: native NFC clients only).
|
|
88
|
+
* `national_eid`: the country's national eID (e.g. Houwiyeti for Mauritania),
|
|
89
|
+
* offered when the app's profile turns the national eID on.
|
|
90
|
+
* @public
|
|
91
|
+
*/
|
|
92
|
+
type IdentityMethod = "national_number" | "document_photo" | "document_chip" | "national_eid";
|
|
93
|
+
/** The verification checks a flow may contain. @public */
|
|
94
|
+
type CheckType = "liveness" | "face_match" | "doc_ocr" | "population_registry" | "phone_otp" | "nfc_chip" | "email_otp" | "portrait_icao" | "eid_auth";
|
|
95
|
+
/** Per-check execution state within a session. @public */
|
|
96
|
+
type CheckState = "pending" | "input_required" | "processing" | "passed" | "failed" | "review" | "skipped";
|
|
97
|
+
/**
|
|
98
|
+
* Why a session was stopped by a profile-v2 policy gate rather than by a
|
|
99
|
+
* failed check:
|
|
100
|
+
* - `location_not_allowed` — the end user's IP location is not allowed for the app;
|
|
101
|
+
* - `anonymizer_blocked` — an anonymizer (VPN / proxy / Tor) was detected while the app blocks them;
|
|
102
|
+
* - `capture_tampered` — the device reported a tampered capture (virtual
|
|
103
|
+
* camera, hooking, emulator…) while the app's `device.tamper` is `block`;
|
|
104
|
+
* - `device_velocity_exceeded` — the device already verified more different
|
|
105
|
+
* people than `device.velocity` allows, with `action: 'block'`;
|
|
106
|
+
* - `device_cooldown` — the device had too many rejected sessions
|
|
107
|
+
* (`cooldown` tiers); {@link Session.retryAfter} says when it may try again.
|
|
108
|
+
* Not billed.
|
|
109
|
+
* @public
|
|
110
|
+
*/
|
|
111
|
+
type SessionFailureReason = "location_not_allowed" | "anonymizer_blocked" | "capture_tampered" | "device_velocity_exceeded" | "device_cooldown";
|
|
112
|
+
/**
|
|
113
|
+
* Profile-v2 decision-mode reasons a check's {@link SessionStep.reason} may
|
|
114
|
+
* carry when the app decides automatically (`decisions.mode: 'automatic'`)
|
|
115
|
+
* instead of routing to human review. All are retryable within the step's
|
|
116
|
+
* attempts: `liveness_inconclusive` (liveness middle band),
|
|
117
|
+
* `match_inconclusive` (face match middle band on every reference),
|
|
118
|
+
* `document_authenticity` (doc_ocr authenticity warning — retake the original)
|
|
119
|
+
* and `mobile_required` (liveness captured on a desktop — continue on a phone;
|
|
120
|
+
* not billed). Every inconclusive attempt is billed.
|
|
121
|
+
* @public
|
|
122
|
+
*/
|
|
123
|
+
type DecisionReason = "liveness_inconclusive" | "match_inconclusive" | "document_authenticity" | "mobile_required";
|
|
124
|
+
/**
|
|
125
|
+
* Profile-v2 eligibility reasons a check's {@link SessionStep.reason} may carry:
|
|
126
|
+
* `document_type_not_accepted` (doc_ocr; the person may pick another
|
|
127
|
+
* document), `nationality_not_allowed` and `underage` (doc_ocr or
|
|
128
|
+
* population_registry; terminal), and `age_unverifiable` (the app sets a
|
|
129
|
+
* minimum age but the birth date could not be read — doc_ocr: retryable with
|
|
130
|
+
* a clearer photo; population_registry: terminal).
|
|
131
|
+
* @public
|
|
132
|
+
*/
|
|
133
|
+
type EligibilityReason = "document_type_not_accepted" | "nationality_not_allowed" | "underage" | "age_unverifiable";
|
|
134
|
+
/**
|
|
135
|
+
* Why a profile-v2 policy ended a session: a session-level
|
|
136
|
+
* {@link SessionFailureReason} (location / anonymizer gate), or the failed
|
|
137
|
+
* check's policy reason — an {@link EligibilityReason} or
|
|
138
|
+
* `document_nni_mismatch` (the document belongs to someone other than the
|
|
139
|
+
* NNI the session was created for), or `camera_unavailable` (spec 2026-10-29 §3.4: the person had no usable camera,
|
|
140
|
+
* so the live step ended without a capture; the session is rejected at level 0 unless your flow has a fallback).
|
|
141
|
+
* @public
|
|
142
|
+
*/
|
|
143
|
+
type PolicyFailureReason = SessionFailureReason | EligibilityReason | "document_nni_mismatch" | "camera_unavailable";
|
|
144
|
+
/**
|
|
145
|
+
* Why the person had no camera (spec 2026-10-29 §3.4, 2026-10-30), when the SDK said: `denied` (the
|
|
146
|
+
* person refused camera access) or `no_camera` (no usable camera: none found, an insecure page or a
|
|
147
|
+
* browser that cannot capture). A detail under `failureReason: "camera_unavailable"`, never a reason of its own.
|
|
148
|
+
* @public
|
|
149
|
+
*/
|
|
150
|
+
type CameraUnavailableCause = "denied" | "no_camera";
|
|
151
|
+
/**
|
|
152
|
+
* Profile-v2 matching reasons a check's {@link SessionStep.reason} may carry
|
|
153
|
+
* when the data you sent in {@link CreateSessionInput.subject} differs from the
|
|
154
|
+
* reference identity: `name_mismatch`, `birth_date_mismatch`,
|
|
155
|
+
* `nationality_mismatch` (doc_ocr or population_registry) and
|
|
156
|
+
* `document_number_mismatch` (doc_ocr). All are final.
|
|
157
|
+
* @public
|
|
158
|
+
*/
|
|
159
|
+
type MatchReason = "name_mismatch" | "birth_date_mismatch" | "nationality_mismatch" | "document_number_mismatch";
|
|
160
|
+
/**
|
|
161
|
+
* Face-match probe-binding reason a `face_match` {@link SessionStep.reason} may
|
|
162
|
+
* carry (SDK spec §4.10): `probe_not_from_liveness` — the face image isn't the
|
|
163
|
+
* person in the liveness clip. Retryable within the step's attempts (the
|
|
164
|
+
* person re-takes the liveness capture); billed.
|
|
165
|
+
* @public
|
|
166
|
+
*/
|
|
167
|
+
type ProbeBindingReason = "probe_not_from_liveness";
|
|
168
|
+
/**
|
|
169
|
+
* The languages the person being verified sees (hosted flow and SDK screens; spec 2026-10-29 §9). `ar`, `fr` and `en`
|
|
170
|
+
* carry every screen; `es`, `pt` and `de` carry the Human verification screens and show English elsewhere. SMS and
|
|
171
|
+
* email messages stay in `ar`, `fr` or `en` (English for the three others).
|
|
172
|
+
* @public
|
|
173
|
+
*/
|
|
174
|
+
type Locale = "ar" | "fr" | "en" | "es" | "pt" | "de";
|
|
175
|
+
/** The environment a webhook was emitted from. @public */
|
|
176
|
+
type SekyroEnvironment = "sandbox" | "live";
|
|
177
|
+
/**
|
|
178
|
+
* One check of a session, as the partner API projects it: enum/id fields only,
|
|
179
|
+
* never civil data.
|
|
180
|
+
* @public
|
|
181
|
+
*/
|
|
182
|
+
interface SessionStep {
|
|
183
|
+
checkType: CheckType;
|
|
184
|
+
state: CheckState;
|
|
185
|
+
/** Sekyro flows: the flow node this check belongs to (e.g. `n_live`). */
|
|
186
|
+
nodeId?: string;
|
|
187
|
+
/** Sekyro flows: the service of that node. */
|
|
188
|
+
service?: ServiceId;
|
|
189
|
+
/** Sekyro flows: the check failed and the flow's fallback took over. */
|
|
190
|
+
handled?: true;
|
|
191
|
+
/** Machine-readable failure/review reason, when the check has one. */
|
|
192
|
+
reason?: string;
|
|
193
|
+
/** With reason `camera_unavailable`: why, when the SDK said (`denied` or `no_camera`). */
|
|
194
|
+
reasonDetail?: CameraUnavailableCause;
|
|
195
|
+
/** Calibrated model score in [0, 1] for scored checks (liveness, face match). */
|
|
196
|
+
calibratedScore?: number;
|
|
197
|
+
/** The check failed after using all of its attempts. */
|
|
198
|
+
attemptsExhausted?: boolean;
|
|
199
|
+
/**
|
|
200
|
+
* `portrait_icao` only (ID mode): the per-criterion ICAO report of the last
|
|
201
|
+
* attempt — numbers and enums only, never the image.
|
|
202
|
+
*/
|
|
203
|
+
report?: PortraitReportEntry[];
|
|
204
|
+
/**
|
|
205
|
+
* `face_match` only: the probe-quality measurement of the selfie that was
|
|
206
|
+
* matched (occlusion, head pose, eye openness, sharpness). Recorded for
|
|
207
|
+
* information only: it never changes the step's state or reason.
|
|
208
|
+
*/
|
|
209
|
+
probeQuality?: ProbeQuality;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* The probe-quality measurement on a `face_match` step. Numbers only; `null`
|
|
213
|
+
* means the value could not be measured. Informational: no threshold applies.
|
|
214
|
+
* @public
|
|
215
|
+
*/
|
|
216
|
+
interface ProbeQuality {
|
|
217
|
+
/** Share of the inner face that is covered (a hand, a mask, a phone), in [0, 1]. */
|
|
218
|
+
occlusion: number | null;
|
|
219
|
+
/** Head pose in degrees. */
|
|
220
|
+
pose: {
|
|
221
|
+
yaw: number | null;
|
|
222
|
+
pitch: number | null;
|
|
223
|
+
roll: number | null;
|
|
224
|
+
};
|
|
225
|
+
/** Openness of the less-open eye, in [0, 1]. */
|
|
226
|
+
eyesOpen: number | null;
|
|
227
|
+
/** Sharpness of the face region (higher is sharper; no fixed scale). */
|
|
228
|
+
sharpness: number | null;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* One row of the `portrait_icao` report (ID mode): the server's measurement of
|
|
232
|
+
* one ICAO criterion and the threshold that applied.
|
|
233
|
+
* @public
|
|
234
|
+
*/
|
|
235
|
+
interface PortraitReportEntry {
|
|
236
|
+
criterion: "pose" | "eyes" | "mouth" | "occlusion" | "glare" | "lighting" | "background" | "resolution";
|
|
237
|
+
value: number | null;
|
|
238
|
+
threshold: number | string | null;
|
|
239
|
+
pass: boolean;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* A short-lived link to a session's ICAO portrait (480×640 JPEG), from
|
|
243
|
+
* {@link SessionsApi.portrait}. Download it before `expiresAt`; never store the URL.
|
|
244
|
+
* @public
|
|
245
|
+
*/
|
|
246
|
+
interface SessionPortraitLink {
|
|
247
|
+
url: string;
|
|
248
|
+
/** ISO 8601 (about 5 minutes after the call). */
|
|
249
|
+
expiresAt: string;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Out-of-band delivery of the session's hosted link, sent by Sekyro AI after the
|
|
253
|
+
* session is created. Best effort: a failed send never fails the create.
|
|
254
|
+
* @public
|
|
255
|
+
*/
|
|
256
|
+
interface DeliverOptions {
|
|
257
|
+
/** Delivery channel. */
|
|
258
|
+
channel: "sms" | "whatsapp";
|
|
259
|
+
/** E.164 phone number of the recipient, e.g. `+22236123456`. */
|
|
260
|
+
to: string;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* What you already know about the person (`subject` at session create). A
|
|
264
|
+
* closed object: unknown keys are refused (`400`). Every field is optional;
|
|
265
|
+
* `null` or blank counts as absent. Identity fields are compared with the
|
|
266
|
+
* person's document or registry record when the app's profile turns name
|
|
267
|
+
* matching on; `nni` binds the session to that identity.
|
|
268
|
+
* @public
|
|
269
|
+
*/
|
|
270
|
+
interface SessionSubjectInput {
|
|
271
|
+
/** 10-digit Mauritanian NNI, as a string. */
|
|
272
|
+
nni?: string;
|
|
273
|
+
/** E.164 phone number, e.g. `+22236123456`. */
|
|
274
|
+
phone?: string;
|
|
275
|
+
fullName?: string;
|
|
276
|
+
/** ISO 8601 date (`YYYY-MM-DD`). */
|
|
277
|
+
birthDate?: string;
|
|
278
|
+
/** ISO 3166-1 alpha-2, e.g. `MR`. */
|
|
279
|
+
nationality?: string;
|
|
280
|
+
/** Identity-document number (1–40 characters). */
|
|
281
|
+
documentNumber?: string;
|
|
282
|
+
/**
|
|
283
|
+
* Your own id for this person (1–128 characters). Echoed on the session and
|
|
284
|
+
* its webhooks, and searchable on the subjects API.
|
|
285
|
+
*/
|
|
286
|
+
externalRef?: string;
|
|
287
|
+
/**
|
|
288
|
+
* Returning user (profile v2 step 5): verify this already-verified subject
|
|
289
|
+
* again with liveness + face match only, against the reference photo stored
|
|
290
|
+
* on the subject. Name exactly one target. Errors at create:
|
|
291
|
+
* `404 subject_not_found`, `409 subject_revoked`, `409 subject_no_reference`,
|
|
292
|
+
* `409 subject_stale` (older than the flow's `returning.maxAgeMonths`),
|
|
293
|
+
* `409 reuse_disabled` (the flow turns returning-user sessions off) and
|
|
294
|
+
* `400` / `409 reuse_target_ambiguous`.
|
|
295
|
+
*/
|
|
296
|
+
reuse?: SubjectReuseTarget;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* An identity document for {@link SubjectReuseTarget}: the document type, the
|
|
300
|
+
* issuing country (ISO 3166-1 alpha-2 or alpha-3) and its number.
|
|
301
|
+
* @public
|
|
302
|
+
*/
|
|
303
|
+
interface SubjectReuseDocument {
|
|
304
|
+
type: "national_id" | "passport" | "residence_permit";
|
|
305
|
+
issuingCountry: string;
|
|
306
|
+
number: string;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Which subject a returning-user session re-verifies — exactly ONE of the
|
|
310
|
+
* subject id, your own `externalRef` (must match a single subject), the NNI
|
|
311
|
+
* or an identity document the person verified with.
|
|
312
|
+
* @public
|
|
313
|
+
*/
|
|
314
|
+
type SubjectReuseTarget = ({
|
|
315
|
+
subjectId: string;
|
|
316
|
+
externalRef?: never;
|
|
317
|
+
nni?: never;
|
|
318
|
+
document?: never;
|
|
319
|
+
} | {
|
|
320
|
+
externalRef: string;
|
|
321
|
+
subjectId?: never;
|
|
322
|
+
nni?: never;
|
|
323
|
+
document?: never;
|
|
324
|
+
} | {
|
|
325
|
+
nni: string;
|
|
326
|
+
subjectId?: never;
|
|
327
|
+
externalRef?: never;
|
|
328
|
+
document?: never;
|
|
329
|
+
} | {
|
|
330
|
+
document: SubjectReuseDocument;
|
|
331
|
+
subjectId?: never;
|
|
332
|
+
externalRef?: never;
|
|
333
|
+
nni?: never;
|
|
334
|
+
}) & {
|
|
335
|
+
/**
|
|
336
|
+
* `recheck` (default) or `step_up` ({@link SubjectReuseMode}). `step_up` on
|
|
337
|
+
* a flow that does not prove level 2 on every path answers
|
|
338
|
+
* `400 step_up_flow_too_weak`.
|
|
339
|
+
*/
|
|
340
|
+
mode?: SubjectReuseMode;
|
|
341
|
+
};
|
|
342
|
+
/** A document type the backend reads (kyc-docs-v2 vocabulary; `carte_identite` = identity card of any issuer). @public */
|
|
343
|
+
type ProfileDocumentType = "carte_identite" | "passport" | "residence_permit";
|
|
344
|
+
/**
|
|
345
|
+
* The services a Sekyro flow is built from. A session's steps
|
|
346
|
+
* ({@link SessionStep.service}) and {@link FlowOverrides.services} use these
|
|
347
|
+
* ids; one service may run several checks (e.g. `liveness` with an ICAO
|
|
348
|
+
* portrait).
|
|
349
|
+
* @public
|
|
350
|
+
*/
|
|
351
|
+
type ServiceId = "device_network" | "phone_otp" | "email_otp" | "national_eid" | "document" | "nfc" | "population_registry" | "supplied_identity" | "summary_confirm" | "liveness" | "face_match" | "aml_screening" | "face_dedup";
|
|
352
|
+
/**
|
|
353
|
+
* The general settings of a flow that a session may override (the flow's
|
|
354
|
+
* `link`, `language` and override policy are not overridable). Country codes
|
|
355
|
+
* are ISO 3166-1 alpha-2 (`MR`). Used through {@link FlowOverrides.settings}.
|
|
356
|
+
* @public
|
|
357
|
+
*/
|
|
358
|
+
interface FlowOverridableSettings {
|
|
359
|
+
/** Who may be verified. */
|
|
360
|
+
eligibility: {
|
|
361
|
+
/** Accepted nationalities: `'*'` or a list, optionally per IP location. */
|
|
362
|
+
nationalities: {
|
|
363
|
+
default: "*" | string[];
|
|
364
|
+
byLocation?: Record<string, "*" | string[]>;
|
|
365
|
+
};
|
|
366
|
+
/** Minimum age in years (1–120), or `null` for none. */
|
|
367
|
+
minAge: number | null;
|
|
368
|
+
};
|
|
369
|
+
/** Automatic decisions instead of human review (`retryConfidentRejects` lets confident rejects retry). */
|
|
370
|
+
decisions?: {
|
|
371
|
+
mode: "automatic" | "review";
|
|
372
|
+
retryConfidentRejects: boolean;
|
|
373
|
+
};
|
|
374
|
+
/** Data consistency across sources. */
|
|
375
|
+
fraud: {
|
|
376
|
+
/** Comparison of your `subject` data with the reference identity. */
|
|
377
|
+
nameMatch?: {
|
|
378
|
+
level: "strict" | "standard" | "lenient";
|
|
379
|
+
onMismatch: "fail" | "signal";
|
|
380
|
+
};
|
|
381
|
+
};
|
|
382
|
+
/** Returning-user sessions (`subject.reuse`). */
|
|
383
|
+
returning: {
|
|
384
|
+
/** `false`: returning-user sessions are refused (`409 reuse_disabled`). */
|
|
385
|
+
enabled: boolean;
|
|
386
|
+
/** Maximum age in months (1–120) of the subject's last verification; `null` = no limit. */
|
|
387
|
+
maxAgeMonths: number | null;
|
|
388
|
+
};
|
|
389
|
+
/** Identity-document rules. */
|
|
390
|
+
documents: {
|
|
391
|
+
/** Accepted document types: `'*'` (all) or a list, optionally per issuing country. */
|
|
392
|
+
accepted: {
|
|
393
|
+
default: "*" | ProfileDocumentType[];
|
|
394
|
+
byIssuer?: Record<string, ProfileDocumentType[]>;
|
|
395
|
+
};
|
|
396
|
+
/** Expired documents: refused, allowed, or allowed for `graceDays` (1–365) after expiry. */
|
|
397
|
+
expired: "reject" | "allow" | {
|
|
398
|
+
graceDays: number;
|
|
399
|
+
};
|
|
400
|
+
authenticity: "standard" | "off";
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Document substitution: the portrait a `document` or `nfc` step produces is
|
|
405
|
+
* compared with the registry portrait (or the chip with the printed photo).
|
|
406
|
+
* `signal` records a risk signal on a clear mismatch, `review` also sends the
|
|
407
|
+
* session to review, `off` compares nothing. `failBelow` is the mismatch bound
|
|
408
|
+
* in (0, 1), absent = the platform bound.
|
|
409
|
+
* @public
|
|
410
|
+
*/
|
|
411
|
+
interface DocumentSubstitutionSettings {
|
|
412
|
+
mode: "off" | "signal" | "review";
|
|
413
|
+
failBelow?: number;
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* The per-service settings a session may override, by {@link ServiceId}.
|
|
417
|
+
* `attempts` limits are per step (absent = the platform default).
|
|
418
|
+
* @public
|
|
419
|
+
*/
|
|
420
|
+
interface FlowServiceSettings {
|
|
421
|
+
/** Device & Network Intelligence: IP location, anonymizers, cooldown, device and capture postures. */
|
|
422
|
+
device_network: {
|
|
423
|
+
/** Where the end user may be (IP location). */
|
|
424
|
+
locations: {
|
|
425
|
+
mode: "all";
|
|
426
|
+
} | {
|
|
427
|
+
mode: "only" | "all_except";
|
|
428
|
+
countries: string[];
|
|
429
|
+
};
|
|
430
|
+
/** VPN / proxy / Tor. */
|
|
431
|
+
anonymizers: "allow" | "block";
|
|
432
|
+
/** Device cooldown after repeated rejections (at most 5 tiers; `[]` = off). */
|
|
433
|
+
cooldown?: {
|
|
434
|
+
tiers: Array<{
|
|
435
|
+
rejectedSessions: number;
|
|
436
|
+
windowHours: number;
|
|
437
|
+
waitMinutes: number;
|
|
438
|
+
}>;
|
|
439
|
+
};
|
|
440
|
+
/** Device tamper and velocity actions. */
|
|
441
|
+
device?: {
|
|
442
|
+
tamper: "block" | "signal";
|
|
443
|
+
velocity: {
|
|
444
|
+
maxIdentitiesPerDevice: number;
|
|
445
|
+
windowDays: number;
|
|
446
|
+
action: "signal" | "block";
|
|
447
|
+
};
|
|
448
|
+
};
|
|
449
|
+
attestation?: "off" | "signal" | "enforce";
|
|
450
|
+
captureIntegrity?: "off" | "signal" | "enforce";
|
|
451
|
+
};
|
|
452
|
+
phone_otp: {
|
|
453
|
+
/** Where the number comes from: your `subject.phone` / `input.phone`, the person, or either. */
|
|
454
|
+
numberSource: "prefilled" | "user_entered" | "prefilled_or_entered";
|
|
455
|
+
/** Narrow the channels the person may choose from (absent = every channel the org has on). */
|
|
456
|
+
channels?: Array<"whatsapp" | "sms">;
|
|
457
|
+
/** Which countries codes may be sent to (absent = the flow's allowed `locations`). */
|
|
458
|
+
destinations?: "locations" | "any" | {
|
|
459
|
+
countries: string[];
|
|
460
|
+
};
|
|
461
|
+
attempts?: number;
|
|
462
|
+
};
|
|
463
|
+
email_otp: {
|
|
464
|
+
/** Where the address comes from: your `input.email`, the person, or either. */
|
|
465
|
+
emailSource: "prefilled" | "user_entered" | "prefilled_or_entered";
|
|
466
|
+
/** Disposable (temporary) addresses: allowed, flagged as a risk signal (default), or refused. */
|
|
467
|
+
disposable?: "allow" | "signal" | "block";
|
|
468
|
+
attempts?: number;
|
|
469
|
+
};
|
|
470
|
+
national_eid: {
|
|
471
|
+
/**
|
|
472
|
+
* `'org'` (every national eID the org can use, resolved at session create)
|
|
473
|
+
* or provider ids (`{country}.{provider}`, e.g. `MR.houwiyeti`).
|
|
474
|
+
*/
|
|
475
|
+
providers: "org" | string[];
|
|
476
|
+
/** The eID portrait is the face-match reference. */
|
|
477
|
+
portraitReference: boolean;
|
|
478
|
+
};
|
|
479
|
+
document: {
|
|
480
|
+
attempts?: number;
|
|
481
|
+
/** Compare the document photo with the registry photo (absent = the platform default). */
|
|
482
|
+
documentSubstitution?: DocumentSubstitutionSettings;
|
|
483
|
+
};
|
|
484
|
+
/** The chip read (its MRZ source is derived from the flow and is not overridable). */
|
|
485
|
+
nfc: {
|
|
486
|
+
maxAttempts?: number;
|
|
487
|
+
/** Compare the chip photo with the registry photo (absent = the platform default). */
|
|
488
|
+
documentSubstitution?: DocumentSubstitutionSettings;
|
|
489
|
+
};
|
|
490
|
+
population_registry: {
|
|
491
|
+
/** `'org'` (every registry the org can use, resolved at session create) or registry ids. */
|
|
492
|
+
sources: "org" | Array<"MR.anrpts">;
|
|
493
|
+
nniSource: "auto" | "typed" | "bound_only";
|
|
494
|
+
onUncovered: "skip";
|
|
495
|
+
attempts?: number;
|
|
496
|
+
};
|
|
497
|
+
supplied_identity: Record<string, never>;
|
|
498
|
+
summary_confirm: {
|
|
499
|
+
/** Offer « Reprendre » (re-open the identity source). */
|
|
500
|
+
retake: boolean;
|
|
501
|
+
};
|
|
502
|
+
liveness: {
|
|
503
|
+
/** `off`, selfie ICAO `alert` / `reject`, or `id_document` (ID-photo portrait, always rejects). */
|
|
504
|
+
icao: "off" | "alert" | "reject" | "id_document";
|
|
505
|
+
attempts?: number;
|
|
506
|
+
};
|
|
507
|
+
face_match: {
|
|
508
|
+
reference: "auto" | "document" | "registry";
|
|
509
|
+
attempts?: number;
|
|
510
|
+
};
|
|
511
|
+
aml_screening: {
|
|
512
|
+
lists: Array<"sanctions" | "pep" | "adverse_media">;
|
|
513
|
+
onHit: "review" | "fail";
|
|
514
|
+
};
|
|
515
|
+
face_dedup: {
|
|
516
|
+
scope: "app" | "org";
|
|
517
|
+
onDuplicate: "review" | "fail";
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* `T` with every property optional, recursively. Arrays are replaced as a
|
|
522
|
+
* whole, never merged element by element.
|
|
523
|
+
* @public
|
|
524
|
+
*/
|
|
525
|
+
type DeepPartial<T> = T extends readonly unknown[] ? T : T extends object ? {
|
|
526
|
+
[K in keyof T]?: DeepPartial<T[K]>;
|
|
527
|
+
} : T;
|
|
528
|
+
/**
|
|
529
|
+
* A per-session override of the flow ({@link CreateSessionInput.overrides}).
|
|
530
|
+
*
|
|
531
|
+
* - `settings`: any subset of {@link FlowOverridableSettings}, at any depth.
|
|
532
|
+
* - `services`: keyed by service (applied to every node of that service): any
|
|
533
|
+
* subset of its {@link FlowServiceSettings}, or `'off'` to remove it from
|
|
534
|
+
* the flow. A service the flow does not use is ignored.
|
|
535
|
+
*
|
|
536
|
+
* Objects merge into the flow; arrays and scalar values replace. Unknown keys
|
|
537
|
+
* and invalid results answer `400 override_invalid`. An override may only
|
|
538
|
+
* make the flow stricter unless the flow allows widening; turning a service
|
|
539
|
+
* `'off'` always widens. A widening change answers `403 override_widens_flow`.
|
|
540
|
+
* The changed paths are reported on {@link Session.overriddenFields}.
|
|
541
|
+
*
|
|
542
|
+
* @example
|
|
543
|
+
* ```ts
|
|
544
|
+
* await sekyro.sessions.create({
|
|
545
|
+
* flow: "foreigners",
|
|
546
|
+
* overrides: {
|
|
547
|
+
* settings: { eligibility: { minAge: 21 } },
|
|
548
|
+
* services: { liveness: { attempts: 2 } },
|
|
549
|
+
* },
|
|
550
|
+
* });
|
|
551
|
+
* ```
|
|
552
|
+
* @public
|
|
553
|
+
*/
|
|
554
|
+
interface FlowOverrides {
|
|
555
|
+
settings?: DeepPartial<FlowOverridableSettings>;
|
|
556
|
+
services?: {
|
|
557
|
+
[S in ServiceId]?: DeepPartial<FlowServiceSettings[S]> | "off";
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* The flow version a session runs: its `flw_` id, its slug and the published
|
|
562
|
+
* version pinned at create.
|
|
563
|
+
* @public
|
|
564
|
+
*/
|
|
565
|
+
interface SessionFlowRef {
|
|
566
|
+
id: string;
|
|
567
|
+
slug: string;
|
|
568
|
+
version: number;
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* One flow of your app, from {@link Sekyro.listFlows}. Published flows only;
|
|
572
|
+
* pass `slug` or `id` as {@link CreateSessionInput.flow}.
|
|
573
|
+
* @public
|
|
574
|
+
*/
|
|
575
|
+
interface FlowSummary {
|
|
576
|
+
/** `flw_` id. */
|
|
577
|
+
id: string;
|
|
578
|
+
slug: string;
|
|
579
|
+
name: string;
|
|
580
|
+
/** The published version a new session runs. */
|
|
581
|
+
version: number;
|
|
582
|
+
/** The flow a session runs when you send no `flow`. */
|
|
583
|
+
isDefault: boolean;
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* Input of {@link SessionsApi.create}. The API key belongs to an app; the
|
|
587
|
+
* app's flow (its default flow, or the one named in `flow`) decides the steps.
|
|
588
|
+
* @public
|
|
589
|
+
*/
|
|
590
|
+
interface CreateSessionInput {
|
|
591
|
+
/**
|
|
592
|
+
* The app's flow to run: its slug (e.g. `foreigners`) or `flw_` id, as
|
|
593
|
+
* {@link Sekyro.listFlows} lists them. Absent = the app's default flow.
|
|
594
|
+
* Errors: `404 flow_not_found` (no such flow in the key's app),
|
|
595
|
+
* `409 flow_not_published`, `409 flow_archived`.
|
|
596
|
+
*/
|
|
597
|
+
flow?: string;
|
|
598
|
+
/** Pins the hosted-flow language. Omit to let the person's device decide. */
|
|
599
|
+
locale?: Locale;
|
|
600
|
+
/**
|
|
601
|
+
* Pre-choose the identity method when the flow offers a choice of identity
|
|
602
|
+
* method (the hosted choice screen is then skipped). Ignored otherwise.
|
|
603
|
+
*/
|
|
604
|
+
identityMethod?: IdentityMethod;
|
|
605
|
+
/**
|
|
606
|
+
* Session lifetime in minutes. Must fall within the flow's link range,
|
|
607
|
+
* otherwise the API answers `400 ttl_out_of_policy`. Omit to use the
|
|
608
|
+
* flow's default.
|
|
609
|
+
*/
|
|
610
|
+
ttlMinutes?: number;
|
|
611
|
+
/** Also send the hosted link to the person by SMS or WhatsApp. */
|
|
612
|
+
deliver?: DeliverOptions;
|
|
613
|
+
/**
|
|
614
|
+
* Where the hosted flow returns the person when the session ends
|
|
615
|
+
* ({@link SessionLinkInput}). A URL outside the app's web origins and app
|
|
616
|
+
* scheme answers `400 return_url_not_allowed`.
|
|
617
|
+
*/
|
|
618
|
+
link?: SessionLinkInput;
|
|
619
|
+
/**
|
|
620
|
+
* What you already know about the person (preferred over `input` for
|
|
621
|
+
* identity data). A key sent in both `subject` and `input` with different
|
|
622
|
+
* values answers `400 subject_input_conflict`.
|
|
623
|
+
*/
|
|
624
|
+
subject?: SessionSubjectInput;
|
|
625
|
+
/**
|
|
626
|
+
* Your own id for the agent filming the person, for flows whose liveness
|
|
627
|
+
* capture is `assisted` (1 to 128 characters). Stored as is and echoed on
|
|
628
|
+
* the session and in webhooks.
|
|
629
|
+
*/
|
|
630
|
+
assistedBy?: {
|
|
631
|
+
externalRef: string;
|
|
632
|
+
};
|
|
633
|
+
/**
|
|
634
|
+
* Override the flow for this session only ({@link FlowOverrides}): its
|
|
635
|
+
* general settings and per-service settings, or turn a service `'off'`.
|
|
636
|
+
* `400 override_invalid` for an unknown key or an invalid result;
|
|
637
|
+
* `403 override_widens_flow` for a change that makes the flow less strict
|
|
638
|
+
* when the flow does not allow widening.
|
|
639
|
+
*/
|
|
640
|
+
overrides?: FlowOverrides;
|
|
641
|
+
/**
|
|
642
|
+
* Step inputs consumed server-side. The known anchors are typed (all
|
|
643
|
+
* strings — an `nni` is a 10-digit string, never a number); further keys
|
|
644
|
+
* pass through to the API as-is. `nni` binds the session to that identity:
|
|
645
|
+
* the hosted flow may omit it but cannot substitute another.
|
|
646
|
+
*/
|
|
647
|
+
input?: {
|
|
648
|
+
/** 10-digit Mauritanian NNI, as a string. */
|
|
649
|
+
nni?: string;
|
|
650
|
+
/** E.164 phone number, e.g. `+22236123456`. */
|
|
651
|
+
phone?: string;
|
|
652
|
+
/** Email address for the email OTP step (`emailSource` `prefilled` / `prefilled_or_entered`). */
|
|
653
|
+
email?: string;
|
|
654
|
+
fullName?: string;
|
|
655
|
+
/** ISO 8601 date (`YYYY-MM-DD`). */
|
|
656
|
+
birthDate?: string;
|
|
657
|
+
/**
|
|
658
|
+
* Partner-supplied identity data (`supplied` mode only): the person's
|
|
659
|
+
* biographic record and photo as YOUR system holds them — for example
|
|
660
|
+
* from your own ANRPTS answer, converted with {@link registryFromAnrpts}.
|
|
661
|
+
* Sekyro AI stores it as data you vouch for, makes no registry call, and
|
|
662
|
+
* never receives or stores any registry key. `nni` must be set too and
|
|
663
|
+
* equal `suppliedIdentity.nni`. Refused unless Sekyro AI enabled the mode
|
|
664
|
+
* for the environment (`403 supplied_identity_not_entitled`); required in
|
|
665
|
+
* that mode when the app verifies identity (`422 supplied_identity_required`).
|
|
666
|
+
*/
|
|
667
|
+
suppliedIdentity?: SuppliedIdentityRecord;
|
|
668
|
+
} & Record<string, unknown>;
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* Partner-supplied identity data (`sessions.create` `input.suppliedIdentity`):
|
|
672
|
+
* the person's biographic record and photo, as your organization holds them.
|
|
673
|
+
* Sekyro AI treats it as identity data supplied by your organization, not as
|
|
674
|
+
* a registry lookup. Refusals at create: `400 supplied_identity_nni_mismatch`,
|
|
675
|
+
* `422 supplied_identity_stale` (`fetchedAt` older than 24 h),
|
|
676
|
+
* `422 supplied_identity_photo_unusable` (not a JPEG/PNG of at most 1 MB within the
|
|
677
|
+
* size bounds). In a `supplied` environment whose app verifies identity, a create
|
|
678
|
+
* without `input.suppliedIdentity` is `422 supplied_identity_required`. The face on
|
|
679
|
+
* the photo is checked after consent, at the face match (`no_face_reference`).
|
|
680
|
+
* @public
|
|
681
|
+
*/
|
|
682
|
+
interface SuppliedIdentityRecord {
|
|
683
|
+
/** 10-digit NNI, as a string. */
|
|
684
|
+
nni: string;
|
|
685
|
+
firstNameFr: string;
|
|
686
|
+
lastNameFr: string;
|
|
687
|
+
fatherNameFr?: string;
|
|
688
|
+
firstNameAr: string;
|
|
689
|
+
lastNameAr: string;
|
|
690
|
+
fatherNameAr?: string;
|
|
691
|
+
/** ISO 8601 date (`YYYY-MM-DD`). */
|
|
692
|
+
birthDate: string;
|
|
693
|
+
birthPlaceFr?: string;
|
|
694
|
+
birthPlaceAr?: string;
|
|
695
|
+
sex?: "M" | "F";
|
|
696
|
+
/** Nationality text as your source holds it (e.g. `Mauritanienne`). */
|
|
697
|
+
nationalities?: string[];
|
|
698
|
+
/** Base64 JPEG or PNG (at most 1 MB decoded). */
|
|
699
|
+
photo: string;
|
|
700
|
+
/** ISO 8601 date (`YYYY-MM-DD`) of the registry photo. */
|
|
701
|
+
photoDate?: string;
|
|
702
|
+
/** ISO 8601 date-time at which your system obtained this record. */
|
|
703
|
+
fetchedAt: string;
|
|
704
|
+
}
|
|
705
|
+
/** Per-request options. @public */
|
|
706
|
+
interface RequestOptions {
|
|
707
|
+
/**
|
|
708
|
+
* Sent as `X-Idempotency-Key`. Replaying the same key within 24 h returns the
|
|
709
|
+
* original response instead of creating a second session.
|
|
710
|
+
*/
|
|
711
|
+
idempotencyKey?: string;
|
|
712
|
+
}
|
|
713
|
+
/**
|
|
714
|
+
* Result of {@link SessionsApi.create}. `clientToken` is returned ONCE and never
|
|
715
|
+
* again — hand it to the browser (`@sekyro/web`) and do not persist it.
|
|
716
|
+
* @public
|
|
717
|
+
*/
|
|
718
|
+
interface CreatedSession {
|
|
719
|
+
id: string;
|
|
720
|
+
status: SessionStatus;
|
|
721
|
+
/** One-time credential for the client SDK / hosted flow. */
|
|
722
|
+
clientToken: string;
|
|
723
|
+
/** Hosted verification link for this session. */
|
|
724
|
+
hostedUrl: string;
|
|
725
|
+
/** The flow version the session runs (the default flow when you sent no `flow`). */
|
|
726
|
+
flow?: SessionFlowRef;
|
|
727
|
+
/** The checks on the session's path (checks of a lane not taken are omitted). */
|
|
728
|
+
steps: SessionStep[];
|
|
729
|
+
/** ISO 8601 — when the session (and its link) stop accepting input. */
|
|
730
|
+
expiresAt: string;
|
|
731
|
+
/** The levels the flow can reach on its paths; absent from older API versions. */
|
|
732
|
+
levelTarget?: LevelTarget;
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* Input of {@link SubjectsApi.createSession}: a re-check or step-up session
|
|
736
|
+
* for an existing subject in one call.
|
|
737
|
+
* @public
|
|
738
|
+
*/
|
|
739
|
+
interface SubjectSessionInput {
|
|
740
|
+
mode: SubjectReuseMode;
|
|
741
|
+
/** The app's flow to run (slug or `flw_` id); absent = the app's default flow. */
|
|
742
|
+
flow?: string;
|
|
743
|
+
link?: SessionLinkInput;
|
|
744
|
+
/** Session lifetime in minutes, within the flow's link range. */
|
|
745
|
+
ttlMinutes?: number;
|
|
746
|
+
locale?: Locale;
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* Which subject {@link SubjectsApi.createSession} targets: the subject id or
|
|
750
|
+
* your own external reference.
|
|
751
|
+
* @public
|
|
752
|
+
*/
|
|
753
|
+
type SubjectSessionTarget = {
|
|
754
|
+
subjectId: string;
|
|
755
|
+
} | {
|
|
756
|
+
externalRef: string;
|
|
757
|
+
};
|
|
758
|
+
/** Result of {@link SessionsApi.resultToken}: a freshly signed result token. @public */
|
|
759
|
+
interface ResultTokenResponse {
|
|
760
|
+
/** ES256 JWT; check it with {@link verifyResultToken}. */
|
|
761
|
+
token: string;
|
|
762
|
+
/** ISO 8601: when the token expires (10 minutes after signing). */
|
|
763
|
+
expiresAt: string;
|
|
764
|
+
}
|
|
765
|
+
/**
|
|
766
|
+
* The end user's network at the start of the session (IP-derived, approximate).
|
|
767
|
+
* @public
|
|
768
|
+
*/
|
|
769
|
+
interface SessionNetworkEvent {
|
|
770
|
+
/** ISO 8601. */
|
|
771
|
+
at: string;
|
|
772
|
+
/** ISO 3166-1 alpha-2. */
|
|
773
|
+
country?: string;
|
|
774
|
+
region?: string;
|
|
775
|
+
city?: string;
|
|
776
|
+
asn?: number;
|
|
777
|
+
operator?: string;
|
|
778
|
+
connectionType: "mobile" | "hosting" | "unknown";
|
|
779
|
+
anonymizer: {
|
|
780
|
+
vpn: boolean;
|
|
781
|
+
tor: boolean;
|
|
782
|
+
hosting: boolean;
|
|
783
|
+
};
|
|
784
|
+
/** IANA time zone reported by the end user's device. */
|
|
785
|
+
browserTimezone?: string;
|
|
786
|
+
/** True when the device time zone does not belong to the IP country. */
|
|
787
|
+
timezoneMismatch?: boolean;
|
|
788
|
+
}
|
|
789
|
+
/**
|
|
790
|
+
* End-user network context; absent when not recorded.
|
|
791
|
+
* @public
|
|
792
|
+
*/
|
|
793
|
+
interface SessionNetwork {
|
|
794
|
+
/** The start event's IP address. Never sent in webhooks. */
|
|
795
|
+
ip?: string;
|
|
796
|
+
/** True when a later call came from a different country than the start. */
|
|
797
|
+
countryChanged: boolean;
|
|
798
|
+
start: SessionNetworkEvent;
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* Device signals detected on the end user's device.
|
|
802
|
+
* @public
|
|
803
|
+
*/
|
|
804
|
+
type SessionDeviceSignal = "webdriver" | "headless" | "emulator" | "rooted" | "jailbroken" | "debugger" | "hooking" | "virtual_camera";
|
|
805
|
+
/**
|
|
806
|
+
* End-user device summary; absent when not recorded.
|
|
807
|
+
* @public
|
|
808
|
+
*/
|
|
809
|
+
interface SessionDevice {
|
|
810
|
+
platform: "web" | "android" | "ios";
|
|
811
|
+
sdk?: string;
|
|
812
|
+
os?: string;
|
|
813
|
+
osVersion?: string;
|
|
814
|
+
browser?: string;
|
|
815
|
+
browserVersion?: string;
|
|
816
|
+
deviceClass: "mobile" | "tablet" | "desktop" | "unknown";
|
|
817
|
+
model?: string;
|
|
818
|
+
/** Device ids hashed with a key unique to your organization. */
|
|
819
|
+
deviceKeys: string[];
|
|
820
|
+
signals: SessionDeviceSignal[];
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
* The national eID that verified the session's identity (the `eid_auth` check
|
|
824
|
+
* passed): the provider id (`{country}.{provider}`, e.g. `MR.houwiyeti`), its
|
|
825
|
+
* ISO 3166-1 alpha-2 country and when. A passed eID ends the session.
|
|
826
|
+
* @public
|
|
827
|
+
*/
|
|
828
|
+
interface EidResult {
|
|
829
|
+
provider: string;
|
|
830
|
+
country: string;
|
|
831
|
+
verifiedAt: string;
|
|
832
|
+
}
|
|
833
|
+
/**
|
|
834
|
+
* The full phone number and email address the person verified in a session
|
|
835
|
+
* (an OTP check that passed) — sent ONLY to you (the session view and your
|
|
836
|
+
* webhooks), never to the person's browser, and removed when the session's
|
|
837
|
+
* personal data is purged. You are the controller of these values. A
|
|
838
|
+
* prefilled value that was not verified is never listed.
|
|
839
|
+
* @public
|
|
840
|
+
*/
|
|
841
|
+
interface VerifiedContacts {
|
|
842
|
+
/** From a passed `phone_otp` check. */
|
|
843
|
+
phone?: {
|
|
844
|
+
/** E.164, e.g. `+22236123456`. */
|
|
845
|
+
number: string;
|
|
846
|
+
/** The channel the code was delivered on. */
|
|
847
|
+
channel: "whatsapp" | "sms";
|
|
848
|
+
/** ISO 8601. */
|
|
849
|
+
verifiedAt: string;
|
|
850
|
+
};
|
|
851
|
+
/** From a passed `email_otp` check. */
|
|
852
|
+
email?: {
|
|
853
|
+
/** The verified address (domain lowercased). */
|
|
854
|
+
address: string;
|
|
855
|
+
/** ISO 8601. */
|
|
856
|
+
verifiedAt: string;
|
|
857
|
+
};
|
|
858
|
+
}
|
|
859
|
+
/**
|
|
860
|
+
* The whitelisted session view returned by {@link SessionsApi.get}. Never
|
|
861
|
+
* contains the client token.
|
|
862
|
+
* @public
|
|
863
|
+
*/
|
|
864
|
+
interface Session {
|
|
865
|
+
id: string;
|
|
866
|
+
/** Sekyro flows: the flow version the session runs (absent on sessions created before flows). */
|
|
867
|
+
flow?: SessionFlowRef;
|
|
868
|
+
status: SessionStatus;
|
|
869
|
+
outcome: SessionOutcome | null;
|
|
870
|
+
/**
|
|
871
|
+
* What the session proved ({@link VerificationLevel}); `null` while the
|
|
872
|
+
* session is active, `0` when it was rejected. Absent from older API versions.
|
|
873
|
+
*/
|
|
874
|
+
level?: VerificationLevel | null;
|
|
875
|
+
/** How the level was proved; `null` while the session is active. */
|
|
876
|
+
assurance?: VerificationAssurance | null;
|
|
877
|
+
/** The billing unit the session consumed; `null` while the session is active. */
|
|
878
|
+
unit?: VerificationUnit | null;
|
|
879
|
+
/** The levels the session's flow can reach. */
|
|
880
|
+
levelTarget?: LevelTarget;
|
|
881
|
+
/** The checks on the session's path (checks of a lane the person did not take are omitted). */
|
|
882
|
+
steps: SessionStep[];
|
|
883
|
+
/** ISO 8601. */
|
|
884
|
+
expiresAt: string;
|
|
885
|
+
/** ISO 8601. */
|
|
886
|
+
createdAt: string;
|
|
887
|
+
/** ISO 8601: when the session reached a terminal state; `null` while it is active. */
|
|
888
|
+
completedAt?: string | null;
|
|
889
|
+
/** End-user network context; absent when not recorded. */
|
|
890
|
+
network?: SessionNetwork;
|
|
891
|
+
/** End-user device; absent when not recorded. */
|
|
892
|
+
device?: SessionDevice;
|
|
893
|
+
/**
|
|
894
|
+
* Set when a profile-v2 policy ended the session: a session-level gate
|
|
895
|
+
* (location, anonymizer) or a failed check's policy reason (eligibility,
|
|
896
|
+
* `document_nni_mismatch`). Absent otherwise.
|
|
897
|
+
*/
|
|
898
|
+
failureReason?: PolicyFailureReason;
|
|
899
|
+
/** With failureReason `camera_unavailable`: why (`denied` or `no_camera`), when the SDK said. Absent otherwise. */
|
|
900
|
+
failureDetail?: CameraUnavailableCause;
|
|
901
|
+
/** The subject (person) this session is linked to, once an identifier is known. */
|
|
902
|
+
subjectId?: string;
|
|
903
|
+
/** Your own id for the person, from `subject.externalRef` at create. */
|
|
904
|
+
externalRef?: string;
|
|
905
|
+
/** The agent reference sent as `assistedBy` at create, for assisted capture. */
|
|
906
|
+
assistedBy?: {
|
|
907
|
+
externalRef: string;
|
|
908
|
+
};
|
|
909
|
+
/**
|
|
910
|
+
* `true` when an identifier this session read already belongs to a
|
|
911
|
+
* different subject than `subjectId` — the subjects are never merged.
|
|
912
|
+
*/
|
|
913
|
+
subjectConflict?: boolean;
|
|
914
|
+
/**
|
|
915
|
+
* ISO 8601 — when the end user's device may verify again; set with
|
|
916
|
+
* `failureReason: 'device_cooldown'`.
|
|
917
|
+
*/
|
|
918
|
+
retryAfter?: string;
|
|
919
|
+
/**
|
|
920
|
+
* Dotted paths this session's {@link CreateSessionInput.overrides} changed
|
|
921
|
+
* (e.g. `settings.decisions.mode`, `services.liveness`).
|
|
922
|
+
*/
|
|
923
|
+
overriddenFields?: string[];
|
|
924
|
+
/**
|
|
925
|
+
* Risk signals recorded on the session (e.g. `device_velocity`,
|
|
926
|
+
* `timezone_mismatch`, `icao_non_compliant` when an `alert` ICAO policy flagged
|
|
927
|
+
* the selfie) — signals only, never a verdict by themselves.
|
|
928
|
+
*/
|
|
929
|
+
riskSignals?: string[];
|
|
930
|
+
/**
|
|
931
|
+
* `true` for a returning-user session (created with
|
|
932
|
+
* {@link SessionSubjectInput.reuse}): liveness + face match against the
|
|
933
|
+
* subject's stored reference photo only.
|
|
934
|
+
*/
|
|
935
|
+
returning?: true;
|
|
936
|
+
/** On a returning-user session: the subject (person) it re-verifies. */
|
|
937
|
+
reuseOf?: string;
|
|
938
|
+
/**
|
|
939
|
+
* On a session created for an existing subject: `recheck` (the same person
|
|
940
|
+
* again) or `step_up` (raised to identity level). Absent otherwise.
|
|
941
|
+
*/
|
|
942
|
+
reuseMode?: SubjectReuseMode;
|
|
943
|
+
/** The contacts verified in this session (passed OTP checks only); absent when none. */
|
|
944
|
+
verifiedContacts?: VerifiedContacts;
|
|
945
|
+
/** The national eID that verified this session (the `eid_auth` check passed); absent otherwise. */
|
|
946
|
+
eid?: EidResult;
|
|
947
|
+
/**
|
|
948
|
+
* ID mode (`portrait.purpose = id_document`) only: the ICAO portrait can be
|
|
949
|
+
* fetched with {@link SessionsApi.portrait}.
|
|
950
|
+
*/
|
|
951
|
+
portraitAvailable?: boolean;
|
|
952
|
+
}
|
|
953
|
+
/**
|
|
954
|
+
* `data` of the terminal / review-pending session lifecycle events
|
|
955
|
+
* (`session.completed` | `session.failed` | `session.review_pending` |
|
|
956
|
+
* `session.expired`): ids and enums only, no civil data,
|
|
957
|
+
* scores or links. `outcome` and `steps` travel on `completed` / `failed`;
|
|
958
|
+
* `review_pending` carries `steps` without an outcome; `expired` carries the
|
|
959
|
+
* status and the session's refs (`flow`, subject ids, `overriddenFields`).
|
|
960
|
+
* @public
|
|
961
|
+
*/
|
|
962
|
+
interface SessionLifecycleEventData {
|
|
963
|
+
sessionId: string;
|
|
964
|
+
status: SessionStatus;
|
|
965
|
+
outcome?: SessionOutcome | null;
|
|
966
|
+
/** On `completed` / `failed`: the app the session belongs to. */
|
|
967
|
+
appId?: string;
|
|
968
|
+
/** On `completed` / `failed`: what the session proved ({@link VerificationLevel}). */
|
|
969
|
+
level?: VerificationLevel | null;
|
|
970
|
+
/** On `completed` / `failed`: how the level was proved. */
|
|
971
|
+
assurance?: VerificationAssurance | null;
|
|
972
|
+
/** On `completed` / `failed`: the billing unit the session consumed. */
|
|
973
|
+
unit?: VerificationUnit | null;
|
|
974
|
+
/** On `completed` / `failed`: ISO 8601 terminal time. */
|
|
975
|
+
verifiedAt?: string;
|
|
976
|
+
/** On `completed` / `failed`: device and network risk facts, when recorded. */
|
|
977
|
+
risk?: ResultRisk;
|
|
978
|
+
/** On `completed` / `failed`: other subjects the face matched, when a duplicate search ran. */
|
|
979
|
+
duplicates?: ResultDuplicate[];
|
|
980
|
+
/**
|
|
981
|
+
* On `completed` / `failed`: the signed result token (ES256 JWT, valid
|
|
982
|
+
* 10 minutes). Check it with {@link verifyResultToken}; absent when
|
|
983
|
+
* result tokens are not enabled.
|
|
984
|
+
*/
|
|
985
|
+
resultToken?: string;
|
|
986
|
+
/** The checks on the session's path (checks of a lane the person did not take are omitted). */
|
|
987
|
+
steps?: Array<Pick<SessionStep, "checkType" | "state" | "nodeId" | "service">>;
|
|
988
|
+
/** Sekyro flows: the flow version the session runs (absent on sessions created before flows). */
|
|
989
|
+
flow?: SessionFlowRef;
|
|
990
|
+
/** Machine-readable reason, when the transition has one. */
|
|
991
|
+
reason?: string;
|
|
992
|
+
/** End-user network context (no IP); on `completed` / `failed` when recorded. */
|
|
993
|
+
network?: Omit<SessionNetwork, "ip">;
|
|
994
|
+
/** End-user device; on `completed` / `failed` when recorded. */
|
|
995
|
+
device?: SessionDevice;
|
|
996
|
+
/**
|
|
997
|
+
* On `session.failed`: set when a profile-v2 policy ended the session — a
|
|
998
|
+
* session-level gate (location, anonymizer) or a failed check's policy
|
|
999
|
+
* reason (eligibility, `document_nni_mismatch`).
|
|
1000
|
+
*/
|
|
1001
|
+
failureReason?: PolicyFailureReason;
|
|
1002
|
+
/** On `session.failed` with failureReason `camera_unavailable`: why (`denied` or `no_camera`), when the SDK said. Absent otherwise. */
|
|
1003
|
+
failureDetail?: CameraUnavailableCause;
|
|
1004
|
+
/** The subject (person) the session is linked to, when known. */
|
|
1005
|
+
subjectId?: string;
|
|
1006
|
+
/** Your own id for the person, from `subject.externalRef` at create. */
|
|
1007
|
+
externalRef?: string;
|
|
1008
|
+
/**
|
|
1009
|
+
* `true` when an identifier this session read already belongs to a
|
|
1010
|
+
* different subject than `subjectId` — the subjects are never merged.
|
|
1011
|
+
*/
|
|
1012
|
+
subjectConflict?: boolean;
|
|
1013
|
+
/** `true` on a returning-user session (liveness + face match against the stored photo). */
|
|
1014
|
+
returning?: true;
|
|
1015
|
+
/** On a returning-user session: the subject (person) it re-verifies. */
|
|
1016
|
+
reuseOf?: string;
|
|
1017
|
+
/**
|
|
1018
|
+
* On a session created for an existing subject: `recheck` (the same person
|
|
1019
|
+
* again) or `step_up` (raised to identity level). Absent otherwise.
|
|
1020
|
+
*/
|
|
1021
|
+
reuseMode?: SubjectReuseMode;
|
|
1022
|
+
/**
|
|
1023
|
+
* On `completed` / `failed`: the `link.state` the session was created
|
|
1024
|
+
* with, echoed back; absent when the session had none.
|
|
1025
|
+
*/
|
|
1026
|
+
link?: {
|
|
1027
|
+
state: string;
|
|
1028
|
+
};
|
|
1029
|
+
/**
|
|
1030
|
+
* On `session.failed` with `failureReason: 'device_cooldown'`: ISO time
|
|
1031
|
+
* from which the device may start a new verification.
|
|
1032
|
+
*/
|
|
1033
|
+
retryAfter?: string;
|
|
1034
|
+
/** Dotted paths the session's create-time {@link CreateSessionInput.overrides} changed. */
|
|
1035
|
+
overriddenFields?: string[];
|
|
1036
|
+
/** On `completed` / `failed`: the contacts verified in this session (passed OTP checks only). */
|
|
1037
|
+
verifiedContacts?: VerifiedContacts;
|
|
1038
|
+
/** On `completed` / `failed`: the national eID that verified this session, when one did. */
|
|
1039
|
+
eid?: EidResult;
|
|
1040
|
+
/**
|
|
1041
|
+
* ID mode only, on `completed` / `failed`: the ICAO portrait can be fetched
|
|
1042
|
+
* with {@link SessionsApi.portrait} (the event never carries the image).
|
|
1043
|
+
*/
|
|
1044
|
+
portraitAvailable?: boolean;
|
|
1045
|
+
}
|
|
1046
|
+
/**
|
|
1047
|
+
* `data` of `subject.updated` — either a session linked to the subject reached
|
|
1048
|
+
* a terminal state (`sessionId`, session `status`, `outcome`), or the subject
|
|
1049
|
+
* was revoked (`status: 'revoked'`, no session). Ids and enums only.
|
|
1050
|
+
* @public
|
|
1051
|
+
*/
|
|
1052
|
+
interface SubjectUpdatedEventData {
|
|
1053
|
+
subjectId: string;
|
|
1054
|
+
/** The session that reached a terminal state; absent on a revocation. */
|
|
1055
|
+
sessionId?: string;
|
|
1056
|
+
status: SessionStatus | "revoked";
|
|
1057
|
+
/** The session outcome; absent on a revocation. */
|
|
1058
|
+
outcome?: SessionOutcome | null;
|
|
1059
|
+
/** The session's level; absent on a revocation. */
|
|
1060
|
+
level?: VerificationLevel | null;
|
|
1061
|
+
/** The session's assurance; absent on a revocation. */
|
|
1062
|
+
assurance?: VerificationAssurance | null;
|
|
1063
|
+
/**
|
|
1064
|
+
* Your own ids for the person (`subject.externalRef` values), so a
|
|
1065
|
+
* revocation can find your user without a lookup. Absent from older API versions.
|
|
1066
|
+
*/
|
|
1067
|
+
externalRefs?: string[];
|
|
1068
|
+
}
|
|
1069
|
+
/**
|
|
1070
|
+
* `data` of `subject.enrolled` — the subject's first reference photo was
|
|
1071
|
+
* stored (it can now be used for returning-user sessions). Ids and enums only.
|
|
1072
|
+
* @public
|
|
1073
|
+
*/
|
|
1074
|
+
interface SubjectEnrolledEventData {
|
|
1075
|
+
subjectId: string;
|
|
1076
|
+
/** The approved session the reference photo came from. */
|
|
1077
|
+
sessionId: string;
|
|
1078
|
+
assurance: SubjectAssurance;
|
|
1079
|
+
}
|
|
1080
|
+
/**
|
|
1081
|
+
* `data` of `subject.deleted`. A delete through the subjects API carries
|
|
1082
|
+
* `subjectId`; a right-to-erasure request carries the tokenized `subjectRef`
|
|
1083
|
+
* (with `orgId` / `env`) instead — never the national number.
|
|
1084
|
+
* @public
|
|
1085
|
+
*/
|
|
1086
|
+
interface SubjectDeletedEventData {
|
|
1087
|
+
subjectId?: string;
|
|
1088
|
+
subjectRef?: string;
|
|
1089
|
+
orgId?: string;
|
|
1090
|
+
env?: SekyroEnvironment;
|
|
1091
|
+
/**
|
|
1092
|
+
* With `subjectId` (a delete through the subjects API): your own ids for
|
|
1093
|
+
* the person, so you can find your user. Never on the erasure variant.
|
|
1094
|
+
*/
|
|
1095
|
+
externalRefs?: string[];
|
|
1096
|
+
}
|
|
1097
|
+
/** Subject lifecycle: a revoked subject cannot be reused. @public */
|
|
1098
|
+
type SubjectStatus = "active" | "revoked";
|
|
1099
|
+
/**
|
|
1100
|
+
* How strongly a subject's identity was established: the reference photo
|
|
1101
|
+
* came from the national registry, the document's chip (`chip_biometric`, a
|
|
1102
|
+
* passed chip read plus a face match) or the document, and a face match passed
|
|
1103
|
+
* (`*_biometric`) or the session had no face match (`*_only`). `supplied_*`:
|
|
1104
|
+
* partner-supplied identity data (`input.suppliedIdentity`), with
|
|
1105
|
+
* (`supplied_biometric`) or without (`supplied_only`) a face match against its photo.
|
|
1106
|
+
* @public
|
|
1107
|
+
*/
|
|
1108
|
+
type SubjectAssurance = "registry_biometric" | "chip_biometric" | "document_biometric" | "registry_only" | "document_only" | "supplied_biometric" | "supplied_only";
|
|
1109
|
+
/**
|
|
1110
|
+
* Origin of a subject's stored reference photo, best first (`chip`: the document chip's portrait;
|
|
1111
|
+
* `org_supplied`: the photo of your partner-supplied identity data).
|
|
1112
|
+
* @public
|
|
1113
|
+
*/
|
|
1114
|
+
type SubjectReferenceSource = "registry" | "doc_registry" | "chip" | "org_supplied" | "document";
|
|
1115
|
+
/** One session linked to a subject. @public */
|
|
1116
|
+
interface SubjectSession {
|
|
1117
|
+
sessionId: string;
|
|
1118
|
+
appId: string | null;
|
|
1119
|
+
/** ISO 8601 — when the session was linked. */
|
|
1120
|
+
at: string;
|
|
1121
|
+
status: SessionStatus;
|
|
1122
|
+
outcome: SessionOutcome | null;
|
|
1123
|
+
/** What the session proved; present only when stored (sessions linked before the field existed have none). */
|
|
1124
|
+
level?: VerificationLevel;
|
|
1125
|
+
/** How the session's level was proved; present only when stored. */
|
|
1126
|
+
assurance?: VerificationAssurance;
|
|
1127
|
+
}
|
|
1128
|
+
/**
|
|
1129
|
+
* A subject (the same person across your apps), as `GET /subjects/:id`
|
|
1130
|
+
* returns it. Never contains photo keys or URLs.
|
|
1131
|
+
* @public
|
|
1132
|
+
*/
|
|
1133
|
+
interface Subject {
|
|
1134
|
+
id: string;
|
|
1135
|
+
status: SubjectStatus;
|
|
1136
|
+
/** ISO 8601 — present only when revoked. */
|
|
1137
|
+
revokedAt?: string;
|
|
1138
|
+
sessions: SubjectSession[];
|
|
1139
|
+
externalRefs: string[];
|
|
1140
|
+
/** ISO 8601. */
|
|
1141
|
+
firstSeenAt: string;
|
|
1142
|
+
/** ISO 8601. */
|
|
1143
|
+
lastSeenAt: string;
|
|
1144
|
+
/** ISO 8601, or `null` before the first approved session. */
|
|
1145
|
+
lastPassedAt: string | null;
|
|
1146
|
+
/** ISO 8601 of the last approved full or returning session, or `null`. */
|
|
1147
|
+
lastVerifiedAt: string | null;
|
|
1148
|
+
/** The stored reference photo's origin and date — `null` until one is stored. */
|
|
1149
|
+
reference: {
|
|
1150
|
+
source: SubjectReferenceSource;
|
|
1151
|
+
capturedAt: string;
|
|
1152
|
+
} | null;
|
|
1153
|
+
assurance: SubjectAssurance | null;
|
|
1154
|
+
/**
|
|
1155
|
+
* The highest {@link VerificationLevel} an approved linked session proved;
|
|
1156
|
+
* `0` once the subject is revoked; `null` when no terminal session was
|
|
1157
|
+
* recorded since the field exists. Absent from API versions before the field.
|
|
1158
|
+
*/
|
|
1159
|
+
level?: VerificationLevel | null | undefined;
|
|
1160
|
+
/** ISO 8601: when {@link Subject.level} was last proved (the latest approved session at that level or higher); `null` with it. Absent with it. */
|
|
1161
|
+
levelAt?: string | null | undefined;
|
|
1162
|
+
/** The assurance of the session that proved {@link Subject.level}; `null` with it. Absent with it. */
|
|
1163
|
+
levelAssurance?: VerificationAssurance | null | undefined;
|
|
1164
|
+
/**
|
|
1165
|
+
* A returning-user session can be created now: active, a reference photo is
|
|
1166
|
+
* stored, and the last FULL verification (returning-user sessions do not
|
|
1167
|
+
* reset it) is within the returning-user limit of your app's default flow
|
|
1168
|
+
* (`settings.returning`: turned on, and `maxAgeMonths` when set).
|
|
1169
|
+
*/
|
|
1170
|
+
returningReady: boolean;
|
|
1171
|
+
/** The verified name / birth date of the latest approved session. */
|
|
1172
|
+
display?: {
|
|
1173
|
+
name?: string;
|
|
1174
|
+
birthDate?: string;
|
|
1175
|
+
};
|
|
1176
|
+
}
|
|
1177
|
+
/**
|
|
1178
|
+
* Filters of {@link SessionsApi.list}: your own user id
|
|
1179
|
+
* (`subject.externalRef` at create) and/or a status.
|
|
1180
|
+
* @public
|
|
1181
|
+
*/
|
|
1182
|
+
interface ListSessionsQuery {
|
|
1183
|
+
/** Your own id for the person (1 to 128 characters). */
|
|
1184
|
+
externalRef?: string;
|
|
1185
|
+
status?: SessionStatus;
|
|
1186
|
+
}
|
|
1187
|
+
/** Result of {@link SubjectsApi.delete}. @public */
|
|
1188
|
+
interface DeletedSubject {
|
|
1189
|
+
id: string;
|
|
1190
|
+
deleted: true;
|
|
1191
|
+
}
|
|
1192
|
+
/** Options of {@link SubjectsApi.revoke}. @public */
|
|
1193
|
+
interface RevokeSubjectInput {
|
|
1194
|
+
/** Kept on the audit trail only (≤ 500 characters). Do not put personal data here. */
|
|
1195
|
+
reason?: string;
|
|
1196
|
+
}
|
|
1197
|
+
/**
|
|
1198
|
+
* `data` of `subject.suspicious_activity` — a device already linked to
|
|
1199
|
+
* ANOTHER subject was used for a session of this subject. `count` is the
|
|
1200
|
+
* subject's running total of such events. Ids only.
|
|
1201
|
+
* @public
|
|
1202
|
+
*/
|
|
1203
|
+
interface SubjectSuspiciousActivityEventData {
|
|
1204
|
+
subjectId: string;
|
|
1205
|
+
sessionId: string;
|
|
1206
|
+
count: number;
|
|
1207
|
+
}
|
|
1208
|
+
/**
|
|
1209
|
+
* `data` of `session.step.completed` — the check that just passed.
|
|
1210
|
+
* @public
|
|
1211
|
+
*/
|
|
1212
|
+
interface SessionStepCompletedEventData {
|
|
1213
|
+
sessionId: string;
|
|
1214
|
+
checkType: CheckType;
|
|
1215
|
+
state: CheckState;
|
|
1216
|
+
/** Sekyro flows: the flow node of the passed check. */
|
|
1217
|
+
nodeId?: string;
|
|
1218
|
+
/** Sekyro flows: the service of that node. */
|
|
1219
|
+
service?: ServiceId;
|
|
1220
|
+
/** Sekyro flows: the flow version the session runs (absent on sessions created before flows). */
|
|
1221
|
+
flow?: SessionFlowRef;
|
|
1222
|
+
/** The subject (person) the session is linked to, when known. */
|
|
1223
|
+
subjectId?: string;
|
|
1224
|
+
/** Your own id for the person, from `subject.externalRef` at create. */
|
|
1225
|
+
externalRef?: string;
|
|
1226
|
+
/**
|
|
1227
|
+
* `true` when an identifier this session read already belongs to a
|
|
1228
|
+
* different subject than `subjectId` — the subjects are never merged.
|
|
1229
|
+
*/
|
|
1230
|
+
subjectConflict?: boolean;
|
|
1231
|
+
/** `true` on a returning-user session (liveness + face match against the stored photo). */
|
|
1232
|
+
returning?: true;
|
|
1233
|
+
/** On a returning-user session: the subject (person) it re-verifies. */
|
|
1234
|
+
reuseOf?: string;
|
|
1235
|
+
/** When the passed check is `phone_otp` / `email_otp`: that one verified contact. */
|
|
1236
|
+
verifiedContacts?: VerifiedContacts;
|
|
1237
|
+
}
|
|
1238
|
+
/**
|
|
1239
|
+
* `data` of `session.review_decided` — a human (or the review-timeout sweep)
|
|
1240
|
+
* decided a pending review. `outcome` speaks the REVIEW vocabulary
|
|
1241
|
+
* (`pass` | `fail`), not the session outcome; `reason` is the reviewer's code
|
|
1242
|
+
* (e.g. `review_timeout` for an expired review).
|
|
1243
|
+
* @public
|
|
1244
|
+
*/
|
|
1245
|
+
interface SessionReviewDecidedEventData {
|
|
1246
|
+
sessionId: string;
|
|
1247
|
+
outcome: "pass" | "fail";
|
|
1248
|
+
reason: string;
|
|
1249
|
+
/** Sekyro flows: the flow version the session runs (absent on sessions created before flows). */
|
|
1250
|
+
flow?: SessionFlowRef;
|
|
1251
|
+
/** The subject (person) the session is linked to, when known. */
|
|
1252
|
+
subjectId?: string;
|
|
1253
|
+
/** Your own id for the person, from `subject.externalRef` at create. */
|
|
1254
|
+
externalRef?: string;
|
|
1255
|
+
/**
|
|
1256
|
+
* `true` when an identifier this session read already belongs to a
|
|
1257
|
+
* different subject than `subjectId` — the subjects are never merged.
|
|
1258
|
+
*/
|
|
1259
|
+
subjectConflict?: boolean;
|
|
1260
|
+
/** `true` on a returning-user session (liveness + face match against the stored photo). */
|
|
1261
|
+
returning?: true;
|
|
1262
|
+
/** On a returning-user session: the subject (person) it re-verifies. */
|
|
1263
|
+
reuseOf?: string;
|
|
1264
|
+
/** ID mode only: the ICAO portrait can be fetched with {@link SessionsApi.portrait}. */
|
|
1265
|
+
portraitAvailable?: boolean;
|
|
1266
|
+
}
|
|
1267
|
+
/**
|
|
1268
|
+
* Event type → the shape of its `data`. Session events are typed; the
|
|
1269
|
+
* remaining events carry an open record until their payloads are frozen.
|
|
1270
|
+
* @public
|
|
1271
|
+
*/
|
|
1272
|
+
interface WebhookEventDataMap {
|
|
1273
|
+
"session.created": Record<string, unknown>;
|
|
1274
|
+
"session.started": Record<string, unknown>;
|
|
1275
|
+
"session.step.completed": SessionStepCompletedEventData;
|
|
1276
|
+
"session.review_pending": SessionLifecycleEventData;
|
|
1277
|
+
"session.review_decided": SessionReviewDecidedEventData;
|
|
1278
|
+
"session.completed": SessionLifecycleEventData;
|
|
1279
|
+
"session.expired": SessionLifecycleEventData;
|
|
1280
|
+
"session.failed": SessionLifecycleEventData;
|
|
1281
|
+
"subject.enrolled": SubjectEnrolledEventData;
|
|
1282
|
+
"subject.updated": SubjectUpdatedEventData;
|
|
1283
|
+
"subject.suspicious_activity": SubjectSuspiciousActivityEventData;
|
|
1284
|
+
"subject.deleted": SubjectDeletedEventData;
|
|
1285
|
+
"aml.match_flagged": Record<string, unknown>;
|
|
1286
|
+
"payment.received": Record<string, unknown>;
|
|
1287
|
+
"invoice.generated": Record<string, unknown>;
|
|
1288
|
+
"invoice.paid": Record<string, unknown>;
|
|
1289
|
+
"invoice.overdue": Record<string, unknown>;
|
|
1290
|
+
"webhook.test": Record<string, unknown>;
|
|
1291
|
+
}
|
|
1292
|
+
/** Every event a partner endpoint may receive. @public */
|
|
1293
|
+
type WebhookEventType = keyof WebhookEventDataMap;
|
|
1294
|
+
/**
|
|
1295
|
+
* The signed webhook payload for ONE event type. There is no global API
|
|
1296
|
+
* version; each event carries its own per-event `version`. Retried deliveries
|
|
1297
|
+
* keep the same `id` — de-duplicate on it.
|
|
1298
|
+
* @public
|
|
1299
|
+
*/
|
|
1300
|
+
interface WebhookEnvelopeOf<E extends WebhookEventType> {
|
|
1301
|
+
/** UUIDv7, stable across delivery retries. */
|
|
1302
|
+
id: string;
|
|
1303
|
+
event: E;
|
|
1304
|
+
/** Per-event payload version. */
|
|
1305
|
+
version: number;
|
|
1306
|
+
/** ISO 8601. */
|
|
1307
|
+
createdAt: string;
|
|
1308
|
+
orgId: string;
|
|
1309
|
+
env: SekyroEnvironment;
|
|
1310
|
+
data: WebhookEventDataMap[E];
|
|
1311
|
+
}
|
|
1312
|
+
/**
|
|
1313
|
+
* The signed webhook payload, discriminated on `event`: narrowing on
|
|
1314
|
+
* `envelope.event` narrows `envelope.data` to that event's shape.
|
|
1315
|
+
*
|
|
1316
|
+
* @example
|
|
1317
|
+
* ```ts
|
|
1318
|
+
* const envelope = verifyWebhook(rawBody, header, secret);
|
|
1319
|
+
* switch (envelope.event) {
|
|
1320
|
+
* case "session.completed":
|
|
1321
|
+
* envelope.data.outcome; // SessionOutcome | null | undefined
|
|
1322
|
+
* break;
|
|
1323
|
+
* case "session.review_decided":
|
|
1324
|
+
* envelope.data.outcome; // "pass" | "fail"
|
|
1325
|
+
* break;
|
|
1326
|
+
* }
|
|
1327
|
+
* ```
|
|
1328
|
+
* @public
|
|
1329
|
+
*/
|
|
1330
|
+
type WebhookEnvelope<E extends WebhookEventType = WebhookEventType> = E extends WebhookEventType ? WebhookEnvelopeOf<E> : never;
|
|
1331
|
+
/**
|
|
1332
|
+
* `data` of any `session.*` event.
|
|
1333
|
+
* @deprecated Use {@link SessionLifecycleEventData}, {@link SessionStepCompletedEventData}
|
|
1334
|
+
* or {@link SessionReviewDecidedEventData}, or narrow a {@link WebhookEnvelope} on `event`.
|
|
1335
|
+
* @public
|
|
1336
|
+
*/
|
|
1337
|
+
type SessionEventData = SessionLifecycleEventData | SessionStepCompletedEventData | SessionReviewDecidedEventData;
|
|
1338
|
+
|
|
1339
|
+
/** Default partner API origin + version prefix. @public */
|
|
1340
|
+
declare const DEFAULT_BASE_URL = "https://api.sekyro.ai/api/v2";
|
|
1341
|
+
/** Default per-request timeout. @public */
|
|
1342
|
+
declare const DEFAULT_TIMEOUT_MS = 30000;
|
|
1343
|
+
/** `fetch`-compatible function; the global `fetch` by default. @public */
|
|
1344
|
+
type FetchLike = typeof globalThis.fetch;
|
|
1345
|
+
/** Constructor options of {@link Sekyro}. @public */
|
|
1346
|
+
interface SekyroOptions {
|
|
1347
|
+
/** Partner API key (server-side only). Sent as `Authorization: Bearer`. */
|
|
1348
|
+
apiKey: string;
|
|
1349
|
+
/** API base URL incl. the `/api/v2` prefix. Default {@link DEFAULT_BASE_URL}. */
|
|
1350
|
+
baseUrl?: string;
|
|
1351
|
+
/** Per-request timeout in ms. Default {@link DEFAULT_TIMEOUT_MS}. */
|
|
1352
|
+
timeoutMs?: number;
|
|
1353
|
+
/** Custom `fetch` (tests, proxies, custom agents). Default `globalThis.fetch`. */
|
|
1354
|
+
fetch?: FetchLike;
|
|
1355
|
+
}
|
|
1356
|
+
/**
|
|
1357
|
+
* `sekyro.sessions` — create and read verification sessions.
|
|
1358
|
+
*
|
|
1359
|
+
* Exported as a TYPE only (`import type { SessionsApi }`): the class value is
|
|
1360
|
+
* not part of the package surface, so it can only be obtained through
|
|
1361
|
+
* {@link Sekyro.sessions} — never constructed by hand with an unchecked
|
|
1362
|
+
* transport.
|
|
1363
|
+
* @public
|
|
1364
|
+
*/
|
|
1365
|
+
declare class SessionsApi {
|
|
1366
|
+
private readonly call;
|
|
1367
|
+
/**
|
|
1368
|
+
* Constructed by {@link Sekyro}; the transport is kept out of the public
|
|
1369
|
+
* surface on purpose (only its bound `call` crosses this boundary).
|
|
1370
|
+
* @internal
|
|
1371
|
+
*/
|
|
1372
|
+
constructor(call: <T>(method: "GET" | "POST" | "DELETE", path: string, body?: unknown, idempotencyKey?: string) => Promise<T>);
|
|
1373
|
+
/**
|
|
1374
|
+
* `POST /sessions`. Returns the one-time `clientToken` — hand it to the
|
|
1375
|
+
* browser, never persist it. Pass an `idempotencyKey` so a retried call
|
|
1376
|
+
* cannot create a second session.
|
|
1377
|
+
*/
|
|
1378
|
+
create(input?: CreateSessionInput, opts?: RequestOptions): Promise<CreatedSession>;
|
|
1379
|
+
/**
|
|
1380
|
+
* `POST /sessions/:id/method` — choose the identity method of an
|
|
1381
|
+
* optional-document session on the person's behalf (the hosted method
|
|
1382
|
+
* screen is then skipped). `409 method_locked` once the choice can no
|
|
1383
|
+
* longer change; `409 session_not_active` on a finished or expired session.
|
|
1384
|
+
* On a flow session: `409 choice_not_found` (the flow has no identity-method
|
|
1385
|
+
* choice), `409 choice_locked`, `409 choice_option_unavailable` (see
|
|
1386
|
+
* {@link isFlowError}).
|
|
1387
|
+
*/
|
|
1388
|
+
selectMethod(id: string, method: IdentityMethod): Promise<Session>;
|
|
1389
|
+
/** `GET /sessions/:id` — the whitelisted view (no client token). */
|
|
1390
|
+
get(id: string): Promise<Session>;
|
|
1391
|
+
/**
|
|
1392
|
+
* `GET /sessions?externalRef=&status=`: your newest sessions (at most 100),
|
|
1393
|
+
* optionally filtered by your own user id and/or a status. The filters are
|
|
1394
|
+
* applied again to the answer, so an API that ignores them never returns
|
|
1395
|
+
* another user's sessions.
|
|
1396
|
+
*/
|
|
1397
|
+
list(query?: ListSessionsQuery): Promise<Session[]>;
|
|
1398
|
+
/**
|
|
1399
|
+
* `GET /sessions/:id/portrait?format=url` — ID mode: a 5-minute presigned
|
|
1400
|
+
* link to the 480×640 ICAO portrait (JPEG). Needs the `portrait:read` scope
|
|
1401
|
+
* (keys minted from the dashboard carry it). `404 portrait_not_available`
|
|
1402
|
+
* until the session's `portrait_icao` check has passed (`portraitAvailable`).
|
|
1403
|
+
*/
|
|
1404
|
+
portrait(id: string): Promise<SessionPortraitLink>;
|
|
1405
|
+
/**
|
|
1406
|
+
* `GET /sessions/:id/result-token`: a freshly signed result token for a
|
|
1407
|
+
* finished session (valid 10 minutes; check it with
|
|
1408
|
+
* {@link verifyResultToken}). `409 session_not_terminal` while the session
|
|
1409
|
+
* is still active. Needs the `sessions:read` scope.
|
|
1410
|
+
*/
|
|
1411
|
+
resultToken(id: string): Promise<ResultTokenResponse>;
|
|
1412
|
+
}
|
|
1413
|
+
/**
|
|
1414
|
+
* `sekyro.subjects` — read and manage subjects (the same person across your
|
|
1415
|
+
* apps). Reads need the `subjects:read` scope, `revoke` / `delete` the
|
|
1416
|
+
* `subjects:write` scope (keys minted from the dashboard carry both; an older
|
|
1417
|
+
* key answers `403 insufficient_scope`). A foreign or unknown id answers
|
|
1418
|
+
* `404 subject_not_found`.
|
|
1419
|
+
*
|
|
1420
|
+
* Type-only export, like {@link SessionsApi}: obtained through
|
|
1421
|
+
* {@link Sekyro.subjects}.
|
|
1422
|
+
* @public
|
|
1423
|
+
*/
|
|
1424
|
+
declare class SubjectsApi {
|
|
1425
|
+
private readonly call;
|
|
1426
|
+
/** @internal */
|
|
1427
|
+
constructor(call: <T>(method: "GET" | "POST" | "DELETE", path: string, body?: unknown, idempotencyKey?: string) => Promise<T>);
|
|
1428
|
+
/** `GET /subjects/:id` — the subject, its sessions and its returning-user readiness. */
|
|
1429
|
+
get(id: string): Promise<Subject>;
|
|
1430
|
+
/** `GET /subjects?externalRef=…` — the subjects carrying your own id (newest first, at most 50). */
|
|
1431
|
+
list(query: {
|
|
1432
|
+
externalRef: string;
|
|
1433
|
+
}): Promise<Subject[]>;
|
|
1434
|
+
/**
|
|
1435
|
+
* `POST /subjects/:id/revoke` — the subject can no longer be used for
|
|
1436
|
+
* returning-user sessions. Idempotent: revoking again returns the same view.
|
|
1437
|
+
* Emits `subject.updated` with `status: 'revoked'`.
|
|
1438
|
+
*/
|
|
1439
|
+
revoke(id: string, input?: RevokeSubjectInput, opts?: RequestOptions): Promise<Subject>;
|
|
1440
|
+
/**
|
|
1441
|
+
* `DELETE /subjects/:id` — deletes the subject's stored photos, face
|
|
1442
|
+
* templates and identifiers, and unlinks its sessions. Emits
|
|
1443
|
+
* `subject.deleted`. Cannot be undone; a second call answers `404`.
|
|
1444
|
+
*/
|
|
1445
|
+
delete(id: string): Promise<DeletedSubject>;
|
|
1446
|
+
/**
|
|
1447
|
+
* A re-check or step-up session for an existing subject in one call:
|
|
1448
|
+
* `POST /subjects/:id/sessions` when `target` is a subject id (24
|
|
1449
|
+
* hexadecimal characters) or `{ subjectId }`, otherwise
|
|
1450
|
+
* `POST /subjects/by-external-ref/:externalRef/sessions` (pass
|
|
1451
|
+
* `{ externalRef }` to force it). Same result and errors as
|
|
1452
|
+
* {@link SessionsApi.create}; needs the `sessions:create` and
|
|
1453
|
+
* `subjects:read` scopes.
|
|
1454
|
+
*/
|
|
1455
|
+
createSession(target: string | SubjectSessionTarget, input: SubjectSessionInput, opts?: RequestOptions): Promise<CreatedSession>;
|
|
1456
|
+
}
|
|
1457
|
+
/**
|
|
1458
|
+
* Sekyro AI partner API client. Server-side only: it carries your API key.
|
|
1459
|
+
*
|
|
1460
|
+
* Throws {@link SekyroConfigError} synchronously when `apiKey` is missing or
|
|
1461
|
+
* `baseUrl` is not `https:` (plain `http:` is accepted for `localhost`,
|
|
1462
|
+
* `127.0.0.1` and `[::1]` only).
|
|
1463
|
+
*
|
|
1464
|
+
* @example
|
|
1465
|
+
* ```ts
|
|
1466
|
+
* const sekyro = new Sekyro({ apiKey: process.env.SEKYRO_API_KEY! });
|
|
1467
|
+
* const { id, clientToken } = await sekyro.sessions.create({ input: { nni: "1357924632" } });
|
|
1468
|
+
* ```
|
|
1469
|
+
* @public
|
|
1470
|
+
*/
|
|
1471
|
+
declare class Sekyro {
|
|
1472
|
+
#private;
|
|
1473
|
+
readonly sessions: SessionsApi;
|
|
1474
|
+
readonly subjects: SubjectsApi;
|
|
1475
|
+
constructor(opts: SekyroOptions);
|
|
1476
|
+
/**
|
|
1477
|
+
* `GET /flows` — the published flows of the API key's app (default flow
|
|
1478
|
+
* first, then by name). Pass a flow's `slug` or `id` as
|
|
1479
|
+
* {@link CreateSessionInput.flow}. Needs the `sessions:create` scope; an
|
|
1480
|
+
* invalid key answers `401 unauthorized`.
|
|
1481
|
+
*/
|
|
1482
|
+
listFlows(): Promise<FlowSummary[]>;
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
export { type SessionLifecycleEventData as $, type ListSessionsQuery as A, type PortraitReportEntry as B, type CreatedSession as C, DEFAULT_BASE_URL as D, type EidResult as E, type FetchLike as F, type ProbeBindingReason as G, type ProbeQuality as H, type IdentityMethod as I, type ProfileDocumentType as J, type RequestOptions as K, type Locale as L, type MatchReason as M, type ResultTokenResponse as N, type RevokeSubjectInput as O, type PolicyFailureReason as P, type SekyroOptions as Q, type ResultRisk as R, Sekyro as S, type Session as T, type SessionDevice as U, type VerificationLevel as V, type WebhookEventType as W, type SessionDeviceSignal as X, type SessionEventData as Y, type SessionFailureReason as Z, type SessionFlowRef as _, type ServiceId as a, type SessionLinkInput as a0, type SessionNetwork as a1, type SessionNetworkEvent as a2, type SessionPortraitLink as a3, type SessionReviewDecidedEventData as a4, type SessionStatus as a5, type SessionStep as a6, type SessionStepCompletedEventData as a7, type SessionSubjectInput as a8, SessionsApi as a9, type Subject as aa, type SubjectAssurance as ab, type SubjectDeletedEventData as ac, type SubjectEnrolledEventData as ad, type SubjectReferenceSource as ae, type SubjectReuseDocument as af, type SubjectReuseTarget as ag, type SubjectSession as ah, type SubjectSessionInput as ai, type SubjectSessionTarget as aj, type SubjectStatus as ak, type SubjectSuspiciousActivityEventData as al, type SubjectUpdatedEventData as am, SubjectsApi as an, type VerifiedContacts as ao, type WebhookEnvelopeOf as ap, type WebhookEventDataMap as aq, type SuppliedIdentityRecord as b, type WebhookEnvelope as c, type SekyroEnvironment as d, type VerificationAssurance as e, type SessionOutcome as f, type VerificationUnit as g, type SubjectReuseMode as h, type ResultCheckProofs as i, type ResultDuplicate as j, type CameraUnavailableCause as k, type CheckState as l, type CheckType as m, type CreateSessionInput as n, DEFAULT_TIMEOUT_MS as o, type DecisionReason as p, type DeepPartial as q, type DeletedSubject as r, type DeliverOptions as s, type DocumentSubstitutionSettings as t, type EligibilityReason as u, type FlowOverridableSettings as v, type FlowOverrides as w, type FlowServiceSettings as x, type FlowSummary as y, type LevelTarget as z };
|