Enlaces de verificación
Referencia de /v1/verification-links: crea una página alojada donde la persona sube sus documentos desde el móvil, recibe los resultados por webhook, callback o email y consulta, lista o cancela enlaces.
Un enlace de verificación es una página alojada por Constaia (url, con su código QR en qr_svg) donde la persona
acepta el consentimiento y sube cada documento que pides, con la cámara del móvil o desde un archivo. Cada subida es un
análisis normal en el modo de la clave (en live cobra créditos) y todos quedan en un expediente (dossier_id) con
un veredicto global.
Guía paso a paso con callback, email de resultados y vuelta a tu web: Crear enlaces por API y recibir los resultados.
| Método y ruta | Qué hace |
|---|---|
POST /v1/verification-links | Crea un enlace (y su expediente). |
GET /v1/verification-links | Lista los enlaces del modo de la clave. |
GET /v1/verification-links/{id} | Recupera uno, con qr_svg. |
DELETE /v1/verification-links/{id} | Lo cancela: la página deja de aceptar documentos. |
Todas las rutas usan una clave secreta (ck_test_… o ck_live_…) desde tu backend.
Crear un enlace
POST /v1/verification-links
Content-Type: application/json| Campo | Tipo | Defecto | Descripción |
|---|---|---|---|
template | string | null | — | Id de una plantilla de la cuenta (tpl_…). Sus opciones de análisis se aplican a cada documento. 422 template_not_found si no existe. |
documents | objeto[] (1–10) | — | Documentos que se piden, en orden. Cada uno: key (1–40 caracteres: letras, números, - o _, única), label (texto visible, hasta 120), expect (tipo o lista de tipos) y checks (como en analyze). Si falta y hay template, se pide uno (key: "document") con el expect de la plantilla. Sin documents ni template: 422 documents_required. |
reference | string | null | — | Tu referencia (hasta 200 caracteres). Sirve para filtrar el listado. |
metadata | objeto string → string | {} | Hasta 20 claves. Se copia al expediente y a cada análisis. |
expires_in_hours | entero 1–720 | 72 | Horas de validez. Al pasar, el enlace queda expired. |
locale | es | en | pt | fr | idioma de la plantilla o de la petición | Idioma de la página, de los emails y de los mensajes del expediente. |
notify_email | email | null | — | Envía el enlace por email a la persona, en locale. |
consent_text | string | null | el de la cuenta | Texto de consentimiento propio (hasta 2000 caracteres). |
show_result | boolean | el de la cuenta | Enseñar a la persona el resultado de cada documento. |
redirect_url | string https | null | — | A dónde vuelve la persona al terminar (botón en la pantalla final). |
redirect_with_status | boolean | false | Añade ?link_id=vl_…&status=<estado del enlace> a redirect_url. |
face_verification | { enabled, required? } | null | el de la plantilla | Paso Selfie tras los documentos (módulo opcional, cuentas del EEE con el anexo aceptado; si no, 403 face_verification_not_enabled). El enlace y el webhook llevan face_verification y face_match. Ver Verificación facial. |
callback_url | string https | null | — | Recibe un POST firmado con verification_link.completed y verification_link.expired. Debe ser https://; si no, 422 invalid_url (param: "callback_url"). |
include_results | boolean | true | Incluir results (el análisis de cada documento) en el webhook y el callback. false: solo el enlace y el veredicto del expediente. |
results_email | email | null | — | Email que recibe un resumen de los resultados cuando el enlace se completa, en locale. |
Los campos son estrictos: uno desconocido devuelve 422 invalid_parameter con su param.
curl https://api.constaia.com/v1/verification-links \
-H "Authorization: Bearer $CONSTAIA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"documents": [
{ "key": "id_card", "label": "DNI o NIE", "expect": ["es_dni", "es_nie"], "checks": { "min_age_years": 18 } },
{ "key": "receipt", "label": "Justificante de pago", "expect": "payment_receipt", "checks": { "expected_amount": 45 } }
],
"reference": "inscripcion-4821",
"metadata": { "registration_id": "4821" },
"locale": "es",
"callback_url": "https://example.com/constaia/callback",
"results_email": "secretaria@example.com",
"redirect_url": "https://example.com/inscripcion/4821",
"redirect_with_status": true
}'{
"id": "vl_01J9Z8Q3K4M5N6P7Q8R9S0T1V2",
"object": "verification_link",
"url": "https://app.constaia.com/v/3kqX…",
"qr_svg": "<svg xmlns=\"http://www.w3.org/2000/svg\" …</svg>",
"status": "pending",
"livemode": false,
"template": null,
"reference": "inscripcion-4821",
"metadata": { "registration_id": "4821" },
"documents": [
{
"key": "id_card",
"label": "DNI o NIE",
"expect": ["es_dni", "es_nie"],
"checks": { "min_age_years": 18 },
"status": "pending",
"analysis_id": null,
"attempts": 0,
"verdict_status": null,
"final_status": null,
"warnings": []
},
{ "key": "receipt", "label": "Justificante de pago", "…": "…" }
],
"dossier_id": "dos_01J9Z8Q3K4M5N6P7Q8R9S0T1V3",
"expires_at": "2026-10-03T10:00:00Z",
"redirect_url": "https://example.com/inscripcion/4821",
"redirect_with_status": true,
"callback_url": "https://example.com/constaia/callback",
"include_results": true,
"results_email": "secretaria@example.com",
"results_email_sent_at": null,
"locale": "es",
"notify_email": null,
"last_sent_at": null,
"show_result": false,
"consent_text": null,
"consent": null,
"events": [{ "type": "created", "at": "2026-09-30T10:00:00Z" }],
"created_at": "2026-09-30T10:00:00Z",
"completed_at": null,
"cancelled_at": null
}Envía url a la persona (o enséñale qr_svg). La URL lleva un token secreto: trátala como una credencial de un solo
uso y no la publiques.
El objeto verification_link
| Campo | Tipo | Descripción |
|---|---|---|
id | string | Prefijo vl_. |
url | string | Página que abre la persona. |
qr_svg | string | QR de url en SVG. Solo en la creación y en el GET individual. |
status | string | pending (nadie ha empezado), in_progress, completed, expired o cancelled. |
livemode | boolean | Modo de la clave con la que se creó. |
template, reference, metadata | Lo que indicaste al crearlo. | |
documents[] | objeto[] | Estado de cada documento: key, label, expect, checks, status (pending, processing, completed, failed), analysis_id (el análisis que cuenta), attempts, verdict_status, final_status (tras revisión humana) y warnings (avisos de calidad del último intento). |
dossier_id | string | null | Expediente con todos los documentos, el veredicto global y las comprobaciones cruzadas (mismo titular, fechas coherentes). |
expires_at | string ISO 8601 | Fin de la validez. |
redirect_url, redirect_with_status | Vuelta a tu web. | |
callback_url, include_results | Callback firmado al completarse o caducar. | |
results_email | string | null | Destinatario del resumen. |
results_email_sent_at | string | null | Cuándo se envió el resumen. |
locale | string | Idioma de la página y de los emails. |
notify_email, last_sent_at | A quién se envió el enlace por email y cuándo. | |
show_result, consent_text | Configuración de la página. | |
consent | objeto | null | Consentimiento aceptado: accepted_at, ip y text. |
events[] | objeto[] | Historial: type, at y, según el tipo, document_key o email. |
created_at, completed_at, cancelled_at | string | null | Fechas. |
Tipos de events[].type:
| Tipo | Cuándo |
|---|---|
created | Se crea el enlace. |
sent | Se envía el enlace por email (con email). |
opened | La persona abre la página por primera vez. |
consent_accepted | Acepta el consentimiento. |
document_uploaded | Sube un documento (con document_key). |
document_accepted | Un documento queda aceptado (con document_key). |
document_rejected | Un documento necesita repetirse, por ejemplo por una foto borrosa (con document_key). |
completed | Todos los documentos están terminados. |
expired | Pasa expires_at sin completarse. |
cancelled | Lo cancelas. |
results_sent | Se envía el resumen a results_email (con email). |
Cada documento admite hasta 5 intentos. Un documento con avisos de calidad que piden otra foto (y veredicto no válido) se puede repetir mientras queden intentos. El enlace se completa cuando todos los documentos están aceptados o sin intentos.
Resultados: webhook, callback y email
Cuando el enlace pasa a completed o expired recibes el mismo cuerpo por dos vías:
- Webhook global:
verification_link.completedyverification_link.expired, en los endpoints de webhook suscritos a esos eventos. - Callback del enlace: un
POSTacallback_url, firmado con Standard Webhooks y con los mismos reintentos.
data es el objeto verification_link (sin qr_svg) más:
| Campo | Descripción |
|---|---|
results[] | Solo si include_results es true. Uno por documento pedido, en orden: document_key, label y analysis (el objeto analysis que cuenta para ese documento, tal como se guardó: con mask_fields aplicado y sin file_url; null si no se subió). |
dossier | { id, verdict: { status, reasons: [{ code, severity, message }] } } del expediente, en el idioma del enlace, o null. status: complete_valid, incomplete, invalid o review. |
Con results_email se envía además un resumen sin datos de los documentos al completarse. Detalle de la firma, el
secreto, los reintentos, el cuerpo completo y el email en la
guía de resultados.
Listar enlaces
curl "https://api.constaia.com/v1/verification-links?status=completed&metadata[registration_id]=4821" \
-H "Authorization: Bearer $CONSTAIA_API_KEY"| Parámetro | Descripción |
|---|---|
limit | 1–100, por defecto 20. |
starting_after | Id del último enlace de la página anterior. Ver paginación. |
status | pending, in_progress, completed, expired o cancelled. |
reference | Tu referencia exacta. |
metadata[clave] | Filtra por un valor de metadata. |
Devuelve { "object": "list", "data": [...], "has_more": false, "url": "/v1/verification-links" }, solo con los enlaces
del modo de la clave y sin qr_svg.
Recuperar y cancelar
curl https://api.constaia.com/v1/verification-links/vl_01J9Z8Q3K4M5N6P7Q8R9S0T1V2 \
-H "Authorization: Bearer $CONSTAIA_API_KEY"
curl -X DELETE https://api.constaia.com/v1/verification-links/vl_01J9Z8Q3K4M5N6P7Q8R9S0T1V2 \
-H "Authorization: Bearer $CONSTAIA_API_KEY"DELETE devuelve el enlace con status: "cancelled"; cancelar uno ya cancelado lo devuelve igual. Un enlace
completado o caducado no se puede cancelar: 409 link_not_active. Un id que no existe en la cuenta devuelve
404 resource_missing.
Errores
| HTTP | code | Cuándo |
|---|---|---|
422 | invalid_parameter | Un campo no es válido (param indica cuál), por ejemplo redirect_url sin https://. |
422 | invalid_url | callback_url no es una URL https (param: "callback_url"). |
422 | documents_required | Ni documents ni template. |
422 | template_not_found | La plantilla no existe en la cuenta. |
409 | link_not_active | Cancelar un enlace completado o caducado. |
404 | resource_missing | El enlace no existe. |
Siguientes pasos
Resultados de vuelta
Callback firmado, email de resultados y vuelta a tu web, paso a paso.
Webhooks
Firma Standard Webhooks, reintentos y buenas prácticas.
Veredictos
Qué significa valid, invalid o review en cada documento.
Expedientes
El veredicto global y las comprobaciones cruzadas del enlace.
Plantillas
Las opciones de análisis del enlace, guardadas una sola vez.
Plantillas
Referencia de /v1/templates: guarda una configuración de verificación (expect, checks, almacenamiento, revisión humana, retención) y reutilízala con template en analyze, classify, lotes, enlaces, sesiones y expedientes.
Expedientes
Referencia de /v1/dossiers: agrupa varios documentos de una misma persona o trámite con requisitos, añade documentos por fichero o analysis_id y obtén un veredicto global con comprobaciones cruzadas de titular y fechas.