@sekyro/node 0.1.0-rc.2 → 0.1.0-rc.4

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/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Wire-level enums and shapes of the Sekyro partner API (`/api/v2`). These
2
+ * Wire-level enums and shapes of the Sekyro AI partner API (`/api/v2`). These
3
3
  * mirror the backend's frozen partner contract; they are plain string unions so
4
4
  * a newer API value never throws at runtime — it simply widens the type in the
5
5
  * next SDK release.
@@ -14,10 +14,81 @@ type SessionStatus = "created" | "in_progress" | "review_pending" | "completed"
14
14
  * @public
15
15
  */
16
16
  type SessionOutcome = "approved" | "review" | "rejected";
17
+ /**
18
+ * How the person proves their identity on an optional-document app: type the
19
+ * national number, or photograph the document (`document_chip`: native NFC clients only).
20
+ * `national_eid`: the country's national eID (e.g. Houwiyeti for Mauritania),
21
+ * offered when the app's profile turns the national eID on.
22
+ * @public
23
+ */
24
+ type IdentityMethod = "national_number" | "document_photo" | "document_chip" | "national_eid";
17
25
  /** The verification checks a flow may contain. @public */
18
- type CheckType = "liveness" | "face_match" | "doc_ocr" | "population_registry" | "phone_otp";
26
+ type CheckType = "liveness" | "face_match" | "doc_ocr" | "population_registry" | "phone_otp" | "nfc_chip" | "email_otp" | "portrait_icao" | "eid_auth";
19
27
  /** Per-check execution state within a session. @public */
20
28
  type CheckState = "pending" | "input_required" | "processing" | "passed" | "failed" | "review" | "skipped";
29
+ /**
30
+ * Why a session was stopped by a profile-v2 policy gate rather than by a
31
+ * failed check:
32
+ * - `location_not_allowed` — the end user's IP location is not allowed for the app;
33
+ * - `anonymizer_blocked` — an anonymizer (VPN / proxy / Tor) was detected while the app blocks them;
34
+ * - `capture_tampered` — the device reported a tampered capture (virtual
35
+ * camera, hooking, emulator…) while the app's `device.tamper` is `block`;
36
+ * - `device_velocity_exceeded` — the device already verified more different
37
+ * people than `device.velocity` allows, with `action: 'block'`;
38
+ * - `device_cooldown` — the device had too many rejected sessions
39
+ * (`cooldown` tiers); {@link Session.retryAfter} says when it may try again.
40
+ * Not billed.
41
+ * @public
42
+ */
43
+ type SessionFailureReason = "location_not_allowed" | "anonymizer_blocked" | "capture_tampered" | "device_velocity_exceeded" | "device_cooldown";
44
+ /**
45
+ * Profile-v2 decision-mode reasons a check's {@link SessionStep.reason} may
46
+ * carry when the app decides automatically (`decisions.mode: 'automatic'`)
47
+ * instead of routing to human review. All are retryable within the step's
48
+ * attempts: `liveness_inconclusive` (liveness middle band),
49
+ * `match_inconclusive` (face match middle band on every reference),
50
+ * `document_authenticity` (doc_ocr authenticity warning — retake the original)
51
+ * and `mobile_required` (liveness captured on a desktop — continue on a phone;
52
+ * not billed). Every inconclusive attempt is billed.
53
+ * @public
54
+ */
55
+ type DecisionReason = "liveness_inconclusive" | "match_inconclusive" | "document_authenticity" | "mobile_required";
56
+ /**
57
+ * Profile-v2 eligibility reasons a check's {@link SessionStep.reason} may carry:
58
+ * `document_type_not_accepted` (doc_ocr; the person may pick another
59
+ * document), `nationality_not_allowed` and `underage` (doc_ocr or
60
+ * population_registry; terminal), and `age_unverifiable` (the app sets a
61
+ * minimum age but the birth date could not be read — doc_ocr: retryable with
62
+ * a clearer photo; population_registry: terminal).
63
+ * @public
64
+ */
65
+ type EligibilityReason = "document_type_not_accepted" | "nationality_not_allowed" | "underage" | "age_unverifiable";
66
+ /**
67
+ * Why a profile-v2 policy ended a session: a session-level
68
+ * {@link SessionFailureReason} (location / anonymizer gate), or the failed
69
+ * check's policy reason — an {@link EligibilityReason} or
70
+ * `document_nni_mismatch` (the document belongs to someone other than the
71
+ * NNI the session was created for).
72
+ * @public
73
+ */
74
+ type PolicyFailureReason = SessionFailureReason | EligibilityReason | "document_nni_mismatch";
75
+ /**
76
+ * Profile-v2 matching reasons a check's {@link SessionStep.reason} may carry
77
+ * when the data you sent in {@link CreateSessionInput.subject} differs from the
78
+ * reference identity: `name_mismatch`, `birth_date_mismatch`,
79
+ * `nationality_mismatch` (doc_ocr or population_registry) and
80
+ * `document_number_mismatch` (doc_ocr). All are final.
81
+ * @public
82
+ */
83
+ type MatchReason = "name_mismatch" | "birth_date_mismatch" | "nationality_mismatch" | "document_number_mismatch";
84
+ /**
85
+ * Face-match probe-binding reason a `face_match` {@link SessionStep.reason} may
86
+ * carry (SDK spec §4.10): `probe_not_from_liveness` — the face image isn't the
87
+ * person in the liveness clip. Retryable within the step's attempts (the
88
+ * person re-takes the liveness capture); billed.
89
+ * @public
90
+ */
91
+ type ProbeBindingReason = "probe_not_from_liveness";
21
92
  /** Hosted-flow languages. @public */
22
93
  type Locale = "ar" | "fr" | "en";
23
94
  /** The environment a webhook was emitted from. @public */
@@ -34,9 +105,62 @@ interface SessionStep {
34
105
  reason?: string;
35
106
  /** Calibrated model score in [0, 1] for scored checks (liveness, face match). */
36
107
  calibratedScore?: number;
108
+ /** The check failed after using all of its attempts. */
109
+ attemptsExhausted?: boolean;
110
+ /**
111
+ * `portrait_icao` only (ID mode): the per-criterion ICAO report of the last
112
+ * attempt — numbers and enums only, never the image.
113
+ */
114
+ report?: PortraitReportEntry[];
115
+ /**
116
+ * `face_match` only: the probe-quality measurement of the selfie that was
117
+ * matched (occlusion, head pose, eye openness, sharpness). Recorded for
118
+ * information only: it never changes the step's state or reason.
119
+ */
120
+ probeQuality?: ProbeQuality;
37
121
  }
38
122
  /**
39
- * Out-of-band delivery of the session's hosted link, sent by Sekyro after the
123
+ * The probe-quality measurement on a `face_match` step. Numbers only; `null`
124
+ * means the value could not be measured. Informational: no threshold applies.
125
+ * @public
126
+ */
127
+ interface ProbeQuality {
128
+ /** Share of the inner face that is covered (a hand, a mask, a phone), in [0, 1]. */
129
+ occlusion: number | null;
130
+ /** Head pose in degrees. */
131
+ pose: {
132
+ yaw: number | null;
133
+ pitch: number | null;
134
+ roll: number | null;
135
+ };
136
+ /** Openness of the less-open eye, in [0, 1]. */
137
+ eyesOpen: number | null;
138
+ /** Sharpness of the face region (higher is sharper; no fixed scale). */
139
+ sharpness: number | null;
140
+ }
141
+ /**
142
+ * One row of the `portrait_icao` report (ID mode): the server's measurement of
143
+ * one ICAO criterion and the threshold that applied.
144
+ * @public
145
+ */
146
+ interface PortraitReportEntry {
147
+ criterion: "pose" | "eyes" | "mouth" | "occlusion" | "glare" | "lighting" | "background" | "resolution";
148
+ value: number | null;
149
+ threshold: number | string | null;
150
+ pass: boolean;
151
+ }
152
+ /**
153
+ * A short-lived link to a session's ICAO portrait (480×640 JPEG), from
154
+ * {@link SessionsApi.portrait}. Download it before `expiresAt`; never store the URL.
155
+ * @public
156
+ */
157
+ interface SessionPortraitLink {
158
+ url: string;
159
+ /** ISO 8601 (about 5 minutes after the call). */
160
+ expiresAt: string;
161
+ }
162
+ /**
163
+ * Out-of-band delivery of the session's hosted link, sent by Sekyro AI after the
40
164
  * session is created. Best effort: a failed send never fails the create.
41
165
  * @public
42
166
  */
@@ -46,6 +170,225 @@ interface DeliverOptions {
46
170
  /** E.164 phone number of the recipient, e.g. `+22236123456`. */
47
171
  to: string;
48
172
  }
173
+ /**
174
+ * What you already know about the person (`subject` at session create). A
175
+ * closed object: unknown keys are refused (`400`). Every field is optional;
176
+ * `null` or blank counts as absent. Identity fields are compared with the
177
+ * person's document or registry record when the app's profile turns name
178
+ * matching on; `nni` binds the session to that identity.
179
+ * @public
180
+ */
181
+ interface SessionSubjectInput {
182
+ /** 10-digit Mauritanian NNI, as a string. */
183
+ nni?: string;
184
+ /** E.164 phone number, e.g. `+22236123456`. */
185
+ phone?: string;
186
+ fullName?: string;
187
+ /** ISO 8601 date (`YYYY-MM-DD`). */
188
+ birthDate?: string;
189
+ /** ISO 3166-1 alpha-2, e.g. `MR`. */
190
+ nationality?: string;
191
+ /** Identity-document number (1–40 characters). */
192
+ documentNumber?: string;
193
+ /**
194
+ * Your own id for this person (1–128 characters). Echoed on the session and
195
+ * its webhooks, and searchable on the subjects API.
196
+ */
197
+ externalRef?: string;
198
+ /**
199
+ * Returning user (profile v2 step 5): verify this already-verified subject
200
+ * again with liveness + face match only, against the reference photo stored
201
+ * on the subject. Name exactly one target. Errors at create:
202
+ * `404 subject_not_found`, `409 subject_revoked`, `409 subject_no_reference`,
203
+ * `409 subject_stale` (older than the app's `reuse.maxAgeMonths`) and
204
+ * `400` / `409 reuse_target_ambiguous`.
205
+ */
206
+ reuse?: SubjectReuseTarget;
207
+ }
208
+ /**
209
+ * Which subject a returning-user session re-verifies — exactly ONE of the
210
+ * subject id, your own `externalRef` (must match a single subject) or the NNI.
211
+ * @public
212
+ */
213
+ type SubjectReuseTarget = {
214
+ subjectId: string;
215
+ externalRef?: never;
216
+ nni?: never;
217
+ } | {
218
+ externalRef: string;
219
+ subjectId?: never;
220
+ nni?: never;
221
+ } | {
222
+ nni: string;
223
+ subjectId?: never;
224
+ externalRef?: never;
225
+ };
226
+ /** A document type the backend reads (kyc-docs-v2 vocabulary; `carte_identite` = identity card of any issuer). @public */
227
+ type ProfileDocumentType = "carte_identite" | "passport" | "residence_permit";
228
+ /**
229
+ * The settings of an app's eKYC profile that a session may override — a
230
+ * mirror of the backend profile (schema version 2) without `schemaVersion`,
231
+ * `link` (use {@link CreateSessionInput.ttlMinutes}) and `overrides` (the
232
+ * app's own permission). Country codes are ISO 3166-1 alpha-2 (`MR`).
233
+ * Used through {@link EkycProfileOverride}.
234
+ * @public
235
+ */
236
+ interface EkycProfileSettings {
237
+ /**
238
+ * Phone OTP step: off, or on with where the number comes from. The person
239
+ * chooses WhatsApp or SMS from the channels left after the org's settings
240
+ * and `channels`.
241
+ */
242
+ phone: "off" | {
243
+ /** Where the number comes from: your `subject.phone` / `input.phone`, the person, or either. */
244
+ numberSource: "prefilled" | "user_entered" | "prefilled_or_entered";
245
+ /**
246
+ * Narrow the channels the person may choose from (absent = every
247
+ * channel the org has on). A channel the org turned off answers
248
+ * `400 phone_channels_disabled_for_org`; an empty or duplicated list
249
+ * `400 phone_channels_invalid`.
250
+ */
251
+ channels?: Array<"whatsapp" | "sms">;
252
+ /**
253
+ * Which countries codes may be sent to: the profile's allowed
254
+ * `locations` (default), `any`, or a list of ISO 3166-1 alpha-2 codes.
255
+ * Invalid values answer `400 phone_destinations_invalid`.
256
+ */
257
+ destinations?: "locations" | "any" | {
258
+ countries: string[];
259
+ };
260
+ };
261
+ /** Email OTP step (absent = off): a one-time code sent to the person's email address. */
262
+ email?: "off" | ProfileEmail;
263
+ document: {
264
+ mode: "off" | "optional" | "mandatory";
265
+ /** Accepted document types: `'*'` (all) or a list, optionally per issuing country. */
266
+ accepted: {
267
+ default: "*" | ProfileDocumentType[];
268
+ byIssuer?: Record<string, ProfileDocumentType[]>;
269
+ };
270
+ /** Expired documents: refused, allowed, or allowed for `graceDays` (1–365) after expiry. */
271
+ expired: "reject" | "allow" | {
272
+ graceDays: number;
273
+ };
274
+ authenticity: "standard" | "off";
275
+ };
276
+ registry: {
277
+ enabled: boolean;
278
+ sources: Array<"MR.anrpts">;
279
+ /** Which identity is the reference for face match and your data. */
280
+ reference?: "document" | "registry";
281
+ /** What happens when the registry has no record for the NNI. */
282
+ onNoRecord?: "fail" | "use_document";
283
+ };
284
+ liveness: {
285
+ enabled: boolean;
286
+ };
287
+ faceMatch: {
288
+ enabled: boolean;
289
+ };
290
+ /** Comparison of your `subject` data with the reference identity. */
291
+ nameMatch?: {
292
+ level: "strict" | "standard" | "lenient";
293
+ onMismatch: "fail" | "signal";
294
+ };
295
+ /** Per-step attempt limits. */
296
+ attempts?: {
297
+ phone: number;
298
+ /** Email OTP attempts (1–5); absent = the platform default. */
299
+ email?: number;
300
+ document: number;
301
+ registry: number;
302
+ liveness: number;
303
+ faceMatch: number;
304
+ };
305
+ /** Where the end user may be (IP location). */
306
+ locations: {
307
+ mode: "all";
308
+ } | {
309
+ mode: "only" | "all_except";
310
+ countries: string[];
311
+ };
312
+ anonymizers: "allow" | "block";
313
+ /** Accepted nationalities: `'*'` or a list, optionally per IP location. */
314
+ nationalities: {
315
+ default: "*" | string[];
316
+ byLocation?: Record<string, "*" | string[]>;
317
+ };
318
+ /** Minimum age in years (1–120), or `null` for none. */
319
+ minAge: number | null;
320
+ /** Automatic decisions instead of human review (`retryConfidentRejects` lets confident rejects retry). */
321
+ decisions?: {
322
+ mode: "automatic" | "review";
323
+ retryConfidentRejects: boolean;
324
+ };
325
+ /** Device cooldown after repeated rejections (at most 5 tiers; `[]` = off). */
326
+ cooldown?: {
327
+ tiers: Array<{
328
+ rejectedSessions: number;
329
+ windowHours: number;
330
+ waitMinutes: number;
331
+ }>;
332
+ };
333
+ /** Device tamper and velocity actions. */
334
+ device?: {
335
+ tamper: "block" | "signal";
336
+ velocity: {
337
+ maxIdentitiesPerDevice: number;
338
+ windowDays: number;
339
+ action: "signal" | "block";
340
+ };
341
+ };
342
+ /**
343
+ * The live photo. `purpose: "id_document"` also takes an ICAO 480×640 portrait you
344
+ * download for printing on an ID document. `icao` makes a verification selfie meet
345
+ * the ICAO photo rules: `"reject"` asks the person to retake a non-compliant photo
346
+ * (after the last attempt the session fails, or goes to review in review mode);
347
+ * `"alert"` lets the person continue and adds the risk signal `icao_non_compliant`.
348
+ * Both need liveness on; `"alert"` with `"id_document"` answers
349
+ * `400 portrait_icao_policy_id_document`. Absent = a verification selfie, no ICAO check.
350
+ */
351
+ portrait?: {
352
+ purpose?: "verification" | "id_document";
353
+ icao?: {
354
+ policy: "alert" | "reject";
355
+ };
356
+ };
357
+ }
358
+ /**
359
+ * The email OTP step of a profile. When the email check is not available on
360
+ * the platform yet, saving it answers `400 email_otp_not_available`.
361
+ * @public
362
+ */
363
+ interface ProfileEmail {
364
+ /** Where the address comes from: your `input.email`, the person, or either. */
365
+ emailSource: "prefilled" | "user_entered" | "prefilled_or_entered";
366
+ /** Disposable (temporary) addresses: allowed, flagged as a risk signal (default), or refused. */
367
+ disposable?: "allow" | "signal" | "block";
368
+ }
369
+ /**
370
+ * `T` with every property optional, recursively. Arrays are replaced as a
371
+ * whole, never merged element by element.
372
+ * @public
373
+ */
374
+ type DeepPartial<T> = T extends readonly unknown[] ? T : T extends object ? {
375
+ [K in keyof T]?: DeepPartial<T[K]>;
376
+ } : T;
377
+ /**
378
+ * A per-session override of the app's eKYC profile
379
+ * ({@link CreateSessionInput.profile}): any subset of
380
+ * {@link EkycProfileSettings}, at any depth (every field optional). Objects
381
+ * are merged into the app's profile; arrays and scalar values replace it.
382
+ *
383
+ * The API validates the merged result like a profile save. Unknown keys are
384
+ * rejected server-side (`400`, also for keys this SDK version does not type).
385
+ * An override may only make the profile stricter unless the app allows
386
+ * widening (`overrides.allowWidening`); otherwise a widening change answers
387
+ * `403 override_widens_profile`. The changed paths are reported on
388
+ * {@link Session.overriddenFields}.
389
+ * @public
390
+ */
391
+ type EkycProfileOverride = DeepPartial<EkycProfileSettings>;
49
392
  /**
50
393
  * Input of {@link SessionsApi.create}. There is no recipe field: the API key
51
394
  * belongs to an app, and that app's eKYC profile decides the steps.
@@ -54,6 +397,11 @@ interface DeliverOptions {
54
397
  interface CreateSessionInput {
55
398
  /** Pins the hosted-flow language. Omit to let the person's device decide. */
56
399
  locale?: Locale;
400
+ /**
401
+ * Pre-choose the identity method when the app's document step is optional
402
+ * (the hosted method screen is then skipped). Ignored for other apps.
403
+ */
404
+ identityMethod?: IdentityMethod;
57
405
  /**
58
406
  * Session lifetime in minutes. Must fall within the app profile's link
59
407
  * range, otherwise the API answers `400 ttl_out_of_policy`. Omit to use the
@@ -62,6 +410,19 @@ interface CreateSessionInput {
62
410
  ttlMinutes?: number;
63
411
  /** Also send the hosted link to the person by SMS or WhatsApp. */
64
412
  deliver?: DeliverOptions;
413
+ /**
414
+ * What you already know about the person (preferred over `input` for
415
+ * identity data). A key sent in both `subject` and `input` with different
416
+ * values answers `400 subject_input_conflict`.
417
+ */
418
+ subject?: SessionSubjectInput;
419
+ /**
420
+ * Override the app's eKYC profile for this session only (profile v2): a
421
+ * deep-partial {@link EkycProfileOverride}. Unknown keys are rejected
422
+ * server-side; a change that makes the profile less strict answers
423
+ * `403 override_widens_profile` unless the app allows widening.
424
+ */
425
+ profile?: EkycProfileOverride;
65
426
  /**
66
427
  * Step inputs consumed server-side. The known anchors are typed (all
67
428
  * strings — an `nni` is a 10-digit string, never a number); further keys
@@ -73,11 +434,59 @@ interface CreateSessionInput {
73
434
  nni?: string;
74
435
  /** E.164 phone number, e.g. `+22236123456`. */
75
436
  phone?: string;
437
+ /** Email address for the email OTP step (`emailSource` `prefilled` / `prefilled_or_entered`). */
438
+ email?: string;
76
439
  fullName?: string;
77
440
  /** ISO 8601 date (`YYYY-MM-DD`). */
78
441
  birthDate?: string;
442
+ /**
443
+ * Partner-supplied identity data (`supplied` mode only): the person's
444
+ * biographic record and photo as YOUR system holds them — for example
445
+ * from your own ANRPTS answer, converted with {@link registryFromAnrpts}.
446
+ * Sekyro AI stores it as data you vouch for, makes no registry call, and
447
+ * never receives or stores any registry key. `nni` must be set too and
448
+ * equal `suppliedIdentity.nni`. Refused unless Sekyro AI enabled the mode
449
+ * for the environment (`403 supplied_identity_not_entitled`); required in
450
+ * that mode when the app verifies identity (`422 supplied_identity_required`).
451
+ */
452
+ suppliedIdentity?: SuppliedIdentityRecord;
79
453
  } & Record<string, unknown>;
80
454
  }
455
+ /**
456
+ * Partner-supplied identity data (`sessions.create` `input.suppliedIdentity`):
457
+ * the person's biographic record and photo, as your organization holds them.
458
+ * Sekyro AI treats it as identity data supplied by your organization, not as
459
+ * a registry lookup. Refusals at create: `400 supplied_identity_nni_mismatch`,
460
+ * `422 supplied_identity_stale` (`fetchedAt` older than 24 h),
461
+ * `422 supplied_identity_photo_unusable` (not a JPEG/PNG of at most 1 MB within the
462
+ * size bounds). In a `supplied` environment whose app verifies identity, a create
463
+ * without `input.suppliedIdentity` is `422 supplied_identity_required`. The face on
464
+ * the photo is checked after consent, at the face match (`no_face_reference`).
465
+ * @public
466
+ */
467
+ interface SuppliedIdentityRecord {
468
+ /** 10-digit NNI, as a string. */
469
+ nni: string;
470
+ firstNameFr: string;
471
+ lastNameFr: string;
472
+ fatherNameFr?: string;
473
+ firstNameAr: string;
474
+ lastNameAr: string;
475
+ fatherNameAr?: string;
476
+ /** ISO 8601 date (`YYYY-MM-DD`). */
477
+ birthDate: string;
478
+ birthPlaceFr?: string;
479
+ birthPlaceAr?: string;
480
+ sex?: "M" | "F";
481
+ /** Nationality text as your source holds it (e.g. `Mauritanienne`). */
482
+ nationalities?: string[];
483
+ /** Base64 JPEG or PNG (at most 1 MB decoded). */
484
+ photo: string;
485
+ /** ISO 8601 date (`YYYY-MM-DD`) of the registry photo. */
486
+ photoDate?: string;
487
+ /** ISO 8601 date-time at which your system obtained this record. */
488
+ fetchedAt: string;
489
+ }
81
490
  /** Per-request options. @public */
82
491
  interface RequestOptions {
83
492
  /**
@@ -102,6 +511,100 @@ interface CreatedSession {
102
511
  /** ISO 8601 — when the session (and its link) stop accepting input. */
103
512
  expiresAt: string;
104
513
  }
514
+ /**
515
+ * The end user's network at the start of the session (IP-derived, approximate).
516
+ * @public
517
+ */
518
+ interface SessionNetworkEvent {
519
+ /** ISO 8601. */
520
+ at: string;
521
+ /** ISO 3166-1 alpha-2. */
522
+ country?: string;
523
+ region?: string;
524
+ city?: string;
525
+ asn?: number;
526
+ operator?: string;
527
+ connectionType: "mobile" | "hosting" | "unknown";
528
+ anonymizer: {
529
+ vpn: boolean;
530
+ tor: boolean;
531
+ hosting: boolean;
532
+ };
533
+ /** IANA time zone reported by the end user's device. */
534
+ browserTimezone?: string;
535
+ /** True when the device time zone does not belong to the IP country. */
536
+ timezoneMismatch?: boolean;
537
+ }
538
+ /**
539
+ * End-user network context; absent when not recorded.
540
+ * @public
541
+ */
542
+ interface SessionNetwork {
543
+ /** The start event's IP address. Never sent in webhooks. */
544
+ ip?: string;
545
+ /** True when a later call came from a different country than the start. */
546
+ countryChanged: boolean;
547
+ start: SessionNetworkEvent;
548
+ }
549
+ /**
550
+ * Device signals detected on the end user's device.
551
+ * @public
552
+ */
553
+ type SessionDeviceSignal = "webdriver" | "headless" | "emulator" | "rooted" | "jailbroken" | "debugger" | "hooking" | "virtual_camera";
554
+ /**
555
+ * End-user device summary; absent when not recorded.
556
+ * @public
557
+ */
558
+ interface SessionDevice {
559
+ platform: "web" | "android" | "ios";
560
+ sdk?: string;
561
+ os?: string;
562
+ osVersion?: string;
563
+ browser?: string;
564
+ browserVersion?: string;
565
+ deviceClass: "mobile" | "tablet" | "desktop" | "unknown";
566
+ model?: string;
567
+ /** Device ids hashed with a key unique to your organization. */
568
+ deviceKeys: string[];
569
+ signals: SessionDeviceSignal[];
570
+ }
571
+ /**
572
+ * The national eID that verified the session's identity (the `eid_auth` check
573
+ * passed): the provider id (`{country}.{provider}`, e.g. `MR.houwiyeti`), its
574
+ * ISO 3166-1 alpha-2 country and when. A passed eID ends the session.
575
+ * @public
576
+ */
577
+ interface EidResult {
578
+ provider: string;
579
+ country: string;
580
+ verifiedAt: string;
581
+ }
582
+ /**
583
+ * The full phone number and email address the person verified in a session
584
+ * (an OTP check that passed) — sent ONLY to you (the session view and your
585
+ * webhooks), never to the person's browser, and removed when the session's
586
+ * personal data is purged. You are the controller of these values. A
587
+ * prefilled value that was not verified is never listed.
588
+ * @public
589
+ */
590
+ interface VerifiedContacts {
591
+ /** From a passed `phone_otp` check. */
592
+ phone?: {
593
+ /** E.164, e.g. `+22236123456`. */
594
+ number: string;
595
+ /** The channel the code was delivered on. */
596
+ channel: "whatsapp" | "sms";
597
+ /** ISO 8601. */
598
+ verifiedAt: string;
599
+ };
600
+ /** From a passed `email_otp` check. */
601
+ email?: {
602
+ /** The verified address (domain lowercased). */
603
+ address: string;
604
+ /** ISO 8601. */
605
+ verifiedAt: string;
606
+ };
607
+ }
105
608
  /**
106
609
  * The whitelisted session view returned by {@link SessionsApi.get}. Never
107
610
  * contains the client token.
@@ -116,6 +619,55 @@ interface Session {
116
619
  expiresAt: string;
117
620
  /** ISO 8601. */
118
621
  createdAt: string;
622
+ /** End-user network context; absent when not recorded. */
623
+ network?: SessionNetwork;
624
+ /** End-user device; absent when not recorded. */
625
+ device?: SessionDevice;
626
+ /**
627
+ * Set when a profile-v2 policy ended the session: a session-level gate
628
+ * (location, anonymizer) or a failed check's policy reason (eligibility,
629
+ * `document_nni_mismatch`). Absent otherwise.
630
+ */
631
+ failureReason?: PolicyFailureReason;
632
+ /** The subject (person) this session is linked to, once an identifier is known. */
633
+ subjectId?: string;
634
+ /** Your own id for the person, from `subject.externalRef` at create. */
635
+ externalRef?: string;
636
+ /**
637
+ * `true` when an identifier this session read already belongs to a
638
+ * different subject than `subjectId` — the subjects are never merged.
639
+ */
640
+ subjectConflict?: boolean;
641
+ /**
642
+ * ISO 8601 — when the end user's device may verify again; set with
643
+ * `failureReason: 'device_cooldown'`.
644
+ */
645
+ retryAfter?: string;
646
+ /** Dotted profile paths this session's {@link CreateSessionInput.profile} changed (e.g. `decisions.mode`). */
647
+ overriddenFields?: string[];
648
+ /**
649
+ * Risk signals recorded on the session (e.g. `device_velocity`,
650
+ * `timezone_mismatch`, `icao_non_compliant` when an `alert` ICAO policy flagged
651
+ * the selfie) — signals only, never a verdict by themselves.
652
+ */
653
+ riskSignals?: string[];
654
+ /**
655
+ * `true` for a returning-user session (created with
656
+ * {@link SessionSubjectInput.reuse}): liveness + face match against the
657
+ * subject's stored reference photo only.
658
+ */
659
+ returning?: true;
660
+ /** On a returning-user session: the subject (person) it re-verifies. */
661
+ reuseOf?: string;
662
+ /** The contacts verified in this session (passed OTP checks only); absent when none. */
663
+ verifiedContacts?: VerifiedContacts;
664
+ /** The national eID that verified this session (the `eid_auth` check passed); absent otherwise. */
665
+ eid?: EidResult;
666
+ /**
667
+ * ID mode (`portrait.purpose = id_document`) only: the ICAO portrait can be
668
+ * fetched with {@link SessionsApi.portrait}.
669
+ */
670
+ portraitAvailable?: boolean;
119
671
  }
120
672
  /**
121
673
  * `data` of the terminal / review-pending session lifecycle events
@@ -133,6 +685,169 @@ interface SessionLifecycleEventData {
133
685
  steps?: Array<Pick<SessionStep, "checkType" | "state">>;
134
686
  /** Machine-readable reason, when the transition has one. */
135
687
  reason?: string;
688
+ /** End-user network context (no IP); on `completed` / `failed` when recorded. */
689
+ network?: Omit<SessionNetwork, "ip">;
690
+ /** End-user device; on `completed` / `failed` when recorded. */
691
+ device?: SessionDevice;
692
+ /**
693
+ * On `session.failed`: set when a profile-v2 policy ended the session — a
694
+ * session-level gate (location, anonymizer) or a failed check's policy
695
+ * reason (eligibility, `document_nni_mismatch`).
696
+ */
697
+ failureReason?: PolicyFailureReason;
698
+ /** The subject (person) the session is linked to, when known. */
699
+ subjectId?: string;
700
+ /** Your own id for the person, from `subject.externalRef` at create. */
701
+ externalRef?: string;
702
+ /**
703
+ * `true` when an identifier this session read already belongs to a
704
+ * different subject than `subjectId` — the subjects are never merged.
705
+ */
706
+ subjectConflict?: boolean;
707
+ /** `true` on a returning-user session (liveness + face match against the stored photo). */
708
+ returning?: true;
709
+ /** On a returning-user session: the subject (person) it re-verifies. */
710
+ reuseOf?: string;
711
+ /**
712
+ * On `session.failed` with `failureReason: 'device_cooldown'`: ISO time
713
+ * from which the device may start a new verification.
714
+ */
715
+ retryAfter?: string;
716
+ /** Dotted profile paths the session's create-time override changed. */
717
+ overriddenFields?: string[];
718
+ /** On `completed` / `failed`: the contacts verified in this session (passed OTP checks only). */
719
+ verifiedContacts?: VerifiedContacts;
720
+ /** On `completed` / `failed`: the national eID that verified this session, when one did. */
721
+ eid?: EidResult;
722
+ /**
723
+ * ID mode only, on `completed` / `failed`: the ICAO portrait can be fetched
724
+ * with {@link SessionsApi.portrait} (the event never carries the image).
725
+ */
726
+ portraitAvailable?: boolean;
727
+ }
728
+ /**
729
+ * `data` of `subject.updated` — either a session linked to the subject reached
730
+ * a terminal state (`sessionId`, session `status`, `outcome`), or the subject
731
+ * was revoked (`status: 'revoked'`, no session). Ids and enums only.
732
+ * @public
733
+ */
734
+ interface SubjectUpdatedEventData {
735
+ subjectId: string;
736
+ /** The session that reached a terminal state; absent on a revocation. */
737
+ sessionId?: string;
738
+ status: SessionStatus | "revoked";
739
+ /** The session outcome; absent on a revocation. */
740
+ outcome?: SessionOutcome | null;
741
+ }
742
+ /**
743
+ * `data` of `subject.enrolled` — the subject's first reference photo was
744
+ * stored (it can now be used for returning-user sessions). Ids and enums only.
745
+ * @public
746
+ */
747
+ interface SubjectEnrolledEventData {
748
+ subjectId: string;
749
+ /** The approved session the reference photo came from. */
750
+ sessionId: string;
751
+ assurance: SubjectAssurance;
752
+ }
753
+ /**
754
+ * `data` of `subject.deleted`. A delete through the subjects API carries
755
+ * `subjectId`; a right-to-erasure request carries the tokenized `subjectRef`
756
+ * (with `orgId` / `env`) instead — never the national number.
757
+ * @public
758
+ */
759
+ interface SubjectDeletedEventData {
760
+ subjectId?: string;
761
+ subjectRef?: string;
762
+ orgId?: string;
763
+ env?: SekyroEnvironment;
764
+ }
765
+ /** Subject lifecycle: a revoked subject cannot be reused. @public */
766
+ type SubjectStatus = "active" | "revoked";
767
+ /**
768
+ * How strongly a subject's identity was established: the reference photo
769
+ * came from the national registry, the document's chip (`chip_biometric`, a
770
+ * passed chip read plus a face match) or the document, and a face match passed
771
+ * (`*_biometric`) or the session had no face match (`*_only`). `supplied_*`:
772
+ * partner-supplied identity data (`input.suppliedIdentity`), with
773
+ * (`supplied_biometric`) or without (`supplied_only`) a face match against its photo.
774
+ * @public
775
+ */
776
+ type SubjectAssurance = "registry_biometric" | "chip_biometric" | "document_biometric" | "registry_only" | "document_only" | "supplied_biometric" | "supplied_only";
777
+ /**
778
+ * Origin of a subject's stored reference photo, best first (`chip`: the document chip's portrait;
779
+ * `org_supplied`: the photo of your partner-supplied identity data).
780
+ * @public
781
+ */
782
+ type SubjectReferenceSource = "registry" | "doc_registry" | "chip" | "org_supplied" | "document";
783
+ /** One session linked to a subject. @public */
784
+ interface SubjectSession {
785
+ sessionId: string;
786
+ appId: string | null;
787
+ /** ISO 8601 — when the session was linked. */
788
+ at: string;
789
+ status: SessionStatus;
790
+ outcome: SessionOutcome | null;
791
+ }
792
+ /**
793
+ * A subject (the same person across your apps), as `GET /subjects/:id`
794
+ * returns it. Never contains photo keys or URLs.
795
+ * @public
796
+ */
797
+ interface Subject {
798
+ id: string;
799
+ status: SubjectStatus;
800
+ /** ISO 8601 — present only when revoked. */
801
+ revokedAt?: string;
802
+ sessions: SubjectSession[];
803
+ externalRefs: string[];
804
+ /** ISO 8601. */
805
+ firstSeenAt: string;
806
+ /** ISO 8601. */
807
+ lastSeenAt: string;
808
+ /** ISO 8601, or `null` before the first approved session. */
809
+ lastPassedAt: string | null;
810
+ /** ISO 8601 of the last approved full or returning session, or `null`. */
811
+ lastVerifiedAt: string | null;
812
+ /** The stored reference photo's origin and date — `null` until one is stored. */
813
+ reference: {
814
+ source: SubjectReferenceSource;
815
+ capturedAt: string;
816
+ } | null;
817
+ assurance: SubjectAssurance | null;
818
+ /**
819
+ * A returning-user session can be created now: active, a reference photo is
820
+ * stored, and the last FULL verification (returning-user sessions do not
821
+ * reset it) is within your app's
822
+ * `reuse.maxAgeMonths` (when set).
823
+ */
824
+ returningReady: boolean;
825
+ /** The verified name / birth date of the latest approved session. */
826
+ display?: {
827
+ name?: string;
828
+ birthDate?: string;
829
+ };
830
+ }
831
+ /** Result of {@link SubjectsApi.delete}. @public */
832
+ interface DeletedSubject {
833
+ id: string;
834
+ deleted: true;
835
+ }
836
+ /** Options of {@link SubjectsApi.revoke}. @public */
837
+ interface RevokeSubjectInput {
838
+ /** Kept on the audit trail only (≤ 500 characters). Do not put personal data here. */
839
+ reason?: string;
840
+ }
841
+ /**
842
+ * `data` of `subject.suspicious_activity` — a device already linked to
843
+ * ANOTHER subject was used for a session of this subject. `count` is the
844
+ * subject's running total of such events. Ids only.
845
+ * @public
846
+ */
847
+ interface SubjectSuspiciousActivityEventData {
848
+ subjectId: string;
849
+ sessionId: string;
850
+ count: number;
136
851
  }
137
852
  /**
138
853
  * `data` of `session.step.completed` — the check that just passed.
@@ -142,6 +857,21 @@ interface SessionStepCompletedEventData {
142
857
  sessionId: string;
143
858
  checkType: CheckType;
144
859
  state: CheckState;
860
+ /** The subject (person) the session is linked to, when known. */
861
+ subjectId?: string;
862
+ /** Your own id for the person, from `subject.externalRef` at create. */
863
+ externalRef?: string;
864
+ /**
865
+ * `true` when an identifier this session read already belongs to a
866
+ * different subject than `subjectId` — the subjects are never merged.
867
+ */
868
+ subjectConflict?: boolean;
869
+ /** `true` on a returning-user session (liveness + face match against the stored photo). */
870
+ returning?: true;
871
+ /** On a returning-user session: the subject (person) it re-verifies. */
872
+ reuseOf?: string;
873
+ /** When the passed check is `phone_otp` / `email_otp`: that one verified contact. */
874
+ verifiedContacts?: VerifiedContacts;
145
875
  }
146
876
  /**
147
877
  * `data` of `session.review_decided` — a human (or the review-timeout sweep)
@@ -154,6 +884,21 @@ interface SessionReviewDecidedEventData {
154
884
  sessionId: string;
155
885
  outcome: "pass" | "fail";
156
886
  reason: string;
887
+ /** The subject (person) the session is linked to, when known. */
888
+ subjectId?: string;
889
+ /** Your own id for the person, from `subject.externalRef` at create. */
890
+ externalRef?: string;
891
+ /**
892
+ * `true` when an identifier this session read already belongs to a
893
+ * different subject than `subjectId` — the subjects are never merged.
894
+ */
895
+ subjectConflict?: boolean;
896
+ /** `true` on a returning-user session (liveness + face match against the stored photo). */
897
+ returning?: true;
898
+ /** On a returning-user session: the subject (person) it re-verifies. */
899
+ reuseOf?: string;
900
+ /** ID mode only: the ICAO portrait can be fetched with {@link SessionsApi.portrait}. */
901
+ portraitAvailable?: boolean;
157
902
  }
158
903
  /**
159
904
  * Event type → the shape of its `data`. Session events are typed; the
@@ -170,8 +915,10 @@ interface WebhookEventDataMap {
170
915
  "session.rejected": SessionLifecycleEventData;
171
916
  "session.expired": SessionLifecycleEventData;
172
917
  "session.failed": SessionLifecycleEventData;
173
- "subject.enrolled": Record<string, unknown>;
174
- "subject.deleted": Record<string, unknown>;
918
+ "subject.enrolled": SubjectEnrolledEventData;
919
+ "subject.updated": SubjectUpdatedEventData;
920
+ "subject.suspicious_activity": SubjectSuspiciousActivityEventData;
921
+ "subject.deleted": SubjectDeletedEventData;
175
922
  "aml.match_flagged": Record<string, unknown>;
176
923
  "payment.received": Record<string, unknown>;
177
924
  "invoice.generated": Record<string, unknown>;
@@ -259,18 +1006,66 @@ declare class SessionsApi {
259
1006
  * surface on purpose (only its bound `call` crosses this boundary).
260
1007
  * @internal
261
1008
  */
262
- constructor(call: <T>(method: "GET" | "POST", path: string, body?: unknown, idempotencyKey?: string) => Promise<T>);
1009
+ constructor(call: <T>(method: "GET" | "POST" | "DELETE", path: string, body?: unknown, idempotencyKey?: string) => Promise<T>);
263
1010
  /**
264
1011
  * `POST /sessions`. Returns the one-time `clientToken` — hand it to the
265
1012
  * browser, never persist it. Pass an `idempotencyKey` so a retried call
266
1013
  * cannot create a second session.
267
1014
  */
268
1015
  create(input?: CreateSessionInput, opts?: RequestOptions): Promise<CreatedSession>;
1016
+ /**
1017
+ * `POST /sessions/:id/method` — choose the identity method of an
1018
+ * optional-document session on the person's behalf (the hosted method
1019
+ * screen is then skipped). `409 method_locked` once the choice can no
1020
+ * longer change; `409 session_not_active` on a finished or expired session.
1021
+ */
1022
+ selectMethod(id: string, method: IdentityMethod): Promise<Session>;
269
1023
  /** `GET /sessions/:id` — the whitelisted view (no client token). */
270
1024
  get(id: string): Promise<Session>;
1025
+ /**
1026
+ * `GET /sessions/:id/portrait?format=url` — ID mode: a 5-minute presigned
1027
+ * link to the 480×640 ICAO portrait (JPEG). Needs the `portrait:read` scope
1028
+ * (keys minted from the dashboard carry it). `404 portrait_not_available`
1029
+ * until the session's `portrait_icao` check has passed (`portraitAvailable`).
1030
+ */
1031
+ portrait(id: string): Promise<SessionPortraitLink>;
271
1032
  }
272
1033
  /**
273
- * Sekyro partner API client. Server-side only: it carries your API key.
1034
+ * `sekyro.subjects` — read and manage subjects (the same person across your
1035
+ * apps). Reads need the `subjects:read` scope, `revoke` / `delete` the
1036
+ * `subjects:write` scope (keys minted from the dashboard carry both; an older
1037
+ * key answers `403 insufficient_scope`). A foreign or unknown id answers
1038
+ * `404 subject_not_found`.
1039
+ *
1040
+ * Type-only export, like {@link SessionsApi}: obtained through
1041
+ * {@link Sekyro.subjects}.
1042
+ * @public
1043
+ */
1044
+ declare class SubjectsApi {
1045
+ private readonly call;
1046
+ /** @internal */
1047
+ constructor(call: <T>(method: "GET" | "POST" | "DELETE", path: string, body?: unknown, idempotencyKey?: string) => Promise<T>);
1048
+ /** `GET /subjects/:id` — the subject, its sessions and its returning-user readiness. */
1049
+ get(id: string): Promise<Subject>;
1050
+ /** `GET /subjects?externalRef=…` — the subjects carrying your own id (newest first, at most 50). */
1051
+ list(query: {
1052
+ externalRef: string;
1053
+ }): Promise<Subject[]>;
1054
+ /**
1055
+ * `POST /subjects/:id/revoke` — the subject can no longer be used for
1056
+ * returning-user sessions. Idempotent: revoking again returns the same view.
1057
+ * Emits `subject.updated` with `status: 'revoked'`.
1058
+ */
1059
+ revoke(id: string, input?: RevokeSubjectInput, opts?: RequestOptions): Promise<Subject>;
1060
+ /**
1061
+ * `DELETE /subjects/:id` — deletes the subject's stored photos, face
1062
+ * templates and identifiers, and unlinks its sessions. Emits
1063
+ * `subject.deleted`. Cannot be undone; a second call answers `404`.
1064
+ */
1065
+ delete(id: string): Promise<DeletedSubject>;
1066
+ }
1067
+ /**
1068
+ * Sekyro AI partner API client. Server-side only: it carries your API key.
274
1069
  *
275
1070
  * Throws {@link SekyroConfigError} synchronously when `apiKey` is missing or
276
1071
  * `baseUrl` is not `https:` (plain `http:` is accepted for `localhost`,
@@ -285,6 +1080,7 @@ declare class SessionsApi {
285
1080
  */
286
1081
  declare class Sekyro {
287
1082
  readonly sessions: SessionsApi;
1083
+ readonly subjects: SubjectsApi;
288
1084
  constructor(opts: SekyroOptions);
289
1085
  }
290
1086
 
@@ -292,7 +1088,7 @@ declare class Sekyro {
292
1088
  type SekyroWebhookErrorCode = "invalid_signature" | "stale" | "malformed";
293
1089
  /**
294
1090
  * Thrown by {@link verifyWebhook}. Respond with a 4xx and do not process the
295
- * body; Sekyro retries deliveries that do not receive a 2xx.
1091
+ * body; Sekyro AI retries deliveries that do not receive a 2xx.
296
1092
  * @public
297
1093
  */
298
1094
  declare class SekyroWebhookError extends Error {
@@ -301,7 +1097,7 @@ declare class SekyroWebhookError extends Error {
301
1097
  constructor(code: SekyroWebhookErrorCode, message?: string);
302
1098
  }
303
1099
  /** Why the {@link Sekyro} constructor rejected its options. @public */
304
- type SekyroConfigErrorCode = "missing_api_key" | "invalid_base_url";
1100
+ type SekyroConfigErrorCode = "missing_api_key" | "invalid_base_url" | "invalid_registry_record";
305
1101
  /**
306
1102
  * Thrown synchronously by `new Sekyro(...)` for an unusable configuration —
307
1103
  * before any request is made. Extends `TypeError` so existing
@@ -345,6 +1141,61 @@ declare class SekyroApiError extends Error {
345
1141
  constructor(init: SekyroApiErrorInit);
346
1142
  }
347
1143
 
1144
+ /**
1145
+ * The raw ANRPTS `getPersonne` answer your server received with your own
1146
+ * access: `{ personne, photo }`, where `photo` is a base64 JPEG (optionally
1147
+ * data-URL prefixed). Only the fields the mapping reads are typed.
1148
+ * @public
1149
+ */
1150
+ interface AnrptsPersonneResponse {
1151
+ personne?: {
1152
+ nni?: string | undefined;
1153
+ prenomFr?: string | undefined;
1154
+ patronymeFr?: string | undefined;
1155
+ perePrenomFr?: string | undefined;
1156
+ prenomAr?: string | undefined;
1157
+ patronymeAr?: string | undefined;
1158
+ perePrenomAr?: string | undefined;
1159
+ /** ISO date or date-time (`1990-01-01T00:00:00.000Z`), or `DD/MM/YYYY`. */
1160
+ dateNaissance?: string | undefined;
1161
+ lieuNaissanceFr?: string | undefined;
1162
+ lieuNaissanceAr?: string | undefined;
1163
+ sexeCode?: string | undefined;
1164
+ nationalities?: string[] | undefined;
1165
+ [key: string]: unknown;
1166
+ };
1167
+ photo?: string | undefined;
1168
+ datePhoto?: string | undefined;
1169
+ [key: string]: unknown;
1170
+ }
1171
+ /** Options of {@link registryFromAnrpts}. @public */
1172
+ interface RegistryFromAnrptsOptions {
1173
+ /**
1174
+ * When YOUR system received this ANRPTS answer (not "now" when you map a cached
1175
+ * answer). Required: records older than 24 h are refused at session create.
1176
+ */
1177
+ fetchedAt: Date | string;
1178
+ }
1179
+ /**
1180
+ * Convert an ANRPTS `getPersonne` answer that YOUR server already received,
1181
+ * with your own access, into the `input.suppliedIdentity` record of
1182
+ * `sessions.create` (partner-supplied identity data). A pure, local mapping:
1183
+ * it makes no network call, and Sekyro AI never sees, receives or stores any
1184
+ * ANRPTS key — only the record and photo you pass.
1185
+ *
1186
+ * ```ts
1187
+ * const anrpts = await myAnrptsClient.getPersonne(nni); // your call, your key
1188
+ * const suppliedIdentity = registryFromAnrpts(anrpts, { fetchedAt: receivedAt });
1189
+ * await sekyro.sessions.create({ input: { nni, suppliedIdentity } });
1190
+ * ```
1191
+ *
1192
+ * Throws {@link SekyroConfigError} (`invalid_registry_record`) when a required
1193
+ * field (NNI, French and Arabic first and last names, birth date, photo) is
1194
+ * missing. The message names the field, never its value.
1195
+ * @public
1196
+ */
1197
+ declare function registryFromAnrpts(response: AnrptsPersonneResponse, options: RegistryFromAnrptsOptions): SuppliedIdentityRecord;
1198
+
348
1199
  /**
349
1200
  * The HTTP header carrying the webhook signature:
350
1201
  * `t=<unix seconds>,v1=<hex>[,v1=<hex>]`.
@@ -352,7 +1203,7 @@ declare class SekyroApiError extends Error {
352
1203
  */
353
1204
  declare const SEKYRO_SIGNATURE_HEADER = "x-sekyro-signature";
354
1205
  /**
355
- * The pre-rebrand name of the signature header. Sekyro sends BOTH headers with
1206
+ * The pre-rebrand name of the signature header. Sekyro AI sends BOTH headers with
356
1207
  * the same value during the transition; prefer {@link SEKYRO_SIGNATURE_HEADER}
357
1208
  * and use {@link signatureFromHeaders} to accept either.
358
1209
  * @public
@@ -380,13 +1231,13 @@ interface VerifyWebhookOptions {
380
1231
  now?: () => number;
381
1232
  }
382
1233
  /**
383
- * Verify a Sekyro webhook delivery and return its parsed envelope, discriminated
1234
+ * Verify a Sekyro AI webhook delivery and return its parsed envelope, discriminated
384
1235
  * on `event` (narrow with a `switch` to type `data`).
385
1236
  *
386
1237
  * - `rawBody` MUST be the request body exactly as received (before any JSON
387
1238
  * parsing / re-serialisation); the signature covers those bytes.
388
1239
  * - Accepts the delivery when ANY `v1` in the header matches, which is what
389
- * makes secret rotation seamless (Sekyro signs with current + previous).
1240
+ * makes secret rotation seamless (Sekyro AI signs with current + previous).
390
1241
  * - Uses `node:crypto` only; the digest compare is constant-time.
391
1242
  *
392
1243
  * Checks run in this order: header/secret present → header well-formed →
@@ -401,4 +1252,4 @@ interface VerifyWebhookOptions {
401
1252
  */
402
1253
  declare function verifyWebhook(rawBody: string, header: string | null | undefined, secret: string, opts?: VerifyWebhookOptions): WebhookEnvelope;
403
1254
 
404
- export { type CheckState, type CheckType, type CreateSessionInput, type CreatedSession, DEFAULT_BASE_URL, DEFAULT_TIMEOUT_MS, type DeliverOptions, type FetchLike, LEGACY_SIGNATURE_HEADER, type Locale, type RequestOptions, SEKYRO_SIGNATURE_HEADER, Sekyro, SekyroApiError, type SekyroApiErrorInit, type SekyroClientErrorCode, SekyroConfigError, type SekyroConfigErrorCode, type SekyroEnvironment, type SekyroOptions, SekyroWebhookError, type SekyroWebhookErrorCode, type Session, type SessionEventData, type SessionLifecycleEventData, type SessionOutcome, type SessionReviewDecidedEventData, type SessionStatus, type SessionStep, type SessionStepCompletedEventData, SessionsApi, type VerifyWebhookOptions, type WebhookEnvelope, type WebhookEnvelopeOf, type WebhookEventDataMap, type WebhookEventType, signatureFromHeaders, verifyWebhook };
1255
+ export { type AnrptsPersonneResponse, type CheckState, type CheckType, type CreateSessionInput, type CreatedSession, DEFAULT_BASE_URL, DEFAULT_TIMEOUT_MS, type DecisionReason, type DeepPartial, type DeletedSubject, type DeliverOptions, type EidResult, type EkycProfileOverride, type EkycProfileSettings, type EligibilityReason, type FetchLike, type IdentityMethod, LEGACY_SIGNATURE_HEADER, type Locale, type MatchReason, type PolicyFailureReason, type PortraitReportEntry, type ProbeBindingReason, type ProbeQuality, type ProfileDocumentType, type ProfileEmail, type RegistryFromAnrptsOptions, type RequestOptions, type RevokeSubjectInput, SEKYRO_SIGNATURE_HEADER, Sekyro, SekyroApiError, type SekyroApiErrorInit, type SekyroClientErrorCode, SekyroConfigError, type SekyroConfigErrorCode, type SekyroEnvironment, type SekyroOptions, SekyroWebhookError, type SekyroWebhookErrorCode, type Session, type SessionDevice, type SessionDeviceSignal, type SessionEventData, type SessionFailureReason, type SessionLifecycleEventData, type SessionNetwork, type SessionNetworkEvent, type SessionOutcome, type SessionPortraitLink, type SessionReviewDecidedEventData, type SessionStatus, type SessionStep, type SessionStepCompletedEventData, type SessionSubjectInput, SessionsApi, type Subject, type SubjectAssurance, type SubjectDeletedEventData, type SubjectEnrolledEventData, type SubjectReferenceSource, type SubjectReuseTarget, type SubjectSession, type SubjectStatus, type SubjectSuspiciousActivityEventData, type SubjectUpdatedEventData, SubjectsApi, type SuppliedIdentityRecord, type VerifiedContacts, type VerifyWebhookOptions, type WebhookEnvelope, type WebhookEnvelopeOf, type WebhookEventDataMap, type WebhookEventType, registryFromAnrpts, signatureFromHeaders, verifyWebhook };