Empieza en 5 minutos
Crea una cuenta gratis, copia tu clave de test y valida tu primer DNI con curl, JavaScript o PHP en menos de cinco minutos.
En esta guía harás tres llamadas en modo test y verás los tres veredictos posibles: valid, invalid y review.
El modo test no consume créditos y responde siempre lo mismo para el mismo nombre de fichero, así que puedes
seguirla sin gastar nada.
Crea una cuenta gratis
Regístrate en app.constaia.com/signup. El plan gratis incluye 250 créditos al mes que se renuevan cada mes, sin tarjeta.
Copia tu clave de test
Al crear la cuenta se genera una clave de test. La encontrarás en Claves de API dentro del panel.
Empieza por ck_test_. Guárdala en una variable de entorno:
export CONSTAIA_API_KEY="ck_test_..."Las claves se muestran una sola vez. Si la pierdes, crea otra en el panel y revoca la anterior. Más en Autenticación.
Valida tu primer DNI
En modo test, la respuesta depende del nombre del fichero. Guarda cualquier imagen JPEG como
dni_valid.jpg y envíala indicando que esperas un DNI español:
curl https://api.constaia.com/v1/analyze \
-H "Authorization: Bearer $CONSTAIA_API_KEY" \
-F file=@dni_valid.jpg \
-F 'options={"expect":"es_dni"}'La respuesta completa tiene este aspecto:
{
"id": "an_01J…",
"object": "analysis",
"status": "completed",
"livemode": false,
"created_at": "2026-09-29T10:00:00Z",
"completed_at": "2026-09-29T10:00:02Z",
"file": { "name": "dni_valid.jpg", "mime_type": "image/jpeg", "pages": 2, "size_bytes": 482133 },
"document": { "type": "es_dni", "label": "DNI (España)", "confidence": 0.97, "side": "both", "country": "ESP" },
"verdict": {
"expected": ["es_dni"],
"match": true,
"status": "valid",
"reasons": [
{ "code": "type_match", "severity": "info", "message": "El documento es un DNI español." },
{ "code": "not_expired", "severity": "info", "message": "Vigente hasta el 12/03/2031." }
]
},
"fields": {
"document_number": { "value": "12345678Z", "confidence": 0.99, "validated": true, "source": { "page": 1, "bbox": [0.61, 0.12, 0.83, 0.16] } },
"first_name": { "value": "MARÍA", "confidence": 0.98, "validated": null, "source": { "page": 1, "bbox": [0.3, 0.2, 0.5, 0.24] } }
},
"checks": [
{ "code": "nif_check_digit", "passed": true, "message": "La letra del DNI es correcta." },
{ "code": "mrz_checksums", "passed": true, "message": "Los dígitos de control de la MRZ son correctos." },
{ "code": "mrz_matches_visual", "passed": true, "message": "La MRZ coincide con los datos impresos." }
],
"warnings": [],
"exports": {},
"storage": { "mode": "none", "file_deleted_at": "2026-09-29T10:00:02Z", "expires_at": null },
"usage": { "credits": 1, "pages": 2 },
"metadata": {}
}Lo importante:
verdict.statusesvalid: es un DNI y está vigente.fieldstrae los datos extraídos, cada uno con su confianza y la zona de la página de la que sale.checksson comprobaciones hechas en código (letra del NIF, MRZ), no opiniones del modelo.storage.file_deleted_atconfirma que el fichero ya se ha borrado.livemode: falseindica que es una respuesta de test: no se ha descontado nada de tu saldo.
Prueba un DNI caducado y una foto borrosa
Repite la llamada con dni_expired.jpg:
curl https://api.constaia.com/v1/analyze \
-H "Authorization: Bearer $CONSTAIA_API_KEY" \
-F file=@dni_expired.jpg \
-F 'options={"expect":"es_dni"}' | jq '.verdict'El tipo coincide, pero el documento está caducado, así que el veredicto es No válido
y entre los motivos aparece el código expired:
{
"expected": ["es_dni"],
"match": true,
"status": "invalid",
"reasons": [
{ "code": "type_match", "severity": "info", "message": "El documento es un DNI español." },
{ "code": "expired", "severity": "error", "message": "El documento está caducado." }
]
}Ahora con blurry.jpg:
curl https://api.constaia.com/v1/analyze \
-H "Authorization: Bearer $CONSTAIA_API_KEY" \
-F file=@blurry.jpg \
-F 'options={"expect":"es_dni"}' | jq '{status: .verdict.status, warnings: .warnings}'{ "status": "review", "warnings": ["blurry"] }La imagen no se puede leer con seguridad, así que Constaia no decide por ti: devuelve Revisar
y el aviso blurry. En tu aplicación, lo normal es pedir al usuario otra foto o pasar el caso a una persona.
Tienes la lista completa de ficheros de prueba en Modo test.
Hazlo desde tu código
El mismo flujo con los SDKs oficiales. En JavaScript las opciones van en camelCase; en PHP, en snake_case como en la API.
npm i @constaia/sdkimport { Constaia } from "@constaia/sdk";
import { fromPath } from "@constaia/sdk/node";
const constaia = new Constaia(); // lee CONSTAIA_API_KEY
for (const name of ["dni_valid.jpg", "dni_expired.jpg", "blurry.jpg"]) {
const analysis = await constaia.analyze(await fromPath(name), {
expect: "es_dni",
checks: { notExpired: true },
language: "es",
});
console.log(name, analysis.verdict?.status, analysis.warnings);
for (const reason of analysis.verdict?.reasons ?? []) {
console.log(` ${reason.code}: ${reason.message}`);
}
}Pasa a producción
Cuando tu integración funcione en test:
- Crea una clave
ck_live_en el panel. - Cámbiala en la variable de entorno de tu servidor. El código no cambia.
- Cada análisis consumirá créditos de tu plan gratis o de los packs que compres.
A partir de aquí, livemode será true y los documentos se analizan de verdad.
Siguientes pasos
Comprobaciones
Titular, edad, antigüedad del certificado, firma, sello, importe esperado…
Veredictos y motivos
Qué hacer con valid, invalid y review en tu lógica de negocio.
Almacenamiento y privacidad
Retención cero, TTL y qué se guarda de cada análisis.
Créditos y facturación
Cuánto cuesta cada análisis y cómo se descuenta.
Introducción
Constaia es una API europea que responde si un documento es el que esperas y si es válido, con motivos, campos extraídos y retención cero por defecto.
Autenticación
Cómo autenticar tus llamadas a la API de Constaia con claves Bearer, diferencias entre claves test y live, rotación y por qué nunca van al navegador.