@kyciris/core 0.1.2 → 1.1.0

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.mts CHANGED
@@ -1,210 +1,1526 @@
1
1
  /**
2
- * Credentials required to initialize the KYC SDK
2
+ * The largest upload the gateway accepts (MAX_IMAGE_FILE_SIZE). Checked here
3
+ * too, when the SDK can see the bytes, so an 8MB upload fails instantly
4
+ * instead of after the whole body has gone over the wire.
3
5
  */
4
- interface KYCCredentials {
5
- /** API key for authentication */
6
- apiKey: string;
7
- /** Base URL of the KYC API */
8
- baseUrl: string;
6
+ declare const MAX_IMAGE_FILE_SIZE: number;
7
+ /** The only image types the gateway accepts, decided by magic bytes. */
8
+ type ImageMimeType = 'image/jpeg' | 'image/png';
9
+ /**
10
+ * An image to upload, in whichever form the host platform produces.
11
+ *
12
+ * - `Blob` / `File` — browsers, and Node 18+ (`new Blob([bytes])`).
13
+ * - `{ uri }` — React Native: a `file://`, `content://`, `ph://` or `data:` URI
14
+ * from the camera or image picker.
15
+ * - `{ data }` — raw bytes, e.g. `fs.readFileSync()` in Node.
16
+ * - `string` — a `data:` URI, a bare base64 payload, or a React Native file URI.
17
+ */
18
+ type FileInput = Blob | {
19
+ uri: string;
20
+ name?: string;
21
+ type?: string;
22
+ } | {
23
+ data: ArrayBuffer | ArrayBufferView;
24
+ name?: string;
25
+ type?: string;
26
+ } | string | NormalizedFile;
27
+ /** A file ready to be appended to FormData on this platform. */
28
+ interface NormalizedFile {
29
+ /** Blob on web/Node, `{ uri, name, type }` on React Native. */
30
+ value: unknown;
31
+ filename: string;
32
+ /** Sniffed from the bytes where possible, otherwise the caller's hint. */
33
+ mimeType: string;
9
34
  }
35
+ /** True when `value` has already been through {@link normalizeFile}. */
36
+ declare function isNormalizedFile(value: unknown): value is NormalizedFile;
10
37
  /**
11
- * Parameters required to start a verification session
38
+ * React Native's FormData takes `{ uri, name, type }` and streams the file
39
+ * itself; it has no filesystem access from JS to turn that URI into a Blob.
40
+ * Everywhere else, Blob is the portable choice.
12
41
  */
13
- interface StartVerificationParams {
14
- /** Type of document to verify (e.g., IDENTITY_CARD, DRIVING_LICENSE) */
15
- documentType: 'IDENTITY_CARD' | 'DRIVING_LICENSE';
16
- /** Country code (e.g., MZ, AO, PT) */
17
- country: string;
18
- /** Optional existing identity ID to link verification to */
19
- identityId?: string;
20
- /** Optional external reference ID */
21
- externalId?: string;
42
+ declare function isReactNative(): boolean;
43
+ /**
44
+ * The real image type, from the first bytes.
45
+ *
46
+ * The gateway sniffs the same way and ignores the declared Content-Type, so a
47
+ * caller who mislabels a PNG as image/jpeg still succeeds — and one who
48
+ * uploads a PDF renamed to .jpg still fails. Doing it here just moves that
49
+ * answer earlier.
50
+ */
51
+ declare function detectImageMimeType(bytes: Uint8Array): ImageMimeType | null;
52
+ /** Decodes base64 using whichever primitive the runtime provides. */
53
+ declare function decodeBase64(input: string): Uint8Array;
54
+ /** Encodes bytes as base64 using whichever primitive the runtime provides. */
55
+ declare function encodeBase64(bytes: Uint8Array): string;
56
+ /**
57
+ * Turns whatever the caller has into something FormData can carry on this
58
+ * platform, validating the bytes first whenever they are visible.
59
+ *
60
+ * A React Native `file://` URI is the one case where they are not: the file
61
+ * lives on disk and only the native layer reads it, so type and size are left
62
+ * to the gateway to enforce.
63
+ *
64
+ * @param input The image, in any supported form
65
+ * @param defaultName Filename to use when the input does not carry one
66
+ */
67
+ declare function normalizeFile(input: FileInput, defaultName: string): NormalizedFile;
68
+ /**
69
+ * {@link normalizeFile}, but able to read a Blob's first bytes.
70
+ *
71
+ * This is what the upload path uses. A file chosen from an `<input>` arrives
72
+ * as a Blob whose `type` is whatever the operating system guessed from the
73
+ * extension, so a PDF renamed `.jpg` claims to be `image/jpeg` — and the
74
+ * synchronous path has to take that on trust. Reading eight bytes settles it
75
+ * before megabytes go over a phone connection, using the same magic-byte test
76
+ * the gateway applies on arrival.
77
+ *
78
+ * Every other input form is already validated synchronously, so it is simply
79
+ * delegated.
80
+ */
81
+ declare function prepareFile(input: FileInput, defaultName: string): Promise<NormalizedFile>;
82
+
83
+ /**
84
+ * Metadata the gateway attaches to every response, success or error.
85
+ *
86
+ * `requestId` is also returned as the X-Request-Id header and is the value to
87
+ * quote when reporting a problem — it correlates the call with the gateway's
88
+ * own logs.
89
+ */
90
+ interface ApiMeta {
91
+ requestId: string;
92
+ timestamp: string;
93
+ /** The gateway's API version, not the SDK's. */
94
+ version: string;
22
95
  }
23
- interface FaceMatchVerificationParams {
24
- externalId: string;
25
- file: string;
26
- mimeType?: string;
96
+ interface PaginationMeta {
97
+ page: number;
98
+ limit: number;
99
+ total: number;
27
100
  }
28
- interface FaceMatchStatusParams {
29
- externalId: string;
30
- faceCheckId: string;
31
- interval?: number;
32
- timeout?: number;
101
+ /** A successful response, unwrapped. */
102
+ interface ApiResult<T> {
103
+ data: T;
104
+ meta: ApiMeta;
105
+ /** Present only on list endpoints. */
106
+ pagination?: PaginationMeta;
107
+ }
108
+ /** A page of results: the rows, plus the pagination block that came with them. */
109
+ interface Page<T> {
110
+ items: T[];
111
+ pagination: PaginationMeta;
33
112
  }
34
113
  /**
35
- * Response from starting a verification session
114
+ * Turns an unwrapped list response into a Page.
115
+ *
116
+ * The gateway sends the rows as `data` and the counts as a sibling
117
+ * `pagination` block; a caller wants them together. When the endpoint returned
118
+ * no pagination block (or an unpaginated array), the totals are derived from
119
+ * the rows so the shape stays uniform.
36
120
  */
121
+ declare function toPage<T>(result: ApiResult<T[]>): Page<T>;
122
+
123
+ /** Returns a verification token, refreshing it if the cached one has expired. */
124
+ type VerificationTokenProvider = () => string | Promise<string>;
125
+ /** The subset of `fetch` the SDK uses, so a custom implementation can stand in. */
126
+ type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
127
+ /** Which credential an endpoint accepts. */
128
+ type AuthMode = 'api-key' | 'token' | 'any' | 'none';
129
+ interface HttpClientConfig {
130
+ /** Origin of the gateway, e.g. `https://api.kyciris.com`. */
131
+ baseUrl: string;
132
+ /**
133
+ * Project API key. A project-wide credential — server-side only. Passing it
134
+ * from a browser or React Native app throws CREDENTIAL_MISUSE.
135
+ */
136
+ apiKey?: string;
137
+ /**
138
+ * Verification token, scoped to one end user. This is the credential a
139
+ * client app should hold: mint it on your server with
140
+ * `client.verifications.createToken(externalId)` and hand it out.
141
+ *
142
+ * A function is called before each request, so a token can be refreshed
143
+ * without rebuilding the client.
144
+ */
145
+ verificationToken?: string | VerificationTokenProvider;
146
+ /** URI version segment. Defaults to `v1`. */
147
+ apiVersion?: string;
148
+ /** Per-attempt timeout in ms. Defaults to 30000. */
149
+ timeoutMs?: number;
150
+ /** Retries for a failed attempt. Defaults to 2 (three attempts in total). */
151
+ maxRetries?: number;
152
+ /** Custom fetch (tests, proxies, a Node agent). Defaults to global fetch. */
153
+ fetch?: FetchLike;
154
+ /** Extra headers on every request. Cannot override the auth headers. */
155
+ headers?: Record<string, string>;
156
+ /**
157
+ * Allows an `http://` baseUrl to a non-loopback host.
158
+ *
159
+ * Off by default: the requests carry a project API key or a verification
160
+ * token and the responses carry identity-document data, none of which may
161
+ * cross a plaintext connection.
162
+ */
163
+ allowInsecureBaseUrl?: boolean;
164
+ /**
165
+ * Allows `apiKey` in a browser or React Native app.
166
+ *
167
+ * Only for a trusted first-party context (an internal operations console
168
+ * behind a login). Anything shipped to end users must use a verification
169
+ * token: an API key in a client bundle is extractable and grants the whole
170
+ * project, every identity in it included.
171
+ */
172
+ allowApiKeyInUntrustedClient?: boolean;
173
+ }
174
+ interface RequestOptions {
175
+ method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
176
+ /** Path below the version segment, e.g. `/verification/start`. */
177
+ path: string;
178
+ query?: Record<string, unknown>;
179
+ /** JSON request body. Mutually exclusive with `form`. */
180
+ body?: unknown;
181
+ /** Multipart body. Values typed `FileInput` are normalized per platform. */
182
+ form?: Record<string, string | FileInput | undefined>;
183
+ /** Field names in `form` that hold a file. */
184
+ fileFields?: string[];
185
+ auth?: AuthMode;
186
+ signal?: AbortSignal;
187
+ /** Overrides the client's timeout for this call. */
188
+ timeoutMs?: number;
189
+ /**
190
+ * Whether a failed attempt may be repeated.
191
+ *
192
+ * Defaults to true for GET and false for everything else: a POST that timed
193
+ * out may well have been processed, and re-sending an upload would emit a
194
+ * second pipeline event. A 429 is retried regardless of method, because the
195
+ * gateway rejected it before doing any work.
196
+ */
197
+ retry?: boolean;
198
+ }
199
+ /**
200
+ * True in a context where the bundle is delivered to an end user and anything
201
+ * inside it is readable by them: a browser page or a React Native app.
202
+ */
203
+ declare function isUntrustedClient(): boolean;
204
+ /**
205
+ * The gateway's HTTP transport: URL and auth assembly, timeouts, retries, and
206
+ * translation of the `{ data, meta }` / `{ error, meta }` envelopes into
207
+ * values and KycirisErrors.
208
+ */
209
+ declare class HttpClient {
210
+ private readonly baseUrl;
211
+ private readonly apiVersion;
212
+ private readonly timeoutMs;
213
+ private readonly maxRetries;
214
+ private readonly fetchImpl;
215
+ private readonly extraHeaders;
216
+ private readonly apiKey?;
217
+ private readonly tokenSource?;
218
+ constructor(config: HttpClientConfig);
219
+ /** True when the client holds a project API key. */
220
+ hasApiKey(): boolean;
221
+ /** True when the client holds (or can fetch) a verification token. */
222
+ hasVerificationToken(): boolean;
223
+ buildUrl(path: string, query?: Record<string, unknown>): string;
224
+ private authHeaders;
225
+ private resolveToken;
226
+ private buildForm;
227
+ /** Runs a request, retrying where the method and failure allow it. */
228
+ request<T>(options: RequestOptions): Promise<ApiResult<T>>;
229
+ private attempt;
230
+ /**
231
+ * Streams a response body instead of parsing it — the media download
232
+ * endpoint returns an image, not an envelope.
233
+ */
234
+ requestRaw(options: RequestOptions): Promise<Response>;
235
+ }
236
+
237
+ /**
238
+ * Domain types mirroring the KYCiris gateway's public contract.
239
+ *
240
+ * Everything here is derived from the gateway's DTOs and constants; where the
241
+ * gateway is the authority for a set of values (document catalog, statuses,
242
+ * webhook events) the list is reproduced verbatim rather than widened to
243
+ * `string`, so a typo fails at compile time instead of at runtime with a 422.
244
+ */
245
+ /**
246
+ * The (country, documentType) pairs the pipeline can actually process.
247
+ *
248
+ * Mirrors DOCUMENT_CATALOG in the gateway, which in turn mirrors the OCR
249
+ * worker's handler registry — a pair is only real once something knows how to
250
+ * read it. Starting a verification for a pair outside this list is rejected by
251
+ * the gateway with VALIDATION_ERROR.
252
+ */
253
+ declare const DOCUMENT_CATALOG: readonly [{
254
+ readonly country: "AO";
255
+ readonly documentType: "ID_CARD";
256
+ }, {
257
+ readonly country: "AO";
258
+ readonly documentType: "DRIVING_LICENSE";
259
+ }, {
260
+ readonly country: "MZ";
261
+ readonly documentType: "ID_CARD";
262
+ }];
263
+ type DocumentCatalogEntry = (typeof DOCUMENT_CATALOG)[number];
264
+ /** ISO 3166-1 alpha-2 codes present in the catalog. */
265
+ type CatalogCountry = DocumentCatalogEntry['country'];
266
+ /** Document type codes present in the catalog. */
267
+ type DocumentType = DocumentCatalogEntry['documentType'];
268
+ /** True when the gateway can process this pair. */
269
+ declare function isSupportedDocumentPair(country: string, documentType: string): boolean;
270
+ /** The countries in the catalog, deduplicated. */
271
+ declare function supportedCountries(): CatalogCountry[];
272
+ /** The document types the catalog supports for `country`. */
273
+ declare function supportedDocumentTypes(country: string): DocumentType[];
274
+ /** The pipeline's state machine, as written by the gateway and its workers. */
275
+ declare const VERIFICATION_STATUSES: readonly ["PENDING", "PROCESSING", "REVIEW", "APPROVED", "REJECTED"];
276
+ type VerificationStatus = (typeof VERIFICATION_STATUSES)[number];
277
+ /**
278
+ * What a verification *means* operationally, derived by the gateway from the
279
+ * status and rejection code.
280
+ *
281
+ * The distinction that `status` alone cannot make: REJECTED is written both
282
+ * when the rules genuinely said no and when our own OCR choked on a valid
283
+ * document. Those want opposite handling — the first is an answer for the end
284
+ * user, the second is a retry for us.
285
+ */
286
+ declare const VERIFICATION_OUTCOMES: readonly ["APPROVED", "REJECTED", "FAILED_TECHNICAL", "NEEDS_REVIEW"];
287
+ type VerificationOutcome = (typeof VERIFICATION_OUTCOMES)[number];
288
+ /** Statuses from which the pipeline will not move on its own. */
289
+ declare const TERMINAL_VERIFICATION_STATUSES: readonly ["APPROVED", "REJECTED"];
290
+ /** True when the pipeline has reached a decision for this status. */
291
+ declare function isTerminalStatus(status: string): boolean;
292
+ /** A step the end user has to complete before the pipeline can decide. */
293
+ type VerificationStep = 'document_front' | 'document_back' | 'selfie';
294
+ /** The side of an identity document being uploaded. */
295
+ type DocumentSide = 'front' | 'back';
296
+ /** Files a verification can hold, as named by the gateway's media endpoints. */
297
+ type MediaResource = 'selfie' | 'document-front' | 'document-back' | 'document-face';
298
+ interface StartVerificationParams {
299
+ /** Must form a supported pair with `country` (see DOCUMENT_CATALOG). */
300
+ documentType: DocumentType | (string & {});
301
+ /** ISO 3166-1 alpha-2 country code. */
302
+ country: CatalogCountry | (string & {});
303
+ /** Link to an existing identity instead of creating a new one. */
304
+ identityId?: string;
305
+ /**
306
+ * Your own reference for this end user.
307
+ *
308
+ * Ignored when the client authenticates with a verification token: that token
309
+ * is already bound to one externalId, and the gateway treats the token's
310
+ * value as authoritative so a token cannot create a verification under
311
+ * someone else's reference.
312
+ */
313
+ externalId?: string;
314
+ /**
315
+ * Name of the verification level (policy) to run under. Required.
316
+ *
317
+ * The level is what says which documents the project accepts and whether a
318
+ * selfie is needed, so the gateway has no verification without one: a start
319
+ * that names no level, or names one that is not active on the project, is
320
+ * rejected (422 / 404). Levels are created from your backend with
321
+ * `client.levels.create()` -- a project can verify nobody until it has one.
322
+ */
323
+ levelName: string;
324
+ }
37
325
  interface VerificationSession {
38
- /** Unique verification ID */
39
326
  verificationId: string;
40
- /** Linked identity ID (if exists) */
41
327
  identityId?: string;
42
- /** Current verification status */
43
- status: string;
328
+ status: VerificationStatus;
329
+ }
330
+ /** OCR output. Fields present depend on the document; unread fields are null. */
331
+ interface OcrData {
332
+ country?: string | null;
333
+ documentType?: string | null;
334
+ fullName?: string | null;
335
+ idNumber?: string | null;
336
+ birthDate?: string | null;
337
+ validFrom?: string | null;
338
+ validUntil?: string | null;
339
+ gender?: string | null;
340
+ height?: number | null;
341
+ address?: string | null;
342
+ mrz?: string | null;
343
+ maritalStatus?: string | null;
344
+ [field: string]: unknown;
44
345
  }
45
346
  /**
46
- * Parameters for uploading a selfie image
347
+ * What an applicant still owes, and the verdict about the person.
348
+ *
349
+ * A level may require more than one document, which makes "this document is
350
+ * approved" and "this person is verified" different statements. Only the second
351
+ * one is what an integration actually wants to act on.
47
352
  */
48
- interface UploadSelfieParams {
49
- /** Verification ID to attach the selfie to */
50
- verificationId: string;
51
- /** Base64 encoded image data, data URI, or file:// URI (React Native) */
52
- imageData: string;
53
- /** MIME type of the image (default: image/jpeg) */
54
- mimeType?: string;
55
- }
353
+ type ApplicantAnswer = 'GREEN' | 'RED';
56
354
  /**
57
- * Parameters for uploading a document image
355
+ * Whether presenting the document again could change the answer.
356
+ *
357
+ * `RETRY` is a bad photo, or a failure on the gateway's side -- ask the user to
358
+ * try again. `FINAL` is a decision the rules would reach again, so asking them
359
+ * to retry only wastes their time.
58
360
  */
59
- interface UploadDocumentParams {
60
- /** Verification ID to attach the document to */
361
+ type ApplicantRejectType = 'RETRY' | 'FINAL';
362
+ type RequirementStatus = 'APPROVED' | 'REVIEW' | 'REJECTED' | 'PENDING';
363
+ interface ApplicantRequirement {
364
+ /** One of the document types the level asks for. */
365
+ documentType: string;
366
+ status: RequirementStatus;
367
+ /** The verification that settled it, when one has. */
368
+ verificationId: string | null;
369
+ rejectionType: string | null;
370
+ }
371
+ interface ApplicantStatus {
372
+ identityId: string;
373
+ externalId: string;
374
+ /** Decides which of the level's document lists applies. */
375
+ country: string | null;
376
+ levelName: string;
377
+ /** Every required document approved. */
378
+ complete: boolean;
379
+ /** Null while nothing has been decided, which must not read as a refusal. */
380
+ answer: ApplicantAnswer | null;
381
+ rejectType: ApplicantRejectType | null;
382
+ rejectLabels: string[];
383
+ requirements: ApplicantRequirement[];
384
+ /** Document types with nothing approved yet: what to ask the user for next. */
385
+ outstanding: string[];
386
+ selfie: {
387
+ required: boolean;
388
+ /** Captured once per applicant and reused for every document. */
389
+ captured: boolean;
390
+ capturedAt: string | null;
391
+ };
392
+ }
393
+ interface GetApplicantParams {
394
+ /**
395
+ * The applicant's id in your own system. Required when the client holds an
396
+ * API key; ignored when it holds a verification token, which already names
397
+ * one end-user.
398
+ */
399
+ externalId?: string;
400
+ /**
401
+ * Only needed before the applicant's first verification exists, when there is
402
+ * no level to read from their history.
403
+ */
404
+ levelName?: string;
405
+ }
406
+ interface VerificationStatusResponse {
61
407
  verificationId: string;
62
- /** Type of document (front or back) */
63
- type: 'front' | 'back';
64
- /** Base64 encoded image data, data URI, or file:// URI (React Native) */
65
- imageData: string;
66
- /** MIME type of the image (default: image/jpeg) */
67
- mimeType?: string;
68
- }
69
- /** Result of an upload operation */
408
+ status: VerificationStatus;
409
+ /** Null while still PENDING/PROCESSING — no outcome exists yet. */
410
+ outcome: VerificationOutcome | null;
411
+ /** 0-1 similarity between selfie and document photo; null until computed. */
412
+ faceMatchScore: number | null;
413
+ /** Null until the document front has been processed. */
414
+ ocrData: OcrData | null;
415
+ /** A gateway ERROR_CODE naming why, when the pipeline stopped or refused. */
416
+ rejectionType: string | null;
417
+ rejectionReason: string | null;
418
+ /** An operator's email, "system", or null. */
419
+ decidedBy: string | null;
420
+ decidedAt: string | null;
421
+ createdAt: string;
422
+ updatedAt: string;
423
+ }
70
424
  interface UploadResult {
71
- /** Response message */
72
425
  message: string;
73
- /** Current status after upload */
74
- status: string;
426
+ status: VerificationStatus;
75
427
  }
76
- /** Current status of a verification session */
77
- interface VerificationStatus {
78
- /** Verification ID */
79
- verificationId: string;
80
- /** Current status: PENDING, PROCESSING, APPROVED, or REJECTED */
81
- status: 'PENDING' | 'PROCESSING' | 'APPROVED' | 'REJECTED';
82
- /** Face match similarity score (0-1) */
83
- faceMatchScore?: number;
84
- /** OCR extracted data from document */
85
- ocrData?: {
86
- /** Full name extracted from document */
87
- fullName?: string;
88
- /** ID number extracted from document */
89
- idNumber?: string;
90
- /** Birth date extracted from document */
91
- birthDate?: string;
92
- /** Expiry date extracted from document */
93
- expiryDate?: string;
94
- /** Additional extracted fields */
95
- [key: string]: any;
428
+ /** One row of the operations list. Deliberately free of OCR data and paths. */
429
+ interface VerificationListItem {
430
+ id: string;
431
+ externalId: string | null;
432
+ status: VerificationStatus;
433
+ outcome: VerificationOutcome | null;
434
+ /** True when it has sat in flight past the gateway's stall threshold. */
435
+ stalled: boolean;
436
+ country: string | null;
437
+ documentType: string | null;
438
+ faceMatchScore: number | null;
439
+ rejectionType: string | null;
440
+ rejectionReason: string | null;
441
+ decidedBy: string | null;
442
+ decidedAt: string | null;
443
+ createdAt: string;
444
+ updatedAt: string;
445
+ }
446
+ interface ListVerificationsParams {
447
+ page?: number;
448
+ /** 1-100; the gateway rejects anything larger. */
449
+ limit?: number;
450
+ status?: VerificationStatus[];
451
+ outcome?: VerificationOutcome;
452
+ /** Only stalled (true) or only healthy (false). Omit for both. */
453
+ stalled?: boolean;
454
+ country?: string;
455
+ documentType?: string;
456
+ /** Exact match on your own reference. */
457
+ externalId?: string;
458
+ /** ISO 8601 instant. */
459
+ createdAfter?: string;
460
+ /** ISO 8601 instant. */
461
+ createdBefore?: string;
462
+ order?: 'ASC' | 'DESC';
463
+ }
464
+ interface VerificationSummary {
465
+ byStatus: Partial<Record<VerificationStatus, number>>;
466
+ byOutcome: Partial<Record<VerificationOutcome, number>>;
467
+ needsAttention: {
468
+ stalled: number;
469
+ failedTechnical: number;
470
+ needsReview: number;
471
+ parkedMessages: number;
96
472
  };
97
- /** When the verification was created */
473
+ }
474
+ /** What kind of thing one history entry records. */
475
+ declare const PIPELINE_EVENT_KINDS: readonly ["CREATED", "STATUS_CHANGED", "REPROCESSED", "JOB_PARKED", "JOB_RESENT", "JOB_DISCARDED"];
476
+ type PipelineEventKind = (typeof PIPELINE_EVENT_KINDS)[number];
477
+ /**
478
+ * One entry in a verification's history, appended and never updated.
479
+ *
480
+ * The verification row keeps only the last decision, so this is the only place
481
+ * the sequence survives. Entries that predate the history simply do not exist —
482
+ * a verification from before it shows its creation and last decision and
483
+ * nothing between.
484
+ */
485
+ interface PipelineEvent {
486
+ id: string;
487
+ kind: PipelineEventKind | (string & {});
488
+ fromStatus: string | null;
489
+ toStatus: string | null;
490
+ /**
491
+ * Who did it, as a label frozen at the time — an operator's email, or
492
+ * "system". A snapshot, so it stays true after the person is renamed or
493
+ * removed.
494
+ */
495
+ actorLabel: string;
496
+ actorUserId: string | null;
497
+ /** The one thing worth reading beside the transition. */
498
+ detail: string | null;
499
+ createdAt: string;
500
+ [field: string]: unknown;
501
+ }
502
+ interface ReviewDecision {
503
+ decision: 'APPROVED' | 'REJECTED';
504
+ /** Stored when rejecting. */
505
+ reason?: string;
506
+ }
507
+ interface IdentityDocumentStep {
508
+ step: 'IDENTITY_DOCUMENT';
509
+ required: true;
510
+ documents: {
511
+ country: string;
512
+ types: string[];
513
+ }[];
514
+ }
515
+ interface SelfieStep {
516
+ step: 'SELFIE';
517
+ required: boolean;
518
+ /** Accepted but not enforced by the gateway yet. */
519
+ liveness?: boolean;
520
+ }
521
+ type VerificationLevelStep = IdentityDocumentStep | SelfieStep;
522
+ interface VerificationLevelDefinition {
523
+ requiredSteps: VerificationLevelStep[];
524
+ }
525
+ interface VerificationLevel {
526
+ id: string;
527
+ name: string;
528
+ isActive: boolean;
529
+ definition: VerificationLevelDefinition;
530
+ createdAt: string;
531
+ updatedAt: string;
532
+ }
533
+ interface IdentityFields {
534
+ mrz?: string;
535
+ gender?: string;
536
+ height?: number;
537
+ address?: string;
538
+ country?: string;
539
+ fullName?: string;
540
+ idNumber?: string;
541
+ birthDate?: string;
542
+ maritalStatus?: string;
543
+ }
544
+ interface IdentitySummary extends IdentityFields {
545
+ id: string;
546
+ createdAt: string;
547
+ updatedAt: string;
548
+ }
549
+ interface Identity extends IdentitySummary {
550
+ verifications?: VerificationListItem[];
551
+ [field: string]: unknown;
552
+ }
553
+ interface ListIdentitiesParams {
554
+ page?: number;
555
+ limit?: number;
556
+ /** Partial match. */
557
+ fullName?: string;
558
+ country?: string;
559
+ idNumber?: string;
560
+ }
561
+ /** Fields the gateway can group duplicate identities by. */
562
+ declare const DUPLICATE_FIELDS: readonly ["fullName", "idNumber", "mrz", "gender", "country", "birthDate"];
563
+ type DuplicateField = (typeof DUPLICATE_FIELDS)[number];
564
+ interface FaceCheck {
565
+ id: string;
566
+ status: 'PENDING' | 'APPROVED' | 'REJECTED';
567
+ }
568
+ type OcrProcessStatus = 'PENDING' | 'PROCESSING' | 'COMPLETED' | 'FAILED';
569
+ interface OcrProcess {
570
+ id: string;
571
+ status: OcrProcessStatus;
572
+ documentType: string;
573
+ country: string;
574
+ createdAt: string;
575
+ }
576
+ interface OcrProcessStatusResponse {
577
+ id: string;
578
+ status: OcrProcessStatus;
579
+ /** Present once COMPLETED. */
580
+ ocrResult?: OcrData;
581
+ documentPath?: string;
582
+ createdAt: string;
583
+ updatedAt: string;
584
+ }
585
+ declare const WEBHOOK_EVENT_TYPES: readonly ["VERIFICATION_STARTED", "VERIFICATION_COMPLETED", "VERIFICATION_APPROVED", "VERIFICATION_REJECTED", "VERIFICATION_REVIEW_REQUIRED", "OCR_COMPLETED", "OCR_FAILED"];
586
+ type WebhookEventType = (typeof WEBHOOK_EVENT_TYPES)[number];
587
+ /**
588
+ * Subscribes to every event, including ones added after the endpoint was
589
+ * registered. Prefer it over listing all seven when the intent is "mirror my
590
+ * verification lifecycle" — a literal list silently stops being complete.
591
+ */
592
+ declare const ALL_WEBHOOK_EVENTS = "*";
593
+ type WebhookSubscription = WebhookEventType | typeof ALL_WEBHOOK_EVENTS;
594
+ interface Webhook {
595
+ id: string;
596
+ url: string;
597
+ eventTypes: WebhookSubscription[];
598
+ isActive: boolean;
599
+ headers?: Record<string, string> | null;
600
+ maxRetries?: number | null;
98
601
  createdAt: string;
99
- /** When the verification was last updated */
100
602
  updatedAt: string;
101
603
  }
102
- /** Event emitted when KYC status changes */
103
- interface KYCStatusEvent {
104
- /** Type of event: statusChanged or error */
105
- type: 'statusChanged' | 'error';
106
- /** New status (for statusChanged events) */
107
- status?: string;
108
- /** Error message (for error events) */
109
- error?: string;
604
+ interface CreateWebhookParams {
605
+ /** Must be https:// with a public hostname — the gateway refuses anything else. */
606
+ url: string;
607
+ eventTypes: WebhookSubscription[];
608
+ headers?: Record<string, string>;
609
+ maxRetries?: number;
610
+ }
611
+ interface UpdateWebhookParams {
612
+ url?: string;
613
+ /** Replaces the current list entirely. */
614
+ eventTypes?: WebhookSubscription[];
615
+ isActive?: boolean;
616
+ headers?: Record<string, string>;
617
+ maxRetries?: number;
618
+ }
619
+ /**
620
+ * The result of replaying a delivery.
621
+ *
622
+ * A failed send is a value, not an exception: the gateway records a FAILED row
623
+ * for the attempt either way, so the caller almost always wants to show why
624
+ * beside the delivery it belongs to rather than catch around it.
625
+ */
626
+ type WebhookResendResult = {
627
+ success: true;
628
+ } | {
629
+ success: false;
630
+ error: string;
631
+ };
632
+ interface WebhookLogEntry {
633
+ id: string;
634
+ url: string;
635
+ status: string;
636
+ responseStatus?: number | null;
637
+ responseBody?: string | null;
638
+ payload?: Record<string, unknown>;
639
+ headers?: Record<string, string> | null;
640
+ retries?: number | null;
641
+ createdAt: string;
642
+ updatedAt: string;
643
+ [field: string]: unknown;
644
+ }
645
+ interface AnalyticsSeries {
646
+ change_percentage: number;
647
+ /** Keyed by month, e.g. "2026-07". */
648
+ monthly: Record<string, number>;
649
+ total: number;
650
+ }
651
+ interface Analytics {
652
+ identity: AnalyticsSeries;
653
+ verification: AnalyticsSeries;
654
+ }
655
+
656
+ /** Monthly identity and verification counts, with month-over-month change. */
657
+ declare class AnalyticsResource {
658
+ private readonly http;
659
+ constructor(http: HttpClient);
660
+ get(options?: {
661
+ signal?: AbortSignal;
662
+ }): Promise<Analytics>;
663
+ }
664
+
665
+ interface PollOptions {
666
+ /** Delay between attempts, in ms. Defaults to 3000. */
667
+ intervalMs?: number;
668
+ /** Give up after this long, in ms. Defaults to 120000. */
669
+ timeoutMs?: number;
670
+ /** Cancels the poll; the promise rejects with code ABORTED. */
671
+ signal?: AbortSignal;
672
+ }
673
+ interface PollCallbacks<T> {
674
+ /** Called with every intermediate value, before the done check. */
675
+ onUpdate?: (value: T) => void;
676
+ }
677
+ /**
678
+ * Calls `fetchOnce` until `isDone` accepts the result, the timeout elapses, or
679
+ * the caller aborts.
680
+ *
681
+ * Written as a loop with an awaited delay rather than a self-scheduling
682
+ * setTimeout so that a cancelled poll actually stops: the previous
683
+ * implementation left a pending timer behind after rejecting, which in React
684
+ * Native keeps the JS context awake and warns about a setState on an unmounted
685
+ * component.
686
+ *
687
+ * The timeout is checked before sleeping as well as after, so a poll never
688
+ * waits out one final interval it has no time left to use.
689
+ */
690
+ declare function pollUntil<T>(fetchOnce: (signal?: AbortSignal) => Promise<T>, isDone: (value: T) => boolean, options?: PollOptions & PollCallbacks<T>, description?: string): Promise<T>;
691
+
692
+ interface DuplicateGroup {
693
+ value: string;
694
+ count: number;
695
+ identities: IdentitySummary[];
696
+ }
697
+ interface DuplicatesByField {
698
+ field: string;
699
+ totalDuplicateGroups: number;
700
+ totalDuplicateIdentities: number;
701
+ duplicates: DuplicateGroup[];
702
+ }
703
+ interface DuplicatesByFields {
704
+ fields: string[];
705
+ results: Record<string, DuplicatesByField>;
110
706
  }
111
- /** Callback function for handling KYC status events */
112
- type KYCEventCallback = (event: KYCStatusEvent) => void;
113
707
  /**
114
- * Custom error class for KYC SDK errors
708
+ * The identity records behind verifications — the person, as opposed to any
709
+ * one attempt to verify them.
710
+ *
711
+ * Every endpoint here needs the project API key. A verification token is
712
+ * scoped to a single end user's flow and is refused, which is deliberate: an
713
+ * identity record holds the full extracted document data, and a client app has
714
+ * no business reading the project's identities.
115
715
  */
116
- declare class KYCSdkError extends Error {
117
- /** Error code for programmatic error handling */
118
- code: string;
119
- /** HTTP status code if available */
120
- statusCode?: number;
716
+ declare class IdentitiesResource {
717
+ private readonly http;
718
+ constructor(http: HttpClient);
719
+ /** Registers an identity independently of any verification. */
720
+ create(fields: IdentityFields, options?: {
721
+ signal?: AbortSignal;
722
+ }): Promise<Identity>;
723
+ /** A page of identity summaries. Read one identity for the full record. */
724
+ list(params?: ListIdentitiesParams, options?: {
725
+ signal?: AbortSignal;
726
+ }): Promise<Page<IdentitySummary>>;
727
+ /** The full record, including its verification history. */
728
+ get(id: string, options?: {
729
+ signal?: AbortSignal;
730
+ }): Promise<Identity>;
731
+ /** This identity's verifications, without embeddings or storage paths. */
732
+ verifications(id: string, options?: {
733
+ signal?: AbortSignal;
734
+ }): Promise<VerificationListItem[]>;
735
+ update(id: string, fields: IdentityFields, options?: {
736
+ signal?: AbortSignal;
737
+ }): Promise<Identity>;
738
+ /** Deletes the identity, its verifications, and the stored images. */
739
+ delete(id: string, options?: {
740
+ signal?: AbortSignal;
741
+ }): Promise<void>;
742
+ /**
743
+ * Groups identities that share a value, to find duplicate registrations.
744
+ *
745
+ * Passing one field returns a single grouping; passing several returns one
746
+ * per field, which is why the return type is a union.
747
+ */
748
+ findDuplicates(params?: {
749
+ field?: DuplicateField | DuplicateField[];
750
+ id?: string;
751
+ }, options?: {
752
+ signal?: AbortSignal;
753
+ }): Promise<DuplicatesByField | DuplicatesByFields>;
754
+ /**
755
+ * Folds duplicates into a primary identity, moving their verifications
756
+ * across and deleting them. Requires the admin role on a user token; an API
757
+ * key is a project credential and carries no role.
758
+ */
759
+ merge(id: string, duplicateIds: string[], options?: {
760
+ signal?: AbortSignal;
761
+ }): Promise<unknown>;
121
762
  /**
122
- * Creates a new KYC SDK error
123
- * @param message Human-readable error message
124
- * @param code Error code for handling
125
- * @param statusCode Optional HTTP status code
763
+ * Compares a fresh photo against the face already on file for an identity —
764
+ * a re-authentication check, separate from the verification flow.
765
+ *
766
+ * Asynchronous: the returned check starts PENDING. Poll it with
767
+ * `faceCheckStatus`, or use `waitForFaceCheck`.
126
768
  */
127
- constructor(message: string, code: string, statusCode?: number);
769
+ faceMatch(id: string, file: FileInput, options?: {
770
+ signal?: AbortSignal;
771
+ timeoutMs?: number;
772
+ }): Promise<FaceCheck>;
773
+ /** The result of a face-match check started with `faceMatch`. */
774
+ faceCheckStatus(id: string, faceCheckId: string, options?: {
775
+ signal?: AbortSignal;
776
+ }): Promise<FaceCheck>;
777
+ /** Polls a face-match check until it is APPROVED or REJECTED. */
778
+ waitForFaceCheck(id: string, faceCheckId: string, options?: PollOptions & PollCallbacks<FaceCheck>): Promise<FaceCheck>;
779
+ }
780
+
781
+ interface CreateLevelParams {
782
+ /** Unique within the project. */
783
+ name: string;
784
+ definition: VerificationLevelDefinition;
785
+ isActive?: boolean;
786
+ }
787
+ interface UpdateLevelParams {
788
+ name?: string;
789
+ /** Replaces the required steps entirely. */
790
+ definition?: VerificationLevelDefinition;
791
+ isActive?: boolean;
128
792
  }
129
793
  /**
130
- * Core KYC SDK client for interacting with the verification API
794
+ * Verification levels: named, reusable policies saying which steps a
795
+ * verification requires and which documents it accepts.
796
+ *
797
+ * Every verification names one at start time (`levelName`), and there is no
798
+ * default: a project can verify nobody until it has at least one active level,
799
+ * and a definition must include an IDENTITY_DOCUMENT step saying which
800
+ * (country, documentType) pairs it accepts.
801
+ *
802
+ * API key only, and creating or changing one needs the admin role when acting
803
+ * as a user. Deleting is a soft delete, so verifications that already ran keep
804
+ * the rules they ran under.
131
805
  */
132
- declare class KYCCore {
133
- private client;
134
- private credentials;
135
- private eventCallbacks;
806
+ declare class LevelsResource {
807
+ private readonly http;
808
+ constructor(http: HttpClient);
809
+ create(params: CreateLevelParams, options?: {
810
+ signal?: AbortSignal;
811
+ }): Promise<VerificationLevel>;
812
+ list(options?: {
813
+ signal?: AbortSignal;
814
+ }): Promise<VerificationLevel[]>;
815
+ get(id: string, options?: {
816
+ signal?: AbortSignal;
817
+ }): Promise<VerificationLevel>;
818
+ update(id: string, params: UpdateLevelParams, options?: {
819
+ signal?: AbortSignal;
820
+ }): Promise<VerificationLevel>;
821
+ delete(id: string, options?: {
822
+ signal?: AbortSignal;
823
+ }): Promise<void>;
824
+ }
825
+
826
+ interface DownloadToken {
827
+ token: string;
828
+ /** Lifetime in seconds. The gateway fixes it at 60. */
829
+ expiresIn: number;
830
+ }
831
+ /**
832
+ * Access to the images behind a verification: the selfie, both document pages,
833
+ * and the face the OCR worker cropped out of the document.
834
+ *
835
+ * Downloads are two calls on purpose. The first, authenticated with the project
836
+ * API key, issues a token for exactly one file; the second exchanges it for the
837
+ * bytes. The token lives 60 seconds, is invalidated the first time it is used,
838
+ * and every use is written to the gateway's media access log — so an image URL
839
+ * that leaks into a browser history, a screenshot or a support ticket is worth
840
+ * nothing by the time anyone finds it.
841
+ */
842
+ declare class MediaResourceApi {
843
+ private readonly http;
844
+ constructor(http: HttpClient);
845
+ /**
846
+ * Issues a single-use, 60-second token for one file of one verification.
847
+ *
848
+ * Useful on its own when the bytes should be fetched somewhere else — hand
849
+ * the token to a browser and let it call the download URL directly, without
850
+ * the API key ever leaving your server.
851
+ */
852
+ createDownloadToken(verificationId: string, resource: MediaResource, options?: {
853
+ signal?: AbortSignal;
854
+ }): Promise<DownloadToken>;
136
855
  /**
137
- * Creates a new KYC Core instance
138
- * @param credentials API credentials (apiKey and baseUrl)
856
+ * The URL that exchanges a download token for the file.
857
+ *
858
+ * Treat it as a credential: the token is the whole authorization, so the URL
859
+ * grants the image to whoever holds it, once.
139
860
  */
140
- constructor(credentials: KYCCredentials);
861
+ downloadUrl(token: string): string;
141
862
  /**
142
- * Registers a callback for KYC status events
143
- * @param callback Function to call when status changes
144
- * @returns Unsubscribe function to remove the callback
863
+ * Fetches a file, taking care of both steps.
864
+ *
865
+ * Returns the raw Response so a caller can stream it (to disk, or straight
866
+ * into an HTTP response) instead of holding an identity document in memory.
145
867
  */
146
- onEvent(callback: KYCEventCallback): () => void;
868
+ download(verificationId: string, resource: MediaResource, options?: {
869
+ signal?: AbortSignal;
870
+ }): Promise<Response>;
871
+ /** Fetches a file and buffers it. Convenient; holds the image in memory. */
872
+ downloadBytes(verificationId: string, resource: MediaResource, options?: {
873
+ signal?: AbortSignal;
874
+ }): Promise<Uint8Array>;
875
+ }
876
+
877
+ interface RunOcrParams {
878
+ documentType: DocumentType | (string & {});
879
+ country: CatalogCountry | (string & {});
880
+ /** Your own reference, for correlating the result. */
881
+ externalId?: string;
882
+ }
883
+ /**
884
+ * Standalone document reading, with no verification attached.
885
+ *
886
+ * The same OCR pipeline the verification flow uses, addressed directly: upload
887
+ * a document, get the structured fields back. Nothing is decided and no
888
+ * identity is created — for that, run a verification.
889
+ */
890
+ declare class OcrResource {
891
+ private readonly http;
892
+ constructor(http: HttpClient);
893
+ /**
894
+ * Queues a document for extraction.
895
+ *
896
+ * Returns as soon as the job is accepted; the fields arrive later, via
897
+ * `getStatus` or `waitForResult`.
898
+ */
899
+ run(file: FileInput, params: RunOcrParams, options?: {
900
+ signal?: AbortSignal;
901
+ timeoutMs?: number;
902
+ }): Promise<OcrProcess>;
903
+ /** Status of a queued job, with the extracted fields once COMPLETED. */
904
+ getStatus(ocrId: string, options?: {
905
+ signal?: AbortSignal;
906
+ }): Promise<OcrProcessStatusResponse>;
907
+ /** Polls until the job is COMPLETED or FAILED. */
908
+ waitForResult(ocrId: string, options?: PollOptions & PollCallbacks<OcrProcessStatusResponse>): Promise<OcrProcessStatusResponse>;
909
+ }
910
+
911
+ /**
912
+ * Pluggable key/value storage, so a verification that was interrupted can be
913
+ * picked up again after the app is closed.
914
+ *
915
+ * Inject AsyncStorage on React Native, or an adapter around localStorage on
916
+ * web. Methods may be synchronous or asynchronous; results are awaited either
917
+ * way.
918
+ */
919
+ interface KycirisStorage {
920
+ getItem(key: string): string | null | Promise<string | null>;
921
+ setItem(key: string, value: string): void | Promise<void>;
922
+ removeItem(key: string): void | Promise<void>;
923
+ }
924
+ /** Versioned, so a future change of shape cannot read an old record wrongly. */
925
+ declare const SESSION_STORAGE_KEY = "kyciris:session:v1";
926
+ /**
927
+ * What the SDK remembers about an in-flight verification.
928
+ *
929
+ * Deliberately holds no credential. The verification token is a bearer
930
+ * credential for one end user and persisting it would leave it in
931
+ * AsyncStorage/localStorage long after the flow ended, readable by anything
932
+ * else in the app; the host application decides where — and whether — to keep
933
+ * it. Only identifiers live here, and all of them are already known to the
934
+ * client that fetched them.
935
+ */
936
+ interface StoredSession {
937
+ verificationId: string;
938
+ identityId?: string;
939
+ externalId?: string;
940
+ documentType?: DocumentType | (string & {});
941
+ country?: CatalogCountry | (string & {});
942
+ levelName?: string;
943
+ /** ISO 8601 instant the verification was started. */
944
+ startedAt: string;
945
+ }
946
+ /**
947
+ * Reads and writes the resumable session.
948
+ *
949
+ * Every operation is best-effort: storage can be full, disabled (Safari private
950
+ * browsing), or simply absent. Losing the ability to resume is a degraded flow;
951
+ * throwing here would break a verification that is otherwise proceeding fine.
952
+ */
953
+ declare class SessionStore {
954
+ private readonly storage?;
955
+ constructor(storage?: KycirisStorage | undefined);
956
+ /** True when a storage adapter was configured. */
957
+ get enabled(): boolean;
958
+ save(session: StoredSession): Promise<void>;
959
+ read(): Promise<StoredSession | null>;
960
+ clear(): Promise<void>;
961
+ }
962
+ /**
963
+ * A storage adapter backed by a plain Map.
964
+ *
965
+ * For tests, and for a flow that should not outlive the process.
966
+ */
967
+ declare function createMemoryStorage(): KycirisStorage;
968
+
969
+ interface VerificationToken {
970
+ token: string;
971
+ /** The lifetime the gateway chose, e.g. "8h". The caller does not pick it. */
972
+ expiresIn: string;
973
+ }
974
+ interface AvailableMedia {
975
+ available: MediaResource[];
976
+ }
977
+ interface UploadOptions {
978
+ signal?: AbortSignal;
979
+ timeoutMs?: number;
980
+ }
981
+ interface VerificationProgress {
982
+ verificationId: string;
983
+ status: VerificationStatusResponse['status'];
984
+ outcome: VerificationStatusResponse['outcome'];
985
+ uploaded: Record<VerificationStep, boolean>;
986
+ /** The steps still to collect, in the order they should be asked for. */
987
+ missingSteps: VerificationStep[];
988
+ /** True when nothing is left to upload. */
989
+ isComplete: boolean;
990
+ }
991
+ interface ProgressOptions {
992
+ /**
993
+ * Whether the flow asks for a selfie. Defaults to true, matching the
994
+ * gateway's own default when no verification level is set.
995
+ *
996
+ * A client authenticated with a verification token cannot read the level it
997
+ * is running under — `/verification-levels` needs the project API key — so
998
+ * when a level makes the selfie optional, say so here.
999
+ */
1000
+ selfieRequired?: boolean;
1001
+ signal?: AbortSignal;
1002
+ }
1003
+ interface UploadStepParams {
1004
+ step: VerificationStep;
1005
+ file: FileInput;
1006
+ /** Defaults to the stored session's verification. */
1007
+ verificationId?: string;
1008
+ /** See ProgressOptions.selfieRequired. */
1009
+ selfieRequired?: boolean;
1010
+ signal?: AbortSignal;
1011
+ timeoutMs?: number;
1012
+ }
1013
+ interface UploadStepResult extends UploadResult {
1014
+ /** True when the step was already uploaded and nothing was sent. */
1015
+ skipped: boolean;
1016
+ }
1017
+ interface WaitForResultOptions extends PollOptions, PollCallbacks<VerificationStatusResponse> {
1018
+ /**
1019
+ * Whether REVIEW ends the wait. Defaults to true.
1020
+ *
1021
+ * REVIEW means the automated pipeline has finished and handed the
1022
+ * verification to a person, which can take hours. Polling through it almost
1023
+ * always ends in POLL_TIMEOUT; subscribe to the VERIFICATION_APPROVED /
1024
+ * VERIFICATION_REJECTED webhooks for the human's decision instead.
1025
+ */
1026
+ stopOnReview?: boolean;
1027
+ }
1028
+ /**
1029
+ * The end-user verification flow, plus the review and operations endpoints
1030
+ * that sit behind the project API key.
1031
+ *
1032
+ * Everything up to and including `getStatus` works with either credential; the
1033
+ * list, summary, history and decision calls are API-key only and say so.
1034
+ */
1035
+ declare class VerificationsResource {
1036
+ private readonly http;
1037
+ private readonly session;
1038
+ constructor(http: HttpClient, session: SessionStore);
147
1039
  /**
148
- * Emits a status event to all registered callbacks
149
- * @param event The event to emit
1040
+ * Mints a verification token for one end user.
1041
+ *
1042
+ * Call this on **your server**, with the project API key, and hand the token
1043
+ * to the client app. The token authorizes exactly the flow below (start,
1044
+ * upload, status) for the given `externalId` and nothing else, which is what
1045
+ * keeps the project-wide API key out of a bundle an end user can read.
1046
+ *
1047
+ * The gateway owns the lifetime (VERIFICATION_TOKEN_TTL, 8h by default) — a
1048
+ * client cannot ask for a longer one.
1049
+ *
1050
+ * @param externalId Your own reference for the end user
150
1051
  */
151
- private emitEvent;
1052
+ createToken(externalId: string, options?: {
1053
+ signal?: AbortSignal;
1054
+ }): Promise<VerificationToken>;
152
1055
  /**
153
- * Creates a verification token for secure API access
154
- * @param externalId External reference ID
155
- * @param expiry Token expiry in hours (default: 3)
156
- * @returns Object containing the token and its expiration time
1056
+ * Starts a verification and, when a storage adapter is configured, records
1057
+ * it so an interrupted flow can be resumed.
1058
+ *
1059
+ * The (country, documentType) pair and the level name are checked here before
1060
+ * the request goes out: the gateway rejects an unsupported pair with a 422
1061
+ * that names neither what is supported nor why, and a missing level with a
1062
+ * validation error that reads like a typo in your code rather than a policy
1063
+ * you have not created yet.
157
1064
  */
158
- createVerificationToken(externalId: string, expiry?: string): Promise<{
159
- token: string;
160
- expiresIn: string;
1065
+ start(params: StartVerificationParams, options?: {
1066
+ signal?: AbortSignal;
1067
+ }): Promise<VerificationSession>;
1068
+ /** Uploads the end user's selfie. Triggers face matching once OCR has run. */
1069
+ uploadSelfie(verificationId: string, file: FileInput, options?: UploadOptions): Promise<UploadResult>;
1070
+ /**
1071
+ * Uploads one side of the identity document.
1072
+ *
1073
+ * OCR is queued once both sides are present, so a flow that collects only
1074
+ * the front never starts processing.
1075
+ */
1076
+ uploadDocument(verificationId: string, side: DocumentSide, file: FileInput, options?: UploadOptions): Promise<UploadResult>;
1077
+ /** Current status, face-match score and extracted document data. */
1078
+ getStatus(verificationId: string, options?: {
1079
+ signal?: AbortSignal;
1080
+ }): Promise<VerificationStatusResponse>;
1081
+ /**
1082
+ * What the applicant still owes, and the verdict about the person.
1083
+ *
1084
+ * `getStatus` answers for one document. On a level asking for two, its
1085
+ * APPROVED is not the answer an integration wants -- the applicant may still
1086
+ * owe the other. This is the call that says which, through `outstanding`.
1087
+ *
1088
+ * Works with a verification token, which reports that token's own end-user
1089
+ * and ignores `externalId`, so an app needs no API key to drive a multi-
1090
+ * document flow.
1091
+ */
1092
+ applicant(params?: GetApplicantParams, options?: {
1093
+ signal?: AbortSignal;
1094
+ }): Promise<ApplicantStatus>;
1095
+ /**
1096
+ * Which files exist for a verification.
1097
+ *
1098
+ * This is the credential-safe way to tell what an end user has already
1099
+ * uploaded: it works with a verification token, whereas the identity record
1100
+ * that used to serve the same purpose is API-key only.
1101
+ */
1102
+ listMedia(verificationId: string, options?: {
1103
+ signal?: AbortSignal;
1104
+ }): Promise<MediaResource[]>;
1105
+ /**
1106
+ * Re-runs OCR and face matching from the files already uploaded.
1107
+ *
1108
+ * The remedy for a verification that failed technically (outcome
1109
+ * FAILED_TECHNICAL) or stalled. Clears the previous extraction and decision,
1110
+ * so it is not a read-only operation.
1111
+ *
1112
+ * Only the document front is required, which is why this also works for a
1113
+ * verification that never got as far as the selfie.
1114
+ */
1115
+ reanalyze(verificationId: string, options?: {
1116
+ signal?: AbortSignal;
1117
+ }): Promise<UploadResult>;
1118
+ /** The stored session, or null when there is none. */
1119
+ getSession(): Promise<StoredSession | null>;
1120
+ /**
1121
+ * Forgets the stored session. Call it once a verification is finished, so
1122
+ * the next one starts clean.
1123
+ */
1124
+ clearSession(): Promise<void>;
1125
+ /**
1126
+ * What the end user has uploaded and what is still missing.
1127
+ *
1128
+ * Derived from the files that actually exist server-side rather than from
1129
+ * anything the client remembers, so it is correct after a reinstall, on a
1130
+ * second device, or when a previous attempt failed mid-upload.
1131
+ */
1132
+ getProgress(verificationId?: string, options?: ProgressOptions): Promise<VerificationProgress>;
1133
+ /**
1134
+ * Uploads one step, skipping it when the file is already there.
1135
+ *
1136
+ * The call a resumable UI should make: it never re-sends a step the end user
1137
+ * already completed, which matters most on a retry after a dropped
1138
+ * connection, where the upload may well have succeeded.
1139
+ */
1140
+ uploadStep(params: UploadStepParams): Promise<UploadStepResult>;
1141
+ /**
1142
+ * Polls the status until the verification is decided.
1143
+ *
1144
+ * Stops at APPROVED, REJECTED and — unless `stopOnReview` is false — REVIEW.
1145
+ * For anything longer than a user is willing to watch a spinner, use the
1146
+ * webhooks: polling burns a request every few seconds and still gives up
1147
+ * after `timeoutMs`.
1148
+ */
1149
+ waitForResult(verificationId?: string, options?: WaitForResultOptions): Promise<VerificationStatusResponse>;
1150
+ private resolveVerificationId;
1151
+ /**
1152
+ * A page of the project's verifications, newest first.
1153
+ *
1154
+ * Carries no OCR data or storage paths by design — a 20-row page is not the
1155
+ * place for identity-document PII. Read one verification for those.
1156
+ */
1157
+ list(params?: ListVerificationsParams, options?: {
1158
+ signal?: AbortSignal;
1159
+ }): Promise<Page<VerificationListItem>>;
1160
+ /** Counts per status and outcome, plus what needs an operator's attention. */
1161
+ summary(options?: {
1162
+ signal?: AbortSignal;
1163
+ }): Promise<VerificationSummary>;
1164
+ /**
1165
+ * A verification's recorded history, oldest first.
1166
+ *
1167
+ * The verification row keeps only the last decision, so this is the only
1168
+ * place the sequence survives.
1169
+ */
1170
+ events(verificationId: string, options?: {
1171
+ signal?: AbortSignal;
1172
+ }): Promise<PipelineEvent[]>;
1173
+ /** Moves a PENDING verification to REVIEW so a person can look at it. */
1174
+ sendToReview(verificationId: string, options?: {
1175
+ signal?: AbortSignal;
1176
+ }): Promise<{
1177
+ verificationId: string;
1178
+ status: string;
1179
+ message?: string;
161
1180
  }>;
162
1181
  /**
163
- * Starts a new verification session
164
- * @param params Parameters including documentType, country, identityId, and externalId
165
- * @returns Verification session with verificationId and status
1182
+ * Records a reviewer's decision and fires the matching webhook.
1183
+ *
1184
+ * Repeating the decision a verification already has is refused with 409 —
1185
+ * that is the gateway making a second webhook impossible, not a transient
1186
+ * failure. Changing a decision (rejected in error, then approved) is allowed.
166
1187
  */
167
- startVerification(params: StartVerificationParams): Promise<VerificationSession>;
1188
+ decide(verificationId: string, decision: ReviewDecision, options?: {
1189
+ signal?: AbortSignal;
1190
+ }): Promise<{
1191
+ verificationId: string;
1192
+ status: string;
1193
+ }>;
1194
+ }
1195
+
1196
+ /**
1197
+ * Where the gateway sends verification events.
1198
+ *
1199
+ * Webhooks are the right way to learn a verification's outcome: polling costs
1200
+ * a request every few seconds and still gives up, while a REVIEW can sit with
1201
+ * a human for hours. Subscribe with `["*"]` when the intent is "mirror my
1202
+ * verification lifecycle" — a literal list of today's events silently stops
1203
+ * being complete the day an eighth one exists.
1204
+ *
1205
+ * The URL must be https with a public hostname; the gateway refuses anything
1206
+ * else, localhost included.
1207
+ */
1208
+ declare class WebhooksResource {
1209
+ private readonly http;
1210
+ constructor(http: HttpClient);
1211
+ create(params: CreateWebhookParams, options?: {
1212
+ signal?: AbortSignal;
1213
+ }): Promise<Webhook>;
1214
+ list(options?: {
1215
+ signal?: AbortSignal;
1216
+ }): Promise<Webhook[]>;
1217
+ get(id: string, options?: {
1218
+ signal?: AbortSignal;
1219
+ }): Promise<Webhook>;
1220
+ update(id: string, params: UpdateWebhookParams, options?: {
1221
+ signal?: AbortSignal;
1222
+ }): Promise<Webhook>;
1223
+ delete(id: string, options?: {
1224
+ signal?: AbortSignal;
1225
+ }): Promise<void>;
168
1226
  /**
169
- * Uploads a selfie image for face verification
170
- * @param params Parameters including verificationId, imageData, and optional mimeType
171
- * @returns Upload result with status
1227
+ * Delivery attempts, newest first — what was sent, what came back, how many
1228
+ * retries it took. The place to look when an endpoint stops receiving events.
172
1229
  */
173
- uploadSelfie(params: UploadSelfieParams): Promise<UploadResult>;
1230
+ logs(params?: {
1231
+ page?: number;
1232
+ limit?: number;
1233
+ }, options?: {
1234
+ signal?: AbortSignal;
1235
+ }): Promise<Page<WebhookLogEntry>>;
1236
+ /** One delivery attempt. */
1237
+ log(id: string, options?: {
1238
+ signal?: AbortSignal;
1239
+ }): Promise<WebhookLogEntry>;
174
1240
  /**
175
- * Uploads a document image (front or back)
176
- * @param params Parameters including verificationId, type, imageData, and optional mimeType
177
- * @returns Upload result with status
1241
+ * Sends a recorded delivery again, to the endpoint it originally went to.
1242
+ *
1243
+ * Synchronous: the result says whether it arrived this time. A failure comes
1244
+ * back as `{ success: false, error }` rather than throwing, because the
1245
+ * gateway has already written a FAILED row either way and the caller usually
1246
+ * wants to show the reason beside the delivery it belongs to. A missing
1247
+ * delivery (404) or a deleted endpoint (409) still throw -- those are not
1248
+ * outcomes of the send.
1249
+ *
1250
+ * Not retried: a resend that timed out may well have arrived.
178
1251
  */
179
- uploadDocument(params: UploadDocumentParams): Promise<UploadResult>;
1252
+ resendLog(id: string, options?: {
1253
+ signal?: AbortSignal;
1254
+ }): Promise<WebhookResendResult>;
1255
+ }
1256
+
1257
+ interface KycirisClientConfig extends HttpClientConfig {
180
1258
  /**
181
- * Gets the current status of a verification session
182
- * @param verificationId The verification ID to check
183
- * @returns Current verification status including OCR data and face match score
1259
+ * Where to remember an in-flight verification, so a flow interrupted by the
1260
+ * app closing can be resumed. AsyncStorage on React Native, an adapter around
1261
+ * localStorage on web. No credential is ever written to it.
184
1262
  */
185
- getStatus(verificationId: string): Promise<VerificationStatus>;
186
- faceMatchVerification(params: FaceMatchVerificationParams): Promise<any>;
187
- faceMatchStatus({ externalId, faceCheckId, interval, timeout, }: FaceMatchStatusParams): Promise<VerificationStatus>;
1263
+ storage?: KycirisStorage;
1264
+ }
1265
+ /**
1266
+ * The KYCiris API client.
1267
+ *
1268
+ * Two credentials, two audiences:
1269
+ *
1270
+ * - **`apiKey`** is the project's key. It reaches every endpoint, including
1271
+ * every identity in the project, and belongs on your server only.
1272
+ * - **`verificationToken`** is scoped to one end user and authorizes exactly
1273
+ * the verification flow. Mint it on your server with
1274
+ * `verifications.createToken(externalId)` and hand it to the client app.
1275
+ *
1276
+ * Constructing a client with `apiKey` inside a browser or React Native app
1277
+ * throws, because a key in a shipped bundle is a key the end user has.
1278
+ *
1279
+ * ```ts
1280
+ * // Your server
1281
+ * const server = createKycirisClient({ baseUrl, apiKey: process.env.KYCIRIS_API_KEY });
1282
+ * const { token } = await server.verifications.createToken('user-123');
1283
+ *
1284
+ * // Your app, with that token
1285
+ * const client = createKycirisClient({ baseUrl, verificationToken: token, storage });
1286
+ * const { verificationId } = await client.verifications.start({
1287
+ * country: 'AO',
1288
+ * documentType: 'ID_CARD',
1289
+ * });
1290
+ * ```
1291
+ */
1292
+ declare class KycirisClient {
1293
+ /** The end-user flow, plus review and operations reads. */
1294
+ readonly verifications: VerificationsResource;
1295
+ /** Identity records and re-authentication face checks. API key only. */
1296
+ readonly identities: IdentitiesResource;
1297
+ /** Verification levels (step policies). API key only. */
1298
+ readonly levels: LevelsResource;
1299
+ /** Single-use downloads of verification images. API key only. */
1300
+ readonly media: MediaResourceApi;
1301
+ /** Standalone document reading, outside the verification flow. */
1302
+ readonly ocr: OcrResource;
1303
+ /** Event subscriptions and their delivery log. API key only. */
1304
+ readonly webhooks: WebhooksResource;
1305
+ /** Monthly counts. API key only. */
1306
+ readonly analytics: AnalyticsResource;
1307
+ private readonly http;
1308
+ constructor(config: KycirisClientConfig);
188
1309
  /**
189
- * Polls for verification status until completion or timeout
190
- * @param verificationId The verification ID to check
191
- * @param interval Polling interval in milliseconds (default: 3000)
192
- * @param timeout Maximum time to wait in milliseconds (default: 120000)
193
- * @returns Final verification status when approved or rejected
1310
+ * Whether this client holds the project API key, and so can reach the
1311
+ * server-side endpoints.
1312
+ *
1313
+ * Worth checking in code that runs in both places, rather than letting a
1314
+ * MISSING_CREDENTIAL error be the way you find out.
194
1315
  */
195
- pollStatus(verificationId: string, interval?: number, timeout?: number): Promise<VerificationStatus>;
1316
+ get isServerSide(): boolean;
1317
+ }
1318
+ /** Creates a KYCiris client. See {@link KycirisClient}. */
1319
+ declare function createKycirisClient(config: KycirisClientConfig): KycirisClient;
1320
+
1321
+ /**
1322
+ * Every error the SDK throws is a KycirisError, so a caller can branch on
1323
+ * `code` instead of parsing messages.
1324
+ *
1325
+ * Codes come from two places. Gateway codes are the `error.code` value in the
1326
+ * API's error envelope (`{ error: { code, message, details }, meta }`) and are
1327
+ * kept in step with the gateway's own ERROR_CODE enum. SDK codes are raised
1328
+ * client-side, before or instead of a request.
1329
+ */
1330
+ /**
1331
+ * Error codes produced by the gateway itself.
1332
+ *
1333
+ * Mirrors `ERROR_CODE` in kyc-gateway (src/common/enums/error-codes.ts). Codes
1334
+ * the SDK does not recognise are still surfaced verbatim on `KycirisError.code`
1335
+ * — the list is for autocomplete and exhaustiveness, not for filtering.
1336
+ */
1337
+ declare const GATEWAY_ERROR_CODES: readonly ["INVALID_OCR_DATA", "OCR_EXTRACTION_ERROR", "DOCUMENT_EXPIRED", "INVALID_DOCUMENT_QUALITY", "FACE_MISMATCH", "LOW_FACE_MATCH_SCORE", "NO_FACE", "MANUAL_REJECTION", "BAD_PAYLOAD", "UNSUPPORTED_DOCUMENT", "BAD_IMAGE", "ACCOUNT_SUSPENDED", "VALIDATION_ERROR", "UNAUTHORIZED", "FORBIDDEN", "NOT_FOUND", "RESOURCE_ALREADY_EXISTS", "RATE_LIMIT_EXCEEDED", "INTERNAL_SERVER_ERROR"];
1338
+ type GatewayErrorCode = (typeof GATEWAY_ERROR_CODES)[number];
1339
+ /** Error codes raised by the SDK without (or before) a gateway response. */
1340
+ declare const SDK_ERROR_CODES: readonly ["CONFIG_ERROR", "CREDENTIAL_MISUSE", "MISSING_CREDENTIAL", "NETWORK_ERROR", "TIMEOUT", "ABORTED", "INVALID_RESPONSE", "INVALID_FILE", "POLL_TIMEOUT", "SESSION_NOT_FOUND"];
1341
+ type SdkErrorCode = (typeof SDK_ERROR_CODES)[number];
1342
+ /** Any code that can land on a KycirisError. Open-ended by design. */
1343
+ type KycirisErrorCode = GatewayErrorCode | SdkErrorCode | (string & {});
1344
+ interface KycirisErrorInit {
1345
+ code: KycirisErrorCode;
1346
+ /** HTTP status, when the error came from a response. */
1347
+ status?: number;
1348
+ /** `meta.requestId` from the response envelope — quote it in bug reports. */
1349
+ requestId?: string;
1350
+ /** `error.details` from the envelope, e.g. per-field validation failures. */
1351
+ details?: unknown;
1352
+ /** Whether retrying the same request could plausibly succeed. */
1353
+ retryable?: boolean;
1354
+ /** The underlying error, when this one wraps a lower-level failure. */
1355
+ cause?: unknown;
1356
+ }
1357
+ /**
1358
+ * The single error type the SDK throws.
1359
+ *
1360
+ * It deliberately carries no request/response objects: those hold the
1361
+ * Authorization and X-API-Key headers, and an error is the thing most likely to
1362
+ * be logged verbatim or shipped to an error tracker.
1363
+ */
1364
+ declare class KycirisError extends Error {
1365
+ readonly name = "KycirisError";
1366
+ readonly code: KycirisErrorCode;
1367
+ readonly status?: number;
1368
+ readonly requestId?: string;
1369
+ readonly details?: unknown;
1370
+ readonly retryable: boolean;
1371
+ constructor(message: string, init: KycirisErrorInit);
1372
+ /** True when this is a KycirisError, across bundle/realm boundaries. */
1373
+ static isKycirisError(value: unknown): value is KycirisError;
1374
+ }
1375
+ /** Convenience guard, equivalent to `KycirisError.isKycirisError`. */
1376
+ declare function isKycirisError(value: unknown): value is KycirisError;
1377
+ /**
1378
+ * HTTP statuses worth retrying: the request either never ran (429) or failed
1379
+ * for a reason that is plausibly momentary.
1380
+ */
1381
+ declare function isRetryableStatus(status: number): boolean;
1382
+
1383
+ /** Where the end user is in the flow. */
1384
+ type FlowPhase =
1385
+ /** Nothing started yet. */
1386
+ 'idle'
1387
+ /** Creating the verification. */
1388
+ | 'starting'
1389
+ /** Waiting for the user to supply the current step's image. */
1390
+ | 'collecting'
1391
+ /** Uploading an image. */
1392
+ | 'uploading'
1393
+ /** Everything submitted; the pipeline is deciding. */
1394
+ | 'processing'
1395
+ /** A decision was reached, or a human was asked for one. */
1396
+ | 'finished'
1397
+ /** The flow stopped on an error. `error` says which. */
1398
+ | 'failed';
1399
+ interface FlowState {
1400
+ phase: FlowPhase;
1401
+ verificationId: string | null;
1402
+ /** The step to ask the user for now, or null when none is outstanding. */
1403
+ currentStep: VerificationStep | null;
1404
+ /** Every step still to collect, in order. */
1405
+ missingSteps: VerificationStep[];
1406
+ uploaded: Record<VerificationStep, boolean>;
1407
+ status: VerificationStatus | null;
1408
+ outcome: VerificationOutcome | null;
1409
+ /** Why the pipeline stopped, when it did. */
1410
+ rejectionReason: string | null;
1411
+ error: KycirisError | null;
1412
+ /** True while a request is in flight, for disabling a capture button. */
1413
+ busy: boolean;
1414
+ }
1415
+ interface FlowOptions {
1416
+ country: CatalogCountry | (string & {});
1417
+ documentType: DocumentType | (string & {});
1418
+ /** Verification level to run under. Required: the gateway has no default. */
1419
+ levelName: string;
1420
+ /** Your reference for the user. Ignored when a verification token is used. */
1421
+ externalId?: string;
196
1422
  /**
197
- * Static factory method to create a KYC client instance
198
- * @param credentials API credentials (apiKey and baseUrl)
199
- * @returns Configured KYCCore instance
1423
+ * Whether the level asks for a selfie. Defaults to true.
1424
+ *
1425
+ * A client holding a verification token cannot read its own level, so a
1426
+ * document-only level has to be declared here.
200
1427
  */
201
- static createClient(credentials: KYCCredentials): KYCCore;
1428
+ selfieRequired?: boolean;
1429
+ /** Poll for the decision once everything is uploaded. Defaults to true. */
1430
+ waitForDecision?: boolean;
1431
+ /** How long to poll before giving up, in ms. Defaults to 120000. */
1432
+ decisionTimeoutMs?: number;
1433
+ /** Called on every state change. */
1434
+ onStateChange?: (state: FlowState) => void;
202
1435
  }
203
1436
  /**
204
- * Factory function to create a KYC client instance
205
- * @param credentials API credentials (apiKey and baseUrl)
206
- * @returns Configured KYCCore instance
1437
+ * The end-user verification flow as a state machine, with no UI attached.
1438
+ *
1439
+ * The React Native and web components are both thin wrappers around this, so
1440
+ * the sequencing — which step comes next, what a resumed flow skips, when the
1441
+ * decision is polled for — is written and tested once.
1442
+ *
1443
+ * Every transition is observable through `subscribe`, and every method is safe
1444
+ * to call from a button handler: failures land in `state.error` rather than
1445
+ * rejecting, so a component never has to wrap calls in try/catch.
1446
+ *
1447
+ * ```ts
1448
+ * const flow = new VerificationFlow(client, { country: 'AO', documentType: 'ID_CARD' });
1449
+ * flow.subscribe(render);
1450
+ * await flow.start();
1451
+ * // then, per captured image:
1452
+ * await flow.submit(image);
1453
+ * ```
207
1454
  */
208
- declare function createKYCClient(credentials: KYCCredentials): KYCCore;
1455
+ declare class VerificationFlow {
1456
+ private readonly client;
1457
+ private readonly options;
1458
+ private state;
1459
+ private listeners;
1460
+ private aborter;
1461
+ constructor(client: KycirisClient, options: FlowOptions);
1462
+ getState(): FlowState;
1463
+ /** Observes state changes. Returns an unsubscribe function. */
1464
+ subscribe(listener: (state: FlowState) => void): () => void;
1465
+ /**
1466
+ * Starts a verification, or picks up the one already in storage.
1467
+ *
1468
+ * Resuming is the default because it is almost always what the user wants:
1469
+ * an app killed between the document and the selfie should carry on, not
1470
+ * ask for the document again. Pass `{ fresh: true }` to start over.
1471
+ */
1472
+ start(options?: {
1473
+ fresh?: boolean;
1474
+ }): Promise<FlowState>;
1475
+ /**
1476
+ * Re-reads what the gateway holds.
1477
+ *
1478
+ * Worth calling when a component remounts, or after an upload whose response
1479
+ * never arrived: the file may well have landed, and this is what notices.
1480
+ */
1481
+ refresh(): Promise<FlowState>;
1482
+ /**
1483
+ * Uploads an image for the current step and advances.
1484
+ *
1485
+ * A step that turns out to be already uploaded is skipped rather than sent
1486
+ * again, so retrying after a dropped connection cannot duplicate work.
1487
+ */
1488
+ submit(file: FileInput): Promise<FlowState>;
1489
+ /**
1490
+ * Waits for the pipeline's decision.
1491
+ *
1492
+ * Called automatically once the last step is uploaded, unless
1493
+ * `waitForDecision` is false. Stops at REVIEW, which is a person's queue and
1494
+ * not something worth holding a spinner for.
1495
+ */
1496
+ waitForDecision(): Promise<FlowState>;
1497
+ /**
1498
+ * Cancels whatever is in flight.
1499
+ *
1500
+ * A component's unmount should call this, so a poll does not keep running
1501
+ * against a screen that is gone.
1502
+ */
1503
+ cancel(): void;
1504
+ /** Cancels, forgets the stored session, and returns to `idle`. */
1505
+ reset(): Promise<FlowState>;
1506
+ /**
1507
+ * Reads progress and derives the next phase from it.
1508
+ *
1509
+ * Returns a patch rather than applying one, so `guard` stays the single
1510
+ * place that publishes a state change.
1511
+ */
1512
+ private loadProgress;
1513
+ /**
1514
+ * Runs one transition: marks the flow busy, applies the resulting patch, and
1515
+ * turns any failure into `state.error` instead of a rejected promise.
1516
+ *
1517
+ * The awkward part it exists to contain is that reaching `processing` should
1518
+ * flow straight on into polling — but only when the caller asked for it, and
1519
+ * only once.
1520
+ */
1521
+ private guard;
1522
+ private fail;
1523
+ private patch;
1524
+ }
209
1525
 
210
- export { type FaceMatchStatusParams, type FaceMatchVerificationParams, KYCCore, type KYCCredentials, type KYCEventCallback, KYCSdkError, type KYCStatusEvent, type StartVerificationParams, type UploadDocumentParams, type UploadResult, type UploadSelfieParams, type VerificationSession, type VerificationStatus, createKYCClient };
1526
+ export { ALL_WEBHOOK_EVENTS, type Analytics, AnalyticsResource, type AnalyticsSeries, type ApiMeta, type ApiResult, type ApplicantAnswer, type ApplicantRejectType, type ApplicantRequirement, type ApplicantStatus, type AuthMode, type AvailableMedia, type CatalogCountry, type CreateLevelParams, type CreateWebhookParams, DOCUMENT_CATALOG, DUPLICATE_FIELDS, type DocumentCatalogEntry, type DocumentSide, type DocumentType, type DownloadToken, type DuplicateField, type DuplicateGroup, type DuplicatesByField, type DuplicatesByFields, type FaceCheck, type FetchLike, type FileInput, type FlowOptions, type FlowPhase, type FlowState, GATEWAY_ERROR_CODES, type GatewayErrorCode, type GetApplicantParams, HttpClient, type HttpClientConfig, IdentitiesResource, type Identity, type IdentityDocumentStep, type IdentityFields, type IdentitySummary, type ImageMimeType, KycirisClient, type KycirisClientConfig, KycirisError, type KycirisErrorCode, type KycirisErrorInit, type KycirisStorage, LevelsResource, type ListIdentitiesParams, type ListVerificationsParams, MAX_IMAGE_FILE_SIZE, type MediaResource, MediaResourceApi, type NormalizedFile, type OcrData, type OcrProcess, type OcrProcessStatus, type OcrProcessStatusResponse, OcrResource, PIPELINE_EVENT_KINDS, type Page, type PaginationMeta, type PipelineEvent, type PipelineEventKind, type PollCallbacks, type PollOptions, type ProgressOptions, type RequestOptions, type RequirementStatus, type ReviewDecision, type RunOcrParams, SDK_ERROR_CODES, SESSION_STORAGE_KEY, type SdkErrorCode, type SelfieStep, SessionStore, type StartVerificationParams, type StoredSession, TERMINAL_VERIFICATION_STATUSES, type UpdateLevelParams, type UpdateWebhookParams, type UploadOptions, type UploadResult, type UploadStepParams, type UploadStepResult, VERIFICATION_OUTCOMES, VERIFICATION_STATUSES, VerificationFlow, type VerificationLevel, type VerificationLevelDefinition, type VerificationLevelStep, type VerificationListItem, type VerificationOutcome, type VerificationProgress, type VerificationSession, type VerificationStatus, type VerificationStatusResponse, type VerificationStep, type VerificationSummary, type VerificationToken, type VerificationTokenProvider, VerificationsResource, WEBHOOK_EVENT_TYPES, type WaitForResultOptions, type Webhook, type WebhookEventType, type WebhookLogEntry, type WebhookResendResult, type WebhookSubscription, WebhooksResource, createKycirisClient, createMemoryStorage, decodeBase64, detectImageMimeType, encodeBase64, isKycirisError, isNormalizedFile, isReactNative, isRetryableStatus, isSupportedDocumentPair, isTerminalStatus, isUntrustedClient, normalizeFile, pollUntil, prepareFile, supportedCountries, supportedDocumentTypes, toPage };