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