@sekyro/node 0.1.0-rc.1 → 0.1.0-rc.3
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 +22 -0
- package/LICENSE +3 -3
- package/README.md +17 -9
- package/dist/index.cjs +1 -308
- package/dist/index.d.cts +416 -15
- package/dist/index.d.ts +416 -15
- package/dist/index.js +1 -272
- package/package.json +6 -9
- package/sbom.cdx.json +153 -0
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
package/dist/index.d.cts
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,71 @@ 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.
|
|
20
|
+
* @public
|
|
21
|
+
*/
|
|
22
|
+
type IdentityMethod = "national_number" | "document_photo";
|
|
17
23
|
/** The verification checks a flow may contain. @public */
|
|
18
24
|
type CheckType = "liveness" | "face_match" | "doc_ocr" | "population_registry" | "phone_otp";
|
|
19
25
|
/** Per-check execution state within a session. @public */
|
|
20
26
|
type CheckState = "pending" | "input_required" | "processing" | "passed" | "failed" | "review" | "skipped";
|
|
27
|
+
/**
|
|
28
|
+
* Why a session was stopped by a profile-v2 policy gate rather than by a
|
|
29
|
+
* failed check:
|
|
30
|
+
* - `location_not_allowed` — the end user's IP location is not allowed for the app;
|
|
31
|
+
* - `anonymizer_blocked` — an anonymizer (VPN / proxy / Tor) was detected while the app blocks them;
|
|
32
|
+
* - `capture_tampered` — the device reported a tampered capture (virtual
|
|
33
|
+
* camera, hooking, emulator…) while the app's `device.tamper` is `block`;
|
|
34
|
+
* - `device_velocity_exceeded` — the device already verified more different
|
|
35
|
+
* people than `device.velocity` allows, with `action: 'block'`;
|
|
36
|
+
* - `device_cooldown` — the device had too many rejected sessions
|
|
37
|
+
* (`cooldown` tiers); {@link Session.retryAfter} says when it may try again.
|
|
38
|
+
* Not billed.
|
|
39
|
+
* @public
|
|
40
|
+
*/
|
|
41
|
+
type SessionFailureReason = "location_not_allowed" | "anonymizer_blocked" | "capture_tampered" | "device_velocity_exceeded" | "device_cooldown";
|
|
42
|
+
/**
|
|
43
|
+
* Profile-v2 decision-mode reasons a check's {@link SessionStep.reason} may
|
|
44
|
+
* carry when the app decides automatically (`decisions.mode: 'automatic'`)
|
|
45
|
+
* instead of routing to human review. All are retryable within the step's
|
|
46
|
+
* attempts: `liveness_inconclusive` (liveness middle band),
|
|
47
|
+
* `match_inconclusive` (face match middle band on every reference),
|
|
48
|
+
* `document_authenticity` (doc_ocr authenticity warning — retake the original)
|
|
49
|
+
* and `mobile_required` (liveness captured on a desktop — continue on a phone;
|
|
50
|
+
* not billed). Every inconclusive attempt is billed.
|
|
51
|
+
* @public
|
|
52
|
+
*/
|
|
53
|
+
type DecisionReason = "liveness_inconclusive" | "match_inconclusive" | "document_authenticity" | "mobile_required";
|
|
54
|
+
/**
|
|
55
|
+
* Profile-v2 eligibility reasons a check's {@link SessionStep.reason} may carry:
|
|
56
|
+
* `document_type_not_accepted` (doc_ocr; the person may pick another
|
|
57
|
+
* document), `nationality_not_allowed` and `underage` (doc_ocr or
|
|
58
|
+
* population_registry; terminal), and `age_unverifiable` (the app sets a
|
|
59
|
+
* minimum age but the birth date could not be read — doc_ocr: retryable with
|
|
60
|
+
* a clearer photo; population_registry: terminal).
|
|
61
|
+
* @public
|
|
62
|
+
*/
|
|
63
|
+
type EligibilityReason = "document_type_not_accepted" | "nationality_not_allowed" | "underage" | "age_unverifiable";
|
|
64
|
+
/**
|
|
65
|
+
* Why a profile-v2 policy ended a session: a session-level
|
|
66
|
+
* {@link SessionFailureReason} (location / anonymizer gate), or the failed
|
|
67
|
+
* check's policy reason — an {@link EligibilityReason} or
|
|
68
|
+
* `document_nni_mismatch` (the document belongs to someone other than the
|
|
69
|
+
* NNI the session was created for).
|
|
70
|
+
* @public
|
|
71
|
+
*/
|
|
72
|
+
type PolicyFailureReason = SessionFailureReason | EligibilityReason | "document_nni_mismatch";
|
|
73
|
+
/**
|
|
74
|
+
* Profile-v2 matching reasons a check's {@link SessionStep.reason} may carry
|
|
75
|
+
* when the data you sent in {@link CreateSessionInput.subject} differs from the
|
|
76
|
+
* reference identity: `name_mismatch`, `birth_date_mismatch`,
|
|
77
|
+
* `nationality_mismatch` (doc_ocr or population_registry) and
|
|
78
|
+
* `document_number_mismatch` (doc_ocr). All are final.
|
|
79
|
+
* @public
|
|
80
|
+
*/
|
|
81
|
+
type MatchReason = "name_mismatch" | "birth_date_mismatch" | "nationality_mismatch" | "document_number_mismatch";
|
|
21
82
|
/** Hosted-flow languages. @public */
|
|
22
83
|
type Locale = "ar" | "fr" | "en";
|
|
23
84
|
/** The environment a webhook was emitted from. @public */
|
|
@@ -34,19 +95,196 @@ interface SessionStep {
|
|
|
34
95
|
reason?: string;
|
|
35
96
|
/** Calibrated model score in [0, 1] for scored checks (liveness, face match). */
|
|
36
97
|
calibratedScore?: number;
|
|
98
|
+
/** The check failed after using all of its attempts. */
|
|
99
|
+
attemptsExhausted?: boolean;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Out-of-band delivery of the session's hosted link, sent by Sekyro AI after the
|
|
103
|
+
* session is created. Best effort: a failed send never fails the create.
|
|
104
|
+
* @public
|
|
105
|
+
*/
|
|
106
|
+
interface DeliverOptions {
|
|
107
|
+
/** Delivery channel. */
|
|
108
|
+
channel: "sms" | "whatsapp";
|
|
109
|
+
/** E.164 phone number of the recipient, e.g. `+22236123456`. */
|
|
110
|
+
to: string;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* What you already know about the person (`subject` at session create). A
|
|
114
|
+
* closed object: unknown keys are refused (`400`). Every field is optional;
|
|
115
|
+
* `null` or blank counts as absent. Identity fields are compared with the
|
|
116
|
+
* person's document or registry record when the app's profile turns name
|
|
117
|
+
* matching on; `nni` binds the session to that identity.
|
|
118
|
+
* @public
|
|
119
|
+
*/
|
|
120
|
+
interface SessionSubjectInput {
|
|
121
|
+
/** 10-digit Mauritanian NNI, as a string. */
|
|
122
|
+
nni?: string;
|
|
123
|
+
/** E.164 phone number, e.g. `+22236123456`. */
|
|
124
|
+
phone?: string;
|
|
125
|
+
fullName?: string;
|
|
126
|
+
/** ISO 8601 date (`YYYY-MM-DD`). */
|
|
127
|
+
birthDate?: string;
|
|
128
|
+
/** ISO 3166-1 alpha-2, e.g. `MR`. */
|
|
129
|
+
nationality?: string;
|
|
130
|
+
/** Identity-document number (1–40 characters). */
|
|
131
|
+
documentNumber?: string;
|
|
132
|
+
/**
|
|
133
|
+
* Your own id for this person (1–128 characters). Echoed on the session and
|
|
134
|
+
* its webhooks, and searchable on the subjects API.
|
|
135
|
+
*/
|
|
136
|
+
externalRef?: string;
|
|
137
|
+
}
|
|
138
|
+
/** A document type the backend reads (kyc-docs-v2 vocabulary). @public */
|
|
139
|
+
type ProfileDocumentType = "carte_identite" | "passport";
|
|
140
|
+
/**
|
|
141
|
+
* The settings of an app's eKYC profile that a session may override — a
|
|
142
|
+
* mirror of the backend profile (schema version 2) without `schemaVersion`,
|
|
143
|
+
* `link` (use {@link CreateSessionInput.ttlMinutes}) and `overrides` (the
|
|
144
|
+
* app's own permission). Country codes are ISO 3166-1 alpha-2 (`MR`).
|
|
145
|
+
* Used through {@link EkycProfileOverride}.
|
|
146
|
+
* @public
|
|
147
|
+
*/
|
|
148
|
+
interface EkycProfileSettings {
|
|
149
|
+
/** Phone OTP step: off, or on with where the number comes from. */
|
|
150
|
+
phone: "off" | {
|
|
151
|
+
numberSource: "prefilled" | "user_entered" | "prefilled_or_entered";
|
|
152
|
+
};
|
|
153
|
+
document: {
|
|
154
|
+
mode: "off" | "optional" | "mandatory";
|
|
155
|
+
/** Accepted document types: `'*'` (all) or a list, optionally per issuing country. */
|
|
156
|
+
accepted: {
|
|
157
|
+
default: "*" | ProfileDocumentType[];
|
|
158
|
+
byIssuer?: Record<string, ProfileDocumentType[]>;
|
|
159
|
+
};
|
|
160
|
+
/** Expired documents: refused, allowed, or allowed for `graceDays` (1–365) after expiry. */
|
|
161
|
+
expired: "reject" | "allow" | {
|
|
162
|
+
graceDays: number;
|
|
163
|
+
};
|
|
164
|
+
authenticity: "standard" | "off";
|
|
165
|
+
};
|
|
166
|
+
registry: {
|
|
167
|
+
enabled: boolean;
|
|
168
|
+
sources: Array<"MR.anrpts">;
|
|
169
|
+
/** Which identity is the reference for face match and your data. */
|
|
170
|
+
reference?: "document" | "registry";
|
|
171
|
+
/** What happens when the registry has no record for the NNI. */
|
|
172
|
+
onNoRecord?: "fail" | "use_document";
|
|
173
|
+
};
|
|
174
|
+
liveness: {
|
|
175
|
+
enabled: boolean;
|
|
176
|
+
};
|
|
177
|
+
faceMatch: {
|
|
178
|
+
enabled: boolean;
|
|
179
|
+
};
|
|
180
|
+
/** Comparison of your `subject` data with the reference identity. */
|
|
181
|
+
nameMatch?: {
|
|
182
|
+
level: "strict" | "standard" | "lenient";
|
|
183
|
+
onMismatch: "fail" | "signal";
|
|
184
|
+
};
|
|
185
|
+
/** Per-step attempt limits. */
|
|
186
|
+
attempts?: {
|
|
187
|
+
phone: number;
|
|
188
|
+
document: number;
|
|
189
|
+
registry: number;
|
|
190
|
+
liveness: number;
|
|
191
|
+
faceMatch: number;
|
|
192
|
+
};
|
|
193
|
+
/** Where the end user may be (IP location). */
|
|
194
|
+
locations: {
|
|
195
|
+
mode: "all";
|
|
196
|
+
} | {
|
|
197
|
+
mode: "only" | "all_except";
|
|
198
|
+
countries: string[];
|
|
199
|
+
};
|
|
200
|
+
anonymizers: "allow" | "block";
|
|
201
|
+
/** Accepted nationalities: `'*'` or a list, optionally per IP location. */
|
|
202
|
+
nationalities: {
|
|
203
|
+
default: "*" | string[];
|
|
204
|
+
byLocation?: Record<string, "*" | string[]>;
|
|
205
|
+
};
|
|
206
|
+
/** Minimum age in years (1–120), or `null` for none. */
|
|
207
|
+
minAge: number | null;
|
|
208
|
+
/** Automatic decisions instead of human review (`retryConfidentRejects` lets confident rejects retry). */
|
|
209
|
+
decisions?: {
|
|
210
|
+
mode: "automatic" | "review";
|
|
211
|
+
retryConfidentRejects: boolean;
|
|
212
|
+
};
|
|
213
|
+
/** Device cooldown after repeated rejections (at most 5 tiers; `[]` = off). */
|
|
214
|
+
cooldown?: {
|
|
215
|
+
tiers: Array<{
|
|
216
|
+
rejectedSessions: number;
|
|
217
|
+
windowHours: number;
|
|
218
|
+
waitMinutes: number;
|
|
219
|
+
}>;
|
|
220
|
+
};
|
|
221
|
+
/** Device tamper and velocity actions. */
|
|
222
|
+
device?: {
|
|
223
|
+
tamper: "block" | "signal";
|
|
224
|
+
velocity: {
|
|
225
|
+
maxIdentitiesPerDevice: number;
|
|
226
|
+
windowDays: number;
|
|
227
|
+
action: "signal" | "block";
|
|
228
|
+
};
|
|
229
|
+
};
|
|
37
230
|
}
|
|
38
231
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
232
|
+
* `T` with every property optional, recursively. Arrays are replaced as a
|
|
233
|
+
* whole, never merged element by element.
|
|
234
|
+
* @public
|
|
235
|
+
*/
|
|
236
|
+
type DeepPartial<T> = T extends readonly unknown[] ? T : T extends object ? {
|
|
237
|
+
[K in keyof T]?: DeepPartial<T[K]>;
|
|
238
|
+
} : T;
|
|
239
|
+
/**
|
|
240
|
+
* A per-session override of the app's eKYC profile
|
|
241
|
+
* ({@link CreateSessionInput.profile}): any subset of
|
|
242
|
+
* {@link EkycProfileSettings}, at any depth (every field optional). Objects
|
|
243
|
+
* are merged into the app's profile; arrays and scalar values replace it.
|
|
244
|
+
*
|
|
245
|
+
* The API validates the merged result like a profile save. Unknown keys are
|
|
246
|
+
* rejected server-side (`400`, also for keys this SDK version does not type).
|
|
247
|
+
* An override may only make the profile stricter unless the app allows
|
|
248
|
+
* widening (`overrides.allowWidening`); otherwise a widening change answers
|
|
249
|
+
* `403 override_widens_profile`. The changed paths are reported on
|
|
250
|
+
* {@link Session.overriddenFields}.
|
|
251
|
+
* @public
|
|
252
|
+
*/
|
|
253
|
+
type EkycProfileOverride = DeepPartial<EkycProfileSettings>;
|
|
254
|
+
/**
|
|
255
|
+
* Input of {@link SessionsApi.create}. There is no recipe field: the API key
|
|
256
|
+
* belongs to an app, and that app's eKYC profile decides the steps.
|
|
41
257
|
* @public
|
|
42
258
|
*/
|
|
43
259
|
interface CreateSessionInput {
|
|
44
|
-
/** Flow slug configured for your organisation. */
|
|
45
|
-
flow?: string;
|
|
46
|
-
/** Legacy template id (pre-flows path). Prefer `flow`. */
|
|
47
|
-
templateId?: string;
|
|
48
260
|
/** Pins the hosted-flow language. Omit to let the person's device decide. */
|
|
49
261
|
locale?: Locale;
|
|
262
|
+
/**
|
|
263
|
+
* Pre-choose the identity method when the app's document step is optional
|
|
264
|
+
* (the hosted method screen is then skipped). Ignored for other apps.
|
|
265
|
+
*/
|
|
266
|
+
identityMethod?: IdentityMethod;
|
|
267
|
+
/**
|
|
268
|
+
* Session lifetime in minutes. Must fall within the app profile's link
|
|
269
|
+
* range, otherwise the API answers `400 ttl_out_of_policy`. Omit to use the
|
|
270
|
+
* profile's default.
|
|
271
|
+
*/
|
|
272
|
+
ttlMinutes?: number;
|
|
273
|
+
/** Also send the hosted link to the person by SMS or WhatsApp. */
|
|
274
|
+
deliver?: DeliverOptions;
|
|
275
|
+
/**
|
|
276
|
+
* What you already know about the person (preferred over `input` for
|
|
277
|
+
* identity data). A key sent in both `subject` and `input` with different
|
|
278
|
+
* values answers `400 subject_input_conflict`.
|
|
279
|
+
*/
|
|
280
|
+
subject?: SessionSubjectInput;
|
|
281
|
+
/**
|
|
282
|
+
* Override the app's eKYC profile for this session only (profile v2): a
|
|
283
|
+
* deep-partial {@link EkycProfileOverride}. Unknown keys are rejected
|
|
284
|
+
* server-side; a change that makes the profile less strict answers
|
|
285
|
+
* `403 override_widens_profile` unless the app allows widening.
|
|
286
|
+
*/
|
|
287
|
+
profile?: EkycProfileOverride;
|
|
50
288
|
/**
|
|
51
289
|
* Step inputs consumed server-side. The known anchors are typed (all
|
|
52
290
|
* strings — an `nni` is a 10-digit string, never a number); further keys
|
|
@@ -87,6 +325,63 @@ interface CreatedSession {
|
|
|
87
325
|
/** ISO 8601 — when the session (and its link) stop accepting input. */
|
|
88
326
|
expiresAt: string;
|
|
89
327
|
}
|
|
328
|
+
/**
|
|
329
|
+
* The end user's network at the start of the session (IP-derived, approximate).
|
|
330
|
+
* @public
|
|
331
|
+
*/
|
|
332
|
+
interface SessionNetworkEvent {
|
|
333
|
+
/** ISO 8601. */
|
|
334
|
+
at: string;
|
|
335
|
+
/** ISO 3166-1 alpha-2. */
|
|
336
|
+
country?: string;
|
|
337
|
+
region?: string;
|
|
338
|
+
city?: string;
|
|
339
|
+
asn?: number;
|
|
340
|
+
operator?: string;
|
|
341
|
+
connectionType: "mobile" | "hosting" | "unknown";
|
|
342
|
+
anonymizer: {
|
|
343
|
+
vpn: boolean;
|
|
344
|
+
tor: boolean;
|
|
345
|
+
hosting: boolean;
|
|
346
|
+
};
|
|
347
|
+
/** IANA time zone reported by the end user's device. */
|
|
348
|
+
browserTimezone?: string;
|
|
349
|
+
/** True when the device time zone does not belong to the IP country. */
|
|
350
|
+
timezoneMismatch?: boolean;
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* End-user network context; absent when not recorded.
|
|
354
|
+
* @public
|
|
355
|
+
*/
|
|
356
|
+
interface SessionNetwork {
|
|
357
|
+
/** The start event's IP address. Never sent in webhooks. */
|
|
358
|
+
ip?: string;
|
|
359
|
+
/** True when a later call came from a different country than the start. */
|
|
360
|
+
countryChanged: boolean;
|
|
361
|
+
start: SessionNetworkEvent;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Device signals detected on the end user's device.
|
|
365
|
+
* @public
|
|
366
|
+
*/
|
|
367
|
+
type SessionDeviceSignal = "webdriver" | "headless" | "emulator" | "rooted" | "jailbroken" | "debugger" | "hooking" | "virtual_camera";
|
|
368
|
+
/**
|
|
369
|
+
* End-user device summary; absent when not recorded.
|
|
370
|
+
* @public
|
|
371
|
+
*/
|
|
372
|
+
interface SessionDevice {
|
|
373
|
+
platform: "web" | "android" | "ios";
|
|
374
|
+
sdk?: string;
|
|
375
|
+
os?: string;
|
|
376
|
+
osVersion?: string;
|
|
377
|
+
browser?: string;
|
|
378
|
+
browserVersion?: string;
|
|
379
|
+
deviceClass: "mobile" | "tablet" | "desktop" | "unknown";
|
|
380
|
+
model?: string;
|
|
381
|
+
/** Device ids hashed with a key unique to your organization. */
|
|
382
|
+
deviceKeys: string[];
|
|
383
|
+
signals: SessionDeviceSignal[];
|
|
384
|
+
}
|
|
90
385
|
/**
|
|
91
386
|
* The whitelisted session view returned by {@link SessionsApi.get}. Never
|
|
92
387
|
* contains the client token.
|
|
@@ -101,6 +396,37 @@ interface Session {
|
|
|
101
396
|
expiresAt: string;
|
|
102
397
|
/** ISO 8601. */
|
|
103
398
|
createdAt: string;
|
|
399
|
+
/** End-user network context; absent when not recorded. */
|
|
400
|
+
network?: SessionNetwork;
|
|
401
|
+
/** End-user device; absent when not recorded. */
|
|
402
|
+
device?: SessionDevice;
|
|
403
|
+
/**
|
|
404
|
+
* Set when a profile-v2 policy ended the session: a session-level gate
|
|
405
|
+
* (location, anonymizer) or a failed check's policy reason (eligibility,
|
|
406
|
+
* `document_nni_mismatch`). Absent otherwise.
|
|
407
|
+
*/
|
|
408
|
+
failureReason?: PolicyFailureReason;
|
|
409
|
+
/** The subject (person) this session is linked to, once an identifier is known. */
|
|
410
|
+
subjectId?: string;
|
|
411
|
+
/** Your own id for the person, from `subject.externalRef` at create. */
|
|
412
|
+
externalRef?: string;
|
|
413
|
+
/**
|
|
414
|
+
* `true` when an identifier this session read already belongs to a
|
|
415
|
+
* different subject than `subjectId` — the subjects are never merged.
|
|
416
|
+
*/
|
|
417
|
+
subjectConflict?: boolean;
|
|
418
|
+
/**
|
|
419
|
+
* ISO 8601 — when the end user's device may verify again; set with
|
|
420
|
+
* `failureReason: 'device_cooldown'`.
|
|
421
|
+
*/
|
|
422
|
+
retryAfter?: string;
|
|
423
|
+
/** Dotted profile paths this session's {@link CreateSessionInput.profile} changed (e.g. `decisions.mode`). */
|
|
424
|
+
overriddenFields?: string[];
|
|
425
|
+
/**
|
|
426
|
+
* Risk signals recorded on the session (e.g. `device_velocity`,
|
|
427
|
+
* `timezone_mismatch`) — signals only, never a verdict by themselves.
|
|
428
|
+
*/
|
|
429
|
+
riskSignals?: string[];
|
|
104
430
|
}
|
|
105
431
|
/**
|
|
106
432
|
* `data` of the terminal / review-pending session lifecycle events
|
|
@@ -118,6 +444,54 @@ interface SessionLifecycleEventData {
|
|
|
118
444
|
steps?: Array<Pick<SessionStep, "checkType" | "state">>;
|
|
119
445
|
/** Machine-readable reason, when the transition has one. */
|
|
120
446
|
reason?: string;
|
|
447
|
+
/** End-user network context (no IP); on `completed` / `failed` when recorded. */
|
|
448
|
+
network?: Omit<SessionNetwork, "ip">;
|
|
449
|
+
/** End-user device; on `completed` / `failed` when recorded. */
|
|
450
|
+
device?: SessionDevice;
|
|
451
|
+
/**
|
|
452
|
+
* On `session.failed`: set when a profile-v2 policy ended the session — a
|
|
453
|
+
* session-level gate (location, anonymizer) or a failed check's policy
|
|
454
|
+
* reason (eligibility, `document_nni_mismatch`).
|
|
455
|
+
*/
|
|
456
|
+
failureReason?: PolicyFailureReason;
|
|
457
|
+
/** The subject (person) the session is linked to, when known. */
|
|
458
|
+
subjectId?: string;
|
|
459
|
+
/** Your own id for the person, from `subject.externalRef` at create. */
|
|
460
|
+
externalRef?: string;
|
|
461
|
+
/**
|
|
462
|
+
* `true` when an identifier this session read already belongs to a
|
|
463
|
+
* different subject than `subjectId` — the subjects are never merged.
|
|
464
|
+
*/
|
|
465
|
+
subjectConflict?: boolean;
|
|
466
|
+
/**
|
|
467
|
+
* On `session.failed` with `failureReason: 'device_cooldown'`: ISO time
|
|
468
|
+
* from which the device may start a new verification.
|
|
469
|
+
*/
|
|
470
|
+
retryAfter?: string;
|
|
471
|
+
/** Dotted profile paths the session's create-time override changed. */
|
|
472
|
+
overriddenFields?: string[];
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* `data` of `subject.updated` — a session linked to the subject reached a
|
|
476
|
+
* terminal state. Ids and enums only.
|
|
477
|
+
* @public
|
|
478
|
+
*/
|
|
479
|
+
interface SubjectUpdatedEventData {
|
|
480
|
+
subjectId: string;
|
|
481
|
+
sessionId: string;
|
|
482
|
+
status: SessionStatus;
|
|
483
|
+
outcome: SessionOutcome | null;
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* `data` of `subject.suspicious_activity` — a device already linked to
|
|
487
|
+
* ANOTHER subject was used for a session of this subject. `count` is the
|
|
488
|
+
* subject's running total of such events. Ids only.
|
|
489
|
+
* @public
|
|
490
|
+
*/
|
|
491
|
+
interface SubjectSuspiciousActivityEventData {
|
|
492
|
+
subjectId: string;
|
|
493
|
+
sessionId: string;
|
|
494
|
+
count: number;
|
|
121
495
|
}
|
|
122
496
|
/**
|
|
123
497
|
* `data` of `session.step.completed` — the check that just passed.
|
|
@@ -127,6 +501,15 @@ interface SessionStepCompletedEventData {
|
|
|
127
501
|
sessionId: string;
|
|
128
502
|
checkType: CheckType;
|
|
129
503
|
state: CheckState;
|
|
504
|
+
/** The subject (person) the session is linked to, when known. */
|
|
505
|
+
subjectId?: string;
|
|
506
|
+
/** Your own id for the person, from `subject.externalRef` at create. */
|
|
507
|
+
externalRef?: string;
|
|
508
|
+
/**
|
|
509
|
+
* `true` when an identifier this session read already belongs to a
|
|
510
|
+
* different subject than `subjectId` — the subjects are never merged.
|
|
511
|
+
*/
|
|
512
|
+
subjectConflict?: boolean;
|
|
130
513
|
}
|
|
131
514
|
/**
|
|
132
515
|
* `data` of `session.review_decided` — a human (or the review-timeout sweep)
|
|
@@ -139,6 +522,15 @@ interface SessionReviewDecidedEventData {
|
|
|
139
522
|
sessionId: string;
|
|
140
523
|
outcome: "pass" | "fail";
|
|
141
524
|
reason: string;
|
|
525
|
+
/** The subject (person) the session is linked to, when known. */
|
|
526
|
+
subjectId?: string;
|
|
527
|
+
/** Your own id for the person, from `subject.externalRef` at create. */
|
|
528
|
+
externalRef?: string;
|
|
529
|
+
/**
|
|
530
|
+
* `true` when an identifier this session read already belongs to a
|
|
531
|
+
* different subject than `subjectId` — the subjects are never merged.
|
|
532
|
+
*/
|
|
533
|
+
subjectConflict?: boolean;
|
|
142
534
|
}
|
|
143
535
|
/**
|
|
144
536
|
* Event type → the shape of its `data`. Session events are typed; the
|
|
@@ -156,6 +548,8 @@ interface WebhookEventDataMap {
|
|
|
156
548
|
"session.expired": SessionLifecycleEventData;
|
|
157
549
|
"session.failed": SessionLifecycleEventData;
|
|
158
550
|
"subject.enrolled": Record<string, unknown>;
|
|
551
|
+
"subject.updated": SubjectUpdatedEventData;
|
|
552
|
+
"subject.suspicious_activity": SubjectSuspiciousActivityEventData;
|
|
159
553
|
"subject.deleted": Record<string, unknown>;
|
|
160
554
|
"aml.match_flagged": Record<string, unknown>;
|
|
161
555
|
"payment.received": Record<string, unknown>;
|
|
@@ -250,12 +644,19 @@ declare class SessionsApi {
|
|
|
250
644
|
* browser, never persist it. Pass an `idempotencyKey` so a retried call
|
|
251
645
|
* cannot create a second session.
|
|
252
646
|
*/
|
|
253
|
-
create(input
|
|
647
|
+
create(input?: CreateSessionInput, opts?: RequestOptions): Promise<CreatedSession>;
|
|
648
|
+
/**
|
|
649
|
+
* `POST /sessions/:id/method` — choose the identity method of an
|
|
650
|
+
* optional-document session on the person's behalf (the hosted method
|
|
651
|
+
* screen is then skipped). `409 method_locked` once the choice can no
|
|
652
|
+
* longer change; `409 session_not_active` on a finished or expired session.
|
|
653
|
+
*/
|
|
654
|
+
selectMethod(id: string, method: IdentityMethod): Promise<Session>;
|
|
254
655
|
/** `GET /sessions/:id` — the whitelisted view (no client token). */
|
|
255
656
|
get(id: string): Promise<Session>;
|
|
256
657
|
}
|
|
257
658
|
/**
|
|
258
|
-
* Sekyro partner API client. Server-side only: it carries your API key.
|
|
659
|
+
* Sekyro AI partner API client. Server-side only: it carries your API key.
|
|
259
660
|
*
|
|
260
661
|
* Throws {@link SekyroConfigError} synchronously when `apiKey` is missing or
|
|
261
662
|
* `baseUrl` is not `https:` (plain `http:` is accepted for `localhost`,
|
|
@@ -264,7 +665,7 @@ declare class SessionsApi {
|
|
|
264
665
|
* @example
|
|
265
666
|
* ```ts
|
|
266
667
|
* const sekyro = new Sekyro({ apiKey: process.env.SEKYRO_API_KEY! });
|
|
267
|
-
* const { id, clientToken } = await sekyro.sessions.create({
|
|
668
|
+
* const { id, clientToken } = await sekyro.sessions.create({ input: { nni: "1357924632" } });
|
|
268
669
|
* ```
|
|
269
670
|
* @public
|
|
270
671
|
*/
|
|
@@ -277,7 +678,7 @@ declare class Sekyro {
|
|
|
277
678
|
type SekyroWebhookErrorCode = "invalid_signature" | "stale" | "malformed";
|
|
278
679
|
/**
|
|
279
680
|
* Thrown by {@link verifyWebhook}. Respond with a 4xx and do not process the
|
|
280
|
-
* body; Sekyro retries deliveries that do not receive a 2xx.
|
|
681
|
+
* body; Sekyro AI retries deliveries that do not receive a 2xx.
|
|
281
682
|
* @public
|
|
282
683
|
*/
|
|
283
684
|
declare class SekyroWebhookError extends Error {
|
|
@@ -337,7 +738,7 @@ declare class SekyroApiError extends Error {
|
|
|
337
738
|
*/
|
|
338
739
|
declare const SEKYRO_SIGNATURE_HEADER = "x-sekyro-signature";
|
|
339
740
|
/**
|
|
340
|
-
* The pre-rebrand name of the signature header. Sekyro sends BOTH headers with
|
|
741
|
+
* The pre-rebrand name of the signature header. Sekyro AI sends BOTH headers with
|
|
341
742
|
* the same value during the transition; prefer {@link SEKYRO_SIGNATURE_HEADER}
|
|
342
743
|
* and use {@link signatureFromHeaders} to accept either.
|
|
343
744
|
* @public
|
|
@@ -365,13 +766,13 @@ interface VerifyWebhookOptions {
|
|
|
365
766
|
now?: () => number;
|
|
366
767
|
}
|
|
367
768
|
/**
|
|
368
|
-
* Verify a Sekyro webhook delivery and return its parsed envelope, discriminated
|
|
769
|
+
* Verify a Sekyro AI webhook delivery and return its parsed envelope, discriminated
|
|
369
770
|
* on `event` (narrow with a `switch` to type `data`).
|
|
370
771
|
*
|
|
371
772
|
* - `rawBody` MUST be the request body exactly as received (before any JSON
|
|
372
773
|
* parsing / re-serialisation); the signature covers those bytes.
|
|
373
774
|
* - Accepts the delivery when ANY `v1` in the header matches, which is what
|
|
374
|
-
* makes secret rotation seamless (Sekyro signs with current + previous).
|
|
775
|
+
* makes secret rotation seamless (Sekyro AI signs with current + previous).
|
|
375
776
|
* - Uses `node:crypto` only; the digest compare is constant-time.
|
|
376
777
|
*
|
|
377
778
|
* Checks run in this order: header/secret present → header well-formed →
|
|
@@ -386,4 +787,4 @@ interface VerifyWebhookOptions {
|
|
|
386
787
|
*/
|
|
387
788
|
declare function verifyWebhook(rawBody: string, header: string | null | undefined, secret: string, opts?: VerifyWebhookOptions): WebhookEnvelope;
|
|
388
789
|
|
|
389
|
-
export { type CheckState, type CheckType, type CreateSessionInput, type CreatedSession, DEFAULT_BASE_URL, DEFAULT_TIMEOUT_MS, 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 };
|
|
790
|
+
export { type CheckState, type CheckType, type CreateSessionInput, type CreatedSession, DEFAULT_BASE_URL, DEFAULT_TIMEOUT_MS, type DecisionReason, type DeepPartial, type DeliverOptions, type EkycProfileOverride, type EkycProfileSettings, type EligibilityReason, type FetchLike, type IdentityMethod, LEGACY_SIGNATURE_HEADER, type Locale, type MatchReason, type PolicyFailureReason, type ProfileDocumentType, type RequestOptions, 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 SessionReviewDecidedEventData, type SessionStatus, type SessionStep, type SessionStepCompletedEventData, type SessionSubjectInput, SessionsApi, type SubjectSuspiciousActivityEventData, type SubjectUpdatedEventData, type VerifyWebhookOptions, type WebhookEnvelope, type WebhookEnvelopeOf, type WebhookEventDataMap, type WebhookEventType, signatureFromHeaders, verifyWebhook };
|