@verifiquemos/sdk 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,24 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@verifiquemos/sdk` will be documented here.
4
+
5
+ ## [0.1.1] - 2026-05-25
6
+
7
+ Maintenance release — no changes to the public SDK API.
8
+
9
+ ## [0.1.0] - 2026-05-22
10
+
11
+ Initial public release. Supports:
12
+
13
+ - API key authentication (`x-api-key` header).
14
+ - Automatic `Idempotency-Key` (ULID, cryptographic random) on POST/PUT/PATCH/DELETE.
15
+ - Type-safe access to `auth.me`, `validations.{create,get,report}`, `credits.balance`, `apiKeys.list`.
16
+ - Error classes: `ApiError`, `RateLimitError`, `NetworkError`.
17
+ - Dual ESM + CJS builds. Tree-shakeable.
18
+
19
+ ### Known limitations
20
+
21
+ - Batch validation methods deferred to 0.2.0.
22
+ - Webhook signature verification helpers deferred (no webhooks yet on the API side).
23
+ - API keys CRUD currently exposes only `list()`; `create()` and `revoke()` deferred.
24
+ - No browser-side credential storage (intentional — keep API keys server-side).
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Verifiquemos
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,87 @@
1
+ # @verifiquemos/sdk
2
+
3
+ Official TypeScript SDK for the [Verifiquemos](https://verifiquemos.gt) compliance API.
4
+
5
+ > KYC, RENAP, OFAC, ONU, Lista Engel, PEP, CPE — for Guatemala-specific compliance, in one API call.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @verifiquemos/sdk
11
+ ```
12
+
13
+ ## Quickstart
14
+
15
+ ```typescript
16
+ import { VerifiquemosClient } from "@verifiquemos/sdk";
17
+
18
+ const client = new VerifiquemosClient({
19
+ apiKey: process.env.VERIFIQUEMOS_API_KEY!,
20
+ });
21
+
22
+ // Submit a validation
23
+ const created = await client.validations.create({
24
+ cui: "1234567890101",
25
+ naturalezaCliente: "individual",
26
+ paisOrigen: "GT",
27
+ dpiFront: dpiFrontBlob,
28
+ dpiBack: dpiBackBlob,
29
+ });
30
+
31
+ // Poll until done
32
+ let result;
33
+ while (true) {
34
+ result = await client.validations.get(created.id);
35
+ if (result?.status === "completed") break;
36
+ await new Promise((r) => setTimeout(r, 3000));
37
+ }
38
+
39
+ // Download the PDF report
40
+ const pdf = await client.validations.report(created.id);
41
+ ```
42
+
43
+ ## Error handling
44
+
45
+ ```typescript
46
+ import { ApiError, RateLimitError, NetworkError } from "@verifiquemos/sdk";
47
+
48
+ try {
49
+ await client.validations.create({ ... });
50
+ } catch (e) {
51
+ if (e instanceof RateLimitError) {
52
+ console.log(`Retry after ${e.retryAfterSeconds}s`);
53
+ } else if (e instanceof ApiError && e.isPaymentRequired()) {
54
+ console.log("Buy more credits");
55
+ } else if (e instanceof NetworkError) {
56
+ console.log("Connection failed");
57
+ } else {
58
+ throw e;
59
+ }
60
+ }
61
+ ```
62
+
63
+ ## Configuration
64
+
65
+ | Option | Default | Description |
66
+ |---|---|---|
67
+ | `apiKey` | (required) | Server-issued API key from your dashboard. Starts with `vfq_`. |
68
+ | `baseUrl` | `https://api.verifiquemos.gt` | Override for staging/dev. |
69
+ | `fetch` | `globalThis.fetch` | Inject your own (useful for testing). |
70
+ | `idempotencyKeyFactory` | ULID generator | Override the Idempotency-Key strategy. |
71
+
72
+ ## Versioning
73
+
74
+ The SDK follows semver. Major version bumps mirror major API contract changes; minor bumps add SDK methods or non-breaking API surface; patches are bugfixes.
75
+
76
+ ## Documentation
77
+
78
+ - API reference: <https://api.verifiquemos.gt/scalar>
79
+ - Developer portal: <https://verifiquemos.gt/developers>
80
+
81
+ ## Support
82
+
83
+ - Email: <soporte@verifiquemos.gt>
84
+
85
+ ## License
86
+
87
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,276 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ ApiError: () => ApiError,
34
+ NetworkError: () => NetworkError,
35
+ RateLimitError: () => RateLimitError,
36
+ VerifiquemosClient: () => VerifiquemosClient
37
+ });
38
+ module.exports = __toCommonJS(index_exports);
39
+
40
+ // src/client.ts
41
+ var import_openapi_fetch = __toESM(require("openapi-fetch"));
42
+
43
+ // src/errors.ts
44
+ var ApiError = class extends Error {
45
+ status;
46
+ body;
47
+ constructor(status, message, body) {
48
+ super(message);
49
+ this.name = "ApiError";
50
+ this.status = status;
51
+ this.body = body;
52
+ }
53
+ isUnauthorized() {
54
+ return this.status === 401;
55
+ }
56
+ isPaymentRequired() {
57
+ return this.status === 402;
58
+ }
59
+ isNotFound() {
60
+ return this.status === 404;
61
+ }
62
+ isServerError() {
63
+ return this.status >= 500 && this.status < 600;
64
+ }
65
+ };
66
+ var RateLimitError = class extends ApiError {
67
+ retryAfterSeconds;
68
+ constructor(retryAfterSeconds, body = null) {
69
+ super(429, "Rate limit exceeded", body);
70
+ this.name = "RateLimitError";
71
+ this.retryAfterSeconds = retryAfterSeconds;
72
+ }
73
+ };
74
+ var NetworkError = class extends Error {
75
+ cause;
76
+ constructor(message, cause) {
77
+ super(message);
78
+ this.name = "NetworkError";
79
+ this.cause = cause;
80
+ }
81
+ };
82
+
83
+ // src/client.ts
84
+ var ULID_ALPHABET = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
85
+ function generateUlid() {
86
+ const time = Date.now();
87
+ let timePart = "";
88
+ let t = time;
89
+ for (let i = 0; i < 10; i++) {
90
+ timePart = ULID_ALPHABET[t % 32] + timePart;
91
+ t = Math.floor(t / 32);
92
+ }
93
+ const buf = new Uint8Array(16);
94
+ globalThis.crypto.getRandomValues(buf);
95
+ let randPart = "";
96
+ for (let i = 0; i < 16; i++) {
97
+ randPart += ULID_ALPHABET[buf[i] % 32];
98
+ }
99
+ return timePart + randPart;
100
+ }
101
+ var VerifiquemosClient = class {
102
+ // C1 fix: private class field — not reachable via (client as any)._options
103
+ #apiKey;
104
+ #baseUrl;
105
+ #fetch;
106
+ #idempotencyKeyFactory;
107
+ #raw;
108
+ auth;
109
+ validations;
110
+ credits;
111
+ apiKeys;
112
+ constructor(opts) {
113
+ this.#apiKey = opts.apiKey;
114
+ this.#baseUrl = opts.baseUrl ?? "https://api.verifiquemos.gt";
115
+ this.#fetch = opts.fetch ?? globalThis.fetch.bind(globalThis);
116
+ this.#idempotencyKeyFactory = opts.idempotencyKeyFactory ?? generateUlid;
117
+ this.#raw = (0, import_openapi_fetch.default)({
118
+ baseUrl: this.#baseUrl,
119
+ fetch: (request) => this.wrappedFetch(request)
120
+ });
121
+ const deps = {
122
+ wrappedFetch: this.wrappedFetch.bind(this),
123
+ raw: this.#raw,
124
+ baseUrl: this.#baseUrl
125
+ };
126
+ this.auth = new AuthApi(deps);
127
+ this.validations = new ValidationsApi(deps);
128
+ this.credits = new CreditsApi(deps);
129
+ this.apiKeys = new ApiKeysApi(deps);
130
+ }
131
+ /**
132
+ * Internal: every request flows through here for header injection + error normalization.
133
+ * Accepts either a Request object (from openapi-fetch) or a URL + RequestInit (direct).
134
+ *
135
+ * @internal
136
+ */
137
+ async wrappedFetch(input, init) {
138
+ const isRequest = typeof Request !== "undefined" && input instanceof Request;
139
+ const url = isRequest ? input.url : typeof input === "string" ? input : input.toString();
140
+ const baseInit = isRequest ? {
141
+ method: input.method,
142
+ body: input.body,
143
+ headers: input.headers,
144
+ // Pass through credentials/mode/etc when present
145
+ credentials: input.credentials,
146
+ cache: input.cache,
147
+ redirect: input.redirect,
148
+ referrer: input.referrer,
149
+ integrity: input.integrity,
150
+ signal: input.signal
151
+ } : { ...init ?? {} };
152
+ const method = (baseInit.method ?? "GET").toUpperCase();
153
+ const headers = new Headers(baseInit.headers ?? void 0);
154
+ headers.set("x-api-key", this.#apiKey);
155
+ if (!headers.has("accept")) {
156
+ headers.set("accept", "application/json");
157
+ }
158
+ if (["POST", "PUT", "PATCH", "DELETE"].includes(method) && !headers.has("idempotency-key")) {
159
+ headers.set("idempotency-key", this.#idempotencyKeyFactory());
160
+ }
161
+ const finalInit = { ...baseInit, headers };
162
+ let response;
163
+ try {
164
+ response = await this.#fetch(url, finalInit);
165
+ } catch (e) {
166
+ throw new NetworkError("Network request failed", e instanceof Error ? e : void 0);
167
+ }
168
+ if (!response.ok) {
169
+ const body = await response.clone().json().catch(() => null);
170
+ if (response.status === 429) {
171
+ const raw = response.headers.get("retry-after") ?? "0";
172
+ const asNumber = Number(raw);
173
+ let retryAfter;
174
+ if (Number.isFinite(asNumber) && asNumber >= 0) {
175
+ retryAfter = asNumber;
176
+ } else {
177
+ const dateMs = new Date(raw).getTime();
178
+ retryAfter = Number.isFinite(dateMs) ? Math.max(0, Math.ceil((dateMs - Date.now()) / 1e3)) : 0;
179
+ }
180
+ throw new RateLimitError(retryAfter, body);
181
+ }
182
+ const detail = body && typeof body === "object" && body !== null && "detail" in body ? body.detail : null;
183
+ const message = typeof detail === "string" ? detail : response.statusText;
184
+ throw new ApiError(response.status, message, body);
185
+ }
186
+ return response;
187
+ }
188
+ };
189
+ var AuthApi = class {
190
+ constructor(deps) {
191
+ this.deps = deps;
192
+ }
193
+ deps;
194
+ async me() {
195
+ const { data } = await this.deps.raw.GET("/api/v1/auth/me");
196
+ return data;
197
+ }
198
+ };
199
+ var ValidationsApi = class {
200
+ constructor(deps) {
201
+ this.deps = deps;
202
+ }
203
+ deps;
204
+ /**
205
+ * Submit a new validation request.
206
+ *
207
+ * Note: `cui` (Guatemalan ID number) is NOT a form field — it is extracted
208
+ * automatically from the uploaded DPI image via OCR on the server side.
209
+ *
210
+ * @param input.naturalezaCliente - Client nature, e.g. "individual" or "juridica".
211
+ * @param input.paisOrigenFondos - Optional ISO-3166-1 alpha-2 country code for funds origin.
212
+ * @param input.dpiFile - DPI image blob (front side; OCR extracts the CUI).
213
+ */
214
+ // Fix #5 — C1: Correct multipart field names to match the real API.
215
+ // - Single dpi_file (not dpi_front + dpi_back)
216
+ // - pais_origen_fondos (not pais_origen)
217
+ // - No cui field (extracted via OCR on the server)
218
+ async create(input) {
219
+ const form = new FormData();
220
+ form.append("naturaleza_cliente", input.naturalezaCliente);
221
+ if (input.paisOrigenFondos) {
222
+ form.append("pais_origen_fondos", input.paisOrigenFondos);
223
+ }
224
+ form.append("dpi_file", input.dpiFile);
225
+ const response = await this.deps.wrappedFetch(
226
+ `${this.deps.baseUrl}/api/v1/validations`,
227
+ { method: "POST", body: form }
228
+ );
229
+ return await response.json();
230
+ }
231
+ async get(id) {
232
+ const { data } = await this.deps.raw.GET("/api/v1/validations/{validation_id}", {
233
+ params: { path: { validation_id: id } }
234
+ });
235
+ return data;
236
+ }
237
+ // Fix #4 — I4: Set accept:application/pdf so the server streams the PDF
238
+ // instead of attempting a JSON serialization.
239
+ async report(id) {
240
+ const response = await this.deps.wrappedFetch(
241
+ `${this.deps.baseUrl}/api/v1/validations/${id}/report`,
242
+ { method: "GET", headers: { accept: "application/pdf" } }
243
+ );
244
+ return await response.blob();
245
+ }
246
+ };
247
+ var CreditsApi = class {
248
+ constructor(deps) {
249
+ this.deps = deps;
250
+ }
251
+ deps;
252
+ async balance() {
253
+ const { data } = await this.deps.raw.GET("/api/v1/credits/balance");
254
+ return data;
255
+ }
256
+ };
257
+ var ApiKeysApi = class {
258
+ constructor(deps) {
259
+ this.deps = deps;
260
+ }
261
+ deps;
262
+ async list(tenantId) {
263
+ const { data } = await this.deps.raw.GET("/api/v1/tenants/{tenant_id}/api-keys", {
264
+ params: { path: { tenant_id: tenantId } }
265
+ });
266
+ return data;
267
+ }
268
+ };
269
+ // Annotate the CommonJS export names for ESM import in node:
270
+ 0 && (module.exports = {
271
+ ApiError,
272
+ NetworkError,
273
+ RateLimitError,
274
+ VerifiquemosClient
275
+ });
276
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/errors.ts"],"sourcesContent":["export { VerifiquemosClient } from \"./client\";\nexport type { VerifiquemosClientOptions } from \"./client\";\nexport { ApiError, NetworkError, RateLimitError } from \"./errors\";\nexport type * from \"./types\";\n","import createOpenapiClient from \"openapi-fetch\";\nimport type { paths } from \"./generated\";\nimport { ApiError, NetworkError, RateLimitError } from \"./errors\";\n\nconst ULID_ALPHABET = \"0123456789ABCDEFGHJKMNPQRSTVWXYZ\";\n\n// Fix #2 — I2: Use crypto.getRandomValues() instead of Math.random() for\n// cryptographic-quality randomness in idempotency keys.\nfunction generateUlid(): string {\n // Spec: 26-char Crockford Base32. Top 10 chars are timestamp (ms since epoch).\n // Bottom 16 chars are randomness.\n const time = Date.now();\n let timePart = \"\";\n let t = time;\n for (let i = 0; i < 10; i++) {\n timePart = ULID_ALPHABET[t % 32]! + timePart;\n t = Math.floor(t / 32);\n }\n const buf = new Uint8Array(16);\n // globalThis.crypto is available in Node >= 20 and all modern browsers.\n globalThis.crypto.getRandomValues(buf);\n let randPart = \"\";\n for (let i = 0; i < 16; i++) {\n randPart += ULID_ALPHABET[buf[i]! % 32]!;\n }\n return timePart + randPart;\n}\n\nexport interface VerifiquemosClientOptions {\n apiKey: string;\n baseUrl?: string;\n fetch?: typeof fetch;\n /** Override the default Idempotency-Key generator. */\n idempotencyKeyFactory?: () => string;\n}\n\n// Fix #1 — C1: Sub-API classes receive only the wrappedFetch closure and\n// baseUrl (both non-sensitive). The openapi-fetch raw client is also passed\n// so sub-APIs can use typed path helpers. The API key is stored only in a\n// class-private field (#apiKey) and is never exposed on the public surface.\n\n/** Internal bundle passed to sub-API classes; not part of the public API. */\ninterface SubApiDeps {\n wrappedFetch: VerifiquemosClient[\"wrappedFetch\"];\n raw: ReturnType<typeof createOpenapiClient<paths>>;\n baseUrl: string;\n}\n\nexport class VerifiquemosClient {\n // C1 fix: private class field — not reachable via (client as any)._options\n #apiKey: string;\n #baseUrl: string;\n #fetch: typeof fetch;\n #idempotencyKeyFactory: () => string;\n #raw: ReturnType<typeof createOpenapiClient<paths>>;\n\n readonly auth: AuthApi;\n readonly validations: ValidationsApi;\n readonly credits: CreditsApi;\n readonly apiKeys: ApiKeysApi;\n\n constructor(opts: VerifiquemosClientOptions) {\n this.#apiKey = opts.apiKey;\n this.#baseUrl = opts.baseUrl ?? \"https://api.verifiquemos.gt\";\n this.#fetch = opts.fetch ?? globalThis.fetch.bind(globalThis);\n this.#idempotencyKeyFactory = opts.idempotencyKeyFactory ?? generateUlid;\n\n this.#raw = createOpenapiClient<paths>({\n baseUrl: this.#baseUrl,\n fetch: (request: Request) => this.wrappedFetch(request),\n });\n\n const deps: SubApiDeps = {\n wrappedFetch: this.wrappedFetch.bind(this),\n raw: this.#raw,\n baseUrl: this.#baseUrl,\n };\n\n this.auth = new AuthApi(deps);\n this.validations = new ValidationsApi(deps);\n this.credits = new CreditsApi(deps);\n this.apiKeys = new ApiKeysApi(deps);\n }\n\n /**\n * Internal: every request flows through here for header injection + error normalization.\n * Accepts either a Request object (from openapi-fetch) or a URL + RequestInit (direct).\n *\n * @internal\n */\n async wrappedFetch(input: Request | string | URL, init?: RequestInit): Promise<Response> {\n const isRequest = typeof Request !== \"undefined\" && input instanceof Request;\n const url = isRequest ? input.url : typeof input === \"string\" ? input : input.toString();\n const baseInit: RequestInit = isRequest\n ? {\n method: input.method,\n body: input.body,\n headers: input.headers,\n // Pass through credentials/mode/etc when present\n credentials: input.credentials,\n cache: input.cache,\n redirect: input.redirect,\n referrer: input.referrer,\n integrity: input.integrity,\n signal: input.signal,\n }\n : { ...(init ?? {}) };\n\n const method = (baseInit.method ?? \"GET\").toUpperCase();\n const headers = new Headers(baseInit.headers ?? undefined);\n headers.set(\"x-api-key\", this.#apiKey);\n // Fix #4 — I4: Only set default accept if caller hasn't already set one\n // (e.g. validations.report() sets accept:application/pdf).\n if (!headers.has(\"accept\")) {\n headers.set(\"accept\", \"application/json\");\n }\n if ([\"POST\", \"PUT\", \"PATCH\", \"DELETE\"].includes(method) && !headers.has(\"idempotency-key\")) {\n headers.set(\"idempotency-key\", this.#idempotencyKeyFactory());\n }\n\n const finalInit: RequestInit = { ...baseInit, headers };\n\n let response: Response;\n try {\n response = await this.#fetch(url, finalInit);\n } catch (e) {\n throw new NetworkError(\"Network request failed\", e instanceof Error ? e : undefined);\n }\n\n if (!response.ok) {\n const body = await response.clone().json().catch(() => null);\n if (response.status === 429) {\n // Fix #3 — I1: Defensive retry-after parsing — handle both numeric\n // seconds (RFC 6585 §4) and HTTP-date format (RFC 7231 §7.1.3).\n const raw = response.headers.get(\"retry-after\") ?? \"0\";\n const asNumber = Number(raw);\n let retryAfter: number;\n if (Number.isFinite(asNumber) && asNumber >= 0) {\n retryAfter = asNumber;\n } else {\n const dateMs = new Date(raw).getTime();\n retryAfter = Number.isFinite(dateMs)\n ? Math.max(0, Math.ceil((dateMs - Date.now()) / 1000))\n : 0;\n }\n throw new RateLimitError(retryAfter, body);\n }\n const detail =\n body && typeof body === \"object\" && body !== null && \"detail\" in body\n ? (body as { detail: unknown }).detail\n : null;\n const message = typeof detail === \"string\" ? detail : response.statusText;\n throw new ApiError(response.status, message, body);\n }\n\n return response;\n }\n}\n\nclass AuthApi {\n constructor(private readonly deps: SubApiDeps) {}\n\n async me() {\n const { data } = await this.deps.raw.GET(\"/api/v1/auth/me\");\n return data;\n }\n}\n\nclass ValidationsApi {\n constructor(private readonly deps: SubApiDeps) {}\n\n /**\n * Submit a new validation request.\n *\n * Note: `cui` (Guatemalan ID number) is NOT a form field — it is extracted\n * automatically from the uploaded DPI image via OCR on the server side.\n *\n * @param input.naturalezaCliente - Client nature, e.g. \"individual\" or \"juridica\".\n * @param input.paisOrigenFondos - Optional ISO-3166-1 alpha-2 country code for funds origin.\n * @param input.dpiFile - DPI image blob (front side; OCR extracts the CUI).\n */\n // Fix #5 — C1: Correct multipart field names to match the real API.\n // - Single dpi_file (not dpi_front + dpi_back)\n // - pais_origen_fondos (not pais_origen)\n // - No cui field (extracted via OCR on the server)\n async create(input: {\n naturalezaCliente: string;\n paisOrigenFondos?: string;\n dpiFile: Blob;\n }): Promise<{ id: string; status: string }> {\n const form = new FormData();\n form.append(\"naturaleza_cliente\", input.naturalezaCliente);\n if (input.paisOrigenFondos) {\n form.append(\"pais_origen_fondos\", input.paisOrigenFondos);\n }\n form.append(\"dpi_file\", input.dpiFile);\n\n // openapi-fetch's multipart support is limited; use wrappedFetch directly.\n const response = await this.deps.wrappedFetch(\n `${this.deps.baseUrl}/api/v1/validations`,\n { method: \"POST\", body: form },\n );\n return (await response.json()) as { id: string; status: string };\n }\n\n async get(id: string) {\n const { data } = await this.deps.raw.GET(\"/api/v1/validations/{validation_id}\", {\n params: { path: { validation_id: id } },\n });\n return data;\n }\n\n // Fix #4 — I4: Set accept:application/pdf so the server streams the PDF\n // instead of attempting a JSON serialization.\n async report(id: string): Promise<Blob> {\n const response = await this.deps.wrappedFetch(\n `${this.deps.baseUrl}/api/v1/validations/${id}/report`,\n { method: \"GET\", headers: { accept: \"application/pdf\" } },\n );\n return await response.blob();\n }\n}\n\nclass CreditsApi {\n constructor(private readonly deps: SubApiDeps) {}\n\n async balance() {\n const { data } = await this.deps.raw.GET(\"/api/v1/credits/balance\");\n return data;\n }\n}\n\nclass ApiKeysApi {\n constructor(private readonly deps: SubApiDeps) {}\n\n async list(tenantId: string) {\n const { data } = await this.deps.raw.GET(\"/api/v1/tenants/{tenant_id}/api-keys\", {\n params: { path: { tenant_id: tenantId } },\n });\n return data;\n }\n}\n","/**\n * Errors thrown by the Verifiquemos SDK.\n *\n * `ApiError` is thrown for any HTTP 4xx/5xx response from the API.\n * `RateLimitError` is a specialization for 429 responses.\n * `NetworkError` wraps transport failures (DNS, timeout, connection reset).\n */\n\nexport class ApiError extends Error {\n readonly status: number;\n readonly body: unknown;\n\n constructor(status: number, message: string, body: unknown) {\n super(message);\n this.name = \"ApiError\";\n this.status = status;\n this.body = body;\n }\n\n isUnauthorized(): boolean {\n return this.status === 401;\n }\n\n isPaymentRequired(): boolean {\n return this.status === 402;\n }\n\n isNotFound(): boolean {\n return this.status === 404;\n }\n\n isServerError(): boolean {\n return this.status >= 500 && this.status < 600;\n }\n}\n\nexport class RateLimitError extends ApiError {\n readonly retryAfterSeconds: number;\n\n constructor(retryAfterSeconds: number, body: unknown = null) {\n super(429, \"Rate limit exceeded\", body);\n this.name = \"RateLimitError\";\n this.retryAfterSeconds = retryAfterSeconds;\n }\n}\n\nexport class NetworkError extends Error {\n override readonly cause?: Error;\n\n constructor(message: string, cause?: Error) {\n super(message);\n this.name = \"NetworkError\";\n this.cause = cause;\n }\n}\n"],"mappings":"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","names":["createOpenapiClient"]}