SDK de JavaScript y TypeScript
@constaia/sdk: cliente oficial para Node.js 18+, Bun y Deno, sin dependencias. Análisis, lotes, webhooks, errores tipados y reintentos.
@constaia/sdk es el cliente oficial de Constaia para JavaScript y TypeScript. Usa fetch nativo, no tiene dependencias y trae los tipos incluidos.
npm i @constaia/sdk
# o: pnpm add @constaia/sdk · yarn add @constaia/sdk · bun add @constaia/sdkRequisitos: Node.js 18 o superior (o Bun, o Deno). Funciona en ESM y CommonJS.
Solo en tu servidor
Las claves ck_live_… y ck_test_… son secretas. Si el SDK detecta que se ejecuta en un navegador con una de ellas, lanza un error. Para subir documentos desde el navegador usa el widget, que envía el fichero a tu backend.
Configuración
import { Constaia } from "@constaia/sdk";
const constaia = new Constaia(); // lee CONSTAIA_API_KEY del entorno
// o con opciones explícitas
const constaia2 = new Constaia({
apiKey: process.env.CONSTAIA_API_KEY,
timeout: 60_000, // ms por intento (por defecto 60 000)
maxRetries: 2, // reintentos en 429, 5xx y errores de red (por defecto 2)
});
constaia.livemode; // true con ck_live_, false con ck_test_| Opción | Por defecto | Descripción |
|---|---|---|
apiKey | process.env.CONSTAIA_API_KEY | Tu clave secreta. |
baseUrl | https://api.constaia.com | Cambia la URL base (o usa CONSTAIA_BASE_URL). |
timeout | 60000 | Tiempo máximo por intento, en milisegundos. |
maxRetries | 2 | Reintentos automáticos. |
fetch | globalThis.fetch | Implementación de fetch propia (tests, proxies). |
defaultHeaders | {} | Cabeceras que se añaden a todas las peticiones. |
Analizar un documento
import { Constaia } from "@constaia/sdk";
import { fromPath } from "@constaia/sdk/node"; // solo Node, Bun y Deno
const constaia = new Constaia();
const analysis = await constaia.analyze(await fromPath("dni_valid.jpg"), {
expect: "es_dni",
checks: { notExpired: true, holder: { fullName: "María García López" } },
storage: "none",
language: "es",
});
analysis.verdict?.status; // "valid" | "invalid" | "review"
analysis.verdict?.reasons; // [{ code, severity, message }]
analysis.fields.document_number?.value; // "12345678Z"
analysis.warnings; // ["blurry", …]Entradas admitidas
| Entrada | Ejemplo |
|---|---|
| Ruta local (Node, Bun, Deno) | await fromPath("dni.jpg") |
File o Blob | el File de un FormData en tu route handler |
Buffer, Uint8Array, ArrayBuffer | constaia.analyze(buffer, { filename: "dni.jpg" }) |
ReadableStream | constaia.analyze(stream, { filename: "dni.pdf" }) |
| URL | constaia.analyze({ fileUrl: "https://…/dni.jpg" }) |
| Base64 | constaia.analyze({ base64, filename: "dni.jpg" }) |
Cuando la entrada no trae nombre (buffers, streams), pasa filename: la extensión sirve para deducir el tipo MIME.
Un string suelto no se acepta porque sería ambiguo: usa fromPath() para rutas o { fileUrl } para URLs.
Opciones en camelCase
El SDK usa camelCase y convierte a snake_case al enviar:
| SDK | API |
|---|---|
ttlHours | ttl_hours |
keepResults | keep_results |
checks.notExpired | checks.not_expired |
checks.referenceDate | checks.reference_date |
checks.maxAgeDays | checks.max_age_days |
checks.minAgeYears / maxAgeYears | checks.min_age_years / max_age_years |
checks.holder.fullName, firstName, lastName, documentNumber, birthDate | checks.holder.full_name, … |
checks.requireFields, requireSignature, requireStamp | checks.require_fields, … |
checks.expectedAmount, expectedIban, expectedReference | checks.expected_amount, … |
expect, extract, storage, async, export, metadata y language se llaman igual. Las claves de metadata y el esquema de extract se envían sin tocar.
La lista completa de opciones está en Analizar un documento.
Clasificar
const result = await constaia.classify(await fromPath("passport.jpg"), { expect: ["es_dni", "passport"] });
result.document.type; // "passport"
result.candidates; // [{ type, confidence }, …]
result.verdict?.status; // solo si pasas expectAnálisis guardados
const analysis = await constaia.analyses.get("an_01J…");
// Una página
const page = await constaia.analyses.list({ limit: 20, status: "completed", type: "es_dni" });
page.data; page.has_more;
// Todas las páginas: el SDK sigue el cursor por ti
for await (const a of constaia.analyses.list({ metadata: { registration_id: "123" } })) {
console.log(a.id);
}
const first100 = await constaia.analyses.list().toArray(100);
await constaia.analyses.delete("an_01J…"); // { id, deleted: true }
const res = await constaia.analyses.export("an_01J…", "xlsx"); // Response
const bytes = await res.arrayBuffer();Lotes
const batch = await constaia.batches.create({
files: [await fromPath("dni_valid.jpg"), await fromPath("nie.jpg")],
options: { expect: ["es_dni", "es_nie"], export: ["xlsx"] },
});
// o con URLs y opciones por documento
await constaia.batches.create({
items: [{ fileUrl: "https://example.com/1.jpg", options: { expect: "es_dni" } }],
});
await constaia.batches.get(batch.id);Ver Lotes.
Catálogo, saldo y uso
const types = await constaia.documentTypes.list(); // DocumentTypeInfo[]
const dni = await constaia.documentTypes.get("es_dni");
const balance = await constaia.balance(); // { credits_available, credits_reserved, … }
const usage = await constaia.usage({ from: "2026-09-01", to: "2026-09-30" });Webhooks
// Alta de endpoints
const endpoint = await constaia.webhookEndpoints.create({
url: "https://tuapp.example/webhooks/constaia",
events: ["analysis.completed", "analysis.failed"],
});
endpoint.secret; // whsec_… (solo en la creación)
// Verificación (Standard Webhooks, tolerancia de 5 minutos)
const event = await constaia.webhooks.verify(rawBody, request.headers, process.env.CONSTAIA_WEBHOOK_SECRET!);verifyWebhook y signWebhook también se exportan sueltas desde @constaia/sdk (la segunda sirve para firmar payloads en tus tests). Ejemplos completos para Next.js y Express en Webhooks.
Opciones por petición
Todos los métodos aceptan un último argumento con opciones de esa petición:
const controller = new AbortController();
await constaia.analyze(file, { expect: "es_dni" }, {
idempotencyKey: `registration-123-dni`, // si no la pasas, el SDK genera una
timeout: 90_000,
maxRetries: 0,
signal: controller.signal,
headers: { "X-Trace": "abc" },
});En cada POST el SDK envía una Idempotency-Key y la reutiliza en los reintentos, así que un reintento nunca cobra dos veces. Pasa la tuya si quieres que también sea segura entre procesos o reinicios. Ver Idempotencia.
Errores
Todos los errores heredan de ConstaiaError y exponen status, type, code, param, requestId y headers.
| Clase | Cuándo |
|---|---|
InvalidRequestError | 400/422: parámetros incorrectos, fichero no admitido… |
AuthenticationError | 401: clave ausente o incorrecta. |
PermissionError | 403: la clave no tiene permiso. |
NotFoundError | 404: el recurso no existe. |
InsufficientCreditsError | 402: no queda saldo. |
RateLimitError | 429 tras agotar reintentos. Incluye retryAfter (segundos). |
APIError | 5xx u otros errores del servidor. |
APIConnectionError | No se pudo conectar. |
APITimeoutError | Se superó el timeout (hereda de APIConnectionError). |
WebhookVerificationError | La firma de un webhook no es válida. |
import { InsufficientCreditsError, InvalidRequestError, RateLimitError } from "@constaia/sdk";
try {
await constaia.analyze(file, { expect: "es_dni" });
} catch (err) {
if (err instanceof InsufficientCreditsError) {
// avisa al administrador, compra un pack
} else if (err instanceof InvalidRequestError && err.code === "unsupported_file_type") {
// pide otro formato al usuario
} else if (err instanceof RateLimitError) {
console.log(`Reintenta en ${err.retryAfter} s`);
} else {
throw err;
}
}Reintentos
El SDK reintenta automáticamente (2 veces por defecto) las respuestas 408, 429 y 5xx y los errores de red, con espera exponencial. Si la API envía Retry-After, lo respeta (hasta 60 s). Configúralo con maxRetries en el cliente o por petición.
Tipos
Todos los tipos se exportan: Analysis, AnalyzeOptions, Checks, Verdict, ExtractedField, Classification, Batch, Balance, Usage, WebhookEvent, DocumentType… Las respuestas mantienen los nombres de la API en snake_case (analysis.created_at, balance.credits_available).
DocumentType, ReasonCode y WarningCode incluyen los valores conocidos pero admiten cualquier string, para que tu código no se rompa cuando se añadan tipos o códigos nuevos.
Siguiente paso
- Guía para Next.js y para Express.
- Modo test con los ficheros de ejemplo.