docvalidator-sdk
v0.2.0
Published
Cliente TypeScript/JavaScript para DocValidator v2 — validación documental automatizada con tipos de enriquecimiento RUES, Cédula/Registraduría y AML/SARLAFT.
Downloads
39
Maintainers
Readme
docvalidator-sdk
Official TypeScript / JavaScript client for DocValidator — the horizontal document-validation SaaS by Vértice Tech Group. Extract, validate and cross-check Colombian documents (cédula, RUT, bank statements, payslips, employment letters, bank references) via a single API call and receive an APROBADO / REVISIÓN / RECHAZADO decision at your webhook.
- ✅ Dual CJS + ESM · zero runtime dependencies · Node ≥ 18
- ✅ Fully typed request / response contracts, including v2.1 enrichment (RUES, Cédula/Registraduría, AML/SARLAFT)
- ✅ Timing-safe HMAC-SHA256 webhook verifier
- ✅ Ley 1581 de 2012 compliant (PII purged 72h after job completion)
Install
npm install docvalidator-sdkRequires Node.js 18+ (uses the global fetch).
Quickstart
import { DocValidatorClient, verifyWebhookSignature } from 'docvalidator-sdk';
const client = new DocValidatorClient({
apiKey: process.env.DOCVALIDATOR_API_KEY!,
baseUrl: 'https://docvalidator.verticetechgroup.com',
});
// 1 · Send a document for processing (async — default)
const { job_id } = await client.processDocument({
document_type: 'cedula',
document: 'https://your-bucket.example.com/cedula.pdf',
webhook_url: 'https://your-app.example.com/webhooks/docvalidator',
webhook_secret: process.env.DOCVALIDATOR_WEBHOOK_SECRET!, // ≥ 16 chars
process_mode: 'full', // 'full' (default) | 'extraction_only'
});
// 2 · When DocValidator finishes, it POSTs to your webhook_url.
// Verify the HMAC signature and consume the payload.Async by default; call with { responseMode: 'sync' } to block the request up to 60 s and receive the full PipelineResult in the response body.
Authentication
Every request is authenticated with the X-API-Key header. The SDK adds the header automatically.
- Sandbox key — provided free during 30-day pilots. Rate limits are tighter, cost tracking is on but not billed.
- Production key — issued after signing a plan (Starter USD 200 / Profesional USD 600 / Enterprise from USD 1,500 per month).
To rotate a key: request a new key from your account manager, deploy it, then ask us to revoke the old one. There is no self-service key rotation in the v2.1 API.
Base URLs
| Environment | Base URL |
|---|---|
| Production | https://docvalidator.verticetechgroup.com |
| Local dev (running DocValidator via docker-compose) | http://localhost:3000 |
Pass whichever fits your environment via the baseUrl option. The SDK does not hard-code production.
Client API
new DocValidatorClient(config)
interface DocValidatorClientConfig {
apiKey: string; // required
baseUrl?: string; // default: http://localhost:3000
timeoutMs?: number; // default: 60_000 (matches sync-mode server timeout)
fetchImpl?: typeof fetch; // inject a mock for tests
}client.processDocument(body, opts?)
POST /process — enqueue a document for extraction, validation, cross-validation and decision.
// Async — default. Returns { job_id, status: 'processing' } immediately.
const enqueued = await client.processDocument({
document_type: 'colilla_de_pago',
document: 'https://…/colilla.pdf', // URL or base64 string
webhook_url: 'https://your-app.example.com/hooks/docvalidator',
webhook_secret: 'a-secret-with-at-least-16-chars',
process_mode: 'full',
});
// Sync — blocks up to 60s and returns the full PipelineResult.
const result = await client.processDocument(
{ document_type: 'cedula', document: '…' },
{ responseMode: 'sync' },
);Accepted document_type values: cedula, rut, certificado_laboral, colilla_de_pago, extracto_bancario, referencia_bancaria.
Accepted document shapes:
- HTTPS URL DocValidator can fetch (recommended when the file is larger than ~1 MB).
- Base64-encoded file bytes (recommended for small files or when you cannot expose the file publicly).
client.getStatus(jobId)
GET /status/:job_id — fetch the current state of a job. Returns a fully-typed Job, including pii_purged (see PII purge behavior).
const job = await client.getStatus(job_id);
if (job.status === 'completed') {
console.log(job.decision, job.scoring_result?.final_score);
}client.listJobs(params?)
GET /jobs — list jobs for the tenant with pagination + status filter.
const page = await client.listJobs({ status: 'completed', limit: 50, offset: 0 });
for (const j of page.data) {
console.log(j.job_id, j.decision, j.processing_time_ms);
}Webhook verification
DocValidator signs every webhook with HMAC-SHA256 over the raw JSON body. The signature is delivered in the X-Webhook-Signature header, prefixed with sha256=.
import { verifyWebhookSignature } from 'docvalidator-sdk';
// Framework-agnostic pattern
function handleWebhook(rawBody: string, signatureHeader: string) {
const ok = verifyWebhookSignature(
rawBody, // ← the raw body string
signatureHeader, // ← "sha256=abc123…"
process.env.DOCVALIDATOR_WEBHOOK_SECRET!, // ← the secret you sent in POST /process
);
if (!ok) throw new Error('invalid webhook signature');
// Only now parse and act on the payload:
const payload = JSON.parse(rawBody);
return payload;
}⚠ Critical: pass the raw body string — not
JSON.stringify(req.body). Most Node frameworks parse and re-serialize the body, which changes byte order and breaks the signature. See the framework-specific guides linked below for the exact incantation.
The helper is timing-safe: it never short-circuits on prefix mismatch and rejects with false when lengths differ.
Enrichment (v0.2.0 — v2.1 API)
When your tenant has one or more external integrations enabled and you run in process_mode: 'full', the PipelineResult.enrichment block is populated with typed records:
import type { PipelineResult, EnrichmentResult } from 'docvalidator-sdk';
function summarize(result: PipelineResult) {
const e = result.enrichment;
if (!e) return 'no enrichment (integration disabled or extraction_only)';
// RUES — company registry (open data, always free)
if (e.rues_record) {
console.log('Razón social:', e.rues_record.razon_social);
console.log('Representante legal:', e.rues_record.representante_legal);
}
// Cédula — Registraduría (via Didit)
if (e.cedula_record) {
console.log('Estado:', e.cedula_record.cedula_status); // 'Vigente' | 'Fallecido'
console.log('Match:', e.cedula_record.match_type, e.cedula_record.match_score);
}
// AML / SARLAFT — 1,300+ restrictive lists
if (e.aml_result) {
console.log('Total hits:', e.aml_result.total_hits);
console.log('Filtered hits:', e.aml_result.filtered_hits.length);
for (const hit of e.aml_result.filtered_hits) {
console.log(hit.caption, hit.match_score, {
sanction: hit.is_sanction,
pep: hit.is_pep,
});
}
}
}Each enrichment field uses a three-state encoding:
| Value | Meaning |
|---|---|
| undefined (key absent) | Integration disabled for this tenant, or job ran in extraction_only mode |
| null | Integration enabled but every provider returned no data (alert path) |
| Typed record | Success |
Error handling
All API errors surface as DocValidatorApiError with .status, .code, and .details:
import { DocValidatorApiError } from 'docvalidator-sdk';
try {
await client.processDocument({ /* … */ });
} catch (err) {
if (err instanceof DocValidatorApiError) {
switch (err.status) {
case 401: /* wrong or missing API key */ break;
case 404: /* job or resource not found */ break;
case 429: /* rate limit — respect Retry-After */ break;
case 500:
case 502:
case 503: /* server-side, retry with backoff */ break;
}
console.error(err.code, err.message, err.details);
} else {
throw err; // network / timeout / unknown
}
}See docs/integration-guides/error-handling.md for a full retry-and-backoff cookbook.
PII purge behavior
DocValidator complies with Ley 1581 de 2012 (Colombian data protection law). 72 hours after a job completes:
- Original document binaries are deleted from storage.
- PII fields in
extraction_result(name, cédula number, DOB, account numbers) are replaced with the literal string"[PURGED]". - Enrichment PII (
RuesRecord.representante_legal,CedulaRecord.identification_number,AmlResult.screened_subject.full_name/date_of_birth/document_number) is replaced with"[PURGED]". - Non-PII enrichment fields survive intact (
razon_social,estado_matricula, RUESnit, AMLfiltered_hits— OFAC/PEP names are public). - The
Job.pii_purgedflag flips totrue;Job.pii_purged_atrecords the exact timestamp.
If you need long-term retention of PII on your side, persist your own copy when you receive the webhook. DocValidator does not offer a "hold-longer" option — the purge is unconditional.
Migrating from v0.1.0
v0.2.0 is fully backward-compatible with v0.1.0:
- All v0.1.0 methods behave identically.
- New:
EnrichmentResult,RuesRecord,CedulaRecord,AmlResult,AmlHit,ScreenedSubjecttypes. - New optional fields on
PipelineResult:enrichment,tokens_input,tokens_output.
No breaking changes. Just npm update docvalidator-sdk and pick up the new types.
Documentation
Full integration guides live in the docs/integration-guides/ folder of the DocValidator repository:
- Getting started — the first request from curl to production
- Node · Express, Node · NestJS, Node · Next.js — framework-specific patterns
- Python, PHP, Java · .NET — non-Node integrations
- Error handling — retry, backoff, circuit breaker behaviour
- Webhook security — HMAC deep-dive and raw-body pitfalls
- Sandbox vs production — URLs, quotas, migration checklist
- PII purge behavior — designing your archival around the 72h window
The full OpenAPI spec is served at https://docvalidator.verticetechgroup.com/api/docs.
Support
- Product questions and pilot requests:
[email protected] - Technical issues: file an issue in the DocValidator repository
- Security disclosures:
[email protected]
License
UNLICENSED — usage is governed by the DocValidator service agreement between Vértice Tech Group and the licensee. Contact [email protected] before using in production.
