Una sesión de verificación es una corrida del flujo de un proyecto para una persona. Se crea desde tu backend, la completa la persona en su celular y termina en un estado terminal con un veredicto.
El objeto sesión
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
id | string | siempre | Id de la sesión, vs_…. |
object | string | siempre | Constante "verification_session". |
status | enum | siempre | Estado del ciclo de vida. Ver la tabla de abajo. |
mode | enum | siempre | "live" o "test", según la clave con la que se creó. |
project_id | string | siempre | Proyecto al que pertenece, prj_…. |
config_version | string | siempre | Versión del flujo congelada al crear la sesión, cfg_00000003. |
created_at | string | siempre | ISO 8601 UTC. |
url | string | sólo al crear | Link del flujo para la persona. Irrecuperable después de la respuesta de creación. |
qr | object | sólo al crear | Objeto con svg y png: URLs públicas del QR de ese link. |
expires_at | string | sólo al crear | Cuándo vence el link. |
external_ref | string | si se envió | Eco de tu referencia externa. Viaja también en los webhooks. |
metadata | object | si se envió | Eco de la metadata enviada al crear. Ver la nota de abajo. |
result | object | si hay resolución | Veredicto de la sesión. Aparece cuando el estado ya no es pending ni in_progress. |
completed_at | string | si es terminal | Cuándo quedó en estado terminal. |
Estados
| Campo | Tipo | Terminal | Descripción |
|---|---|---|---|
pending | Creada | no | El link existe pero todavía nadie lo abrió. |
in_progress | En curso | no | La persona está completando el flujo. |
needs_review | En revisión | no | El flujo terminó pero la decisión quedó para revisión humana. |
approved | Aprobada | sí | Verificación exitosa. |
rejected | Rechazada | sí | Verificación fallida. Los motivos están en result.reason_codes. |
expired | Vencida | sí | El link venció sin que la persona terminara. |
abandoned | Abandonada | sí | La persona empezó y dejó el flujo inactivo más allá del tiempo permitido. |
canceled | Cancelada | sí | Cancelada por vos con el endpoint de cancelación. |
Los estados terminales son inmutables: una sesión aprobada no vuelve a cambiar.
El objeto result
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
outcome | enum | siempre | approved, rejected, review_required, expired, abandoned o canceled. Es la traducción pública de status: needs_review se publica como review_required. |
reason_codes | string[] | siempre | Motivos del veredicto, ordenados de más a menos severo. Array vacío en una aprobación limpia. Ver Reason codes. |
steps | object[] | siempre | Un item por paso ejecutado: { id, type, verdict }. verdict es approved, rejected, review o retryable. |
Crear una sesión
Cuerpo
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
project_id | string | sí | Proyecto a usar, prj_…. Tiene que tener una configuración publicada en el modo de tu clave. |
external_ref | string | no | Tu identificador de correlación (id del cliente, número de trámite). De 1 a 255 caracteres. Vuelve en la respuesta y en los webhooks. |
expires_in_hours | number | no | Vigencia del link, entre 0.25 (15 minutos) y 168 (7 días). Si no lo mandás rige el valor del proyecto (por defecto 24 h). |
prefill | object | no | { email?, phone? }. El teléfono va en E.164 (+5491122334455). Ver la advertencia de abajo. |
metadata | object | no | Diccionario de strings: hasta 20 claves de 1 a 64 caracteres, con valores de hasta 500. Ver la advertencia de abajo. |
El cuerpo es estricto: un campo que no esté en esta tabla devuelve 422.
Headers
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
Authorization | string | sí | Bearer sk_live_… o Bearer sk_test_…. |
Content-Type | string | sí | application/json. |
Idempotency-Key | string | no | De 1 a 255 caracteres. Ver Convenciones. |
Ejemplo
curl -sS -X POST "$KYCAR_API/v1/verification-sessions" \
-H "Authorization: Bearer $KYCAR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: alta-4821" \
-d '{
"project_id": "prj_01J9Z2K3M4N5P6Q7R8S9T0V1W2",
"external_ref": "cliente-4821",
"expires_in_hours": 48
}'
201 Created:
{
"id": "vs_01K2M4P6R8T0V2X4Z6B8D0F2H4",
"object": "verification_session",
"status": "pending",
"mode": "live",
"project_id": "prj_01J9Z2K3M4N5P6Q7R8S9T0V1W2",
"config_version": "cfg_00000003",
"url": "https://verify.kyc.ar/s/lt_9pQ2vLxK7sYdN1bTfR4mHc8jWgE3aZuQ5nS0oXpVtB",
"qr": {
"svg": "https://api.kyc.ar/v1/qr/lt_9pQ2vLxK7sYdN1bTfR4mHc8jWgE3aZuQ5nS0oXpVtB.svg",
"png": "https://api.kyc.ar/v1/qr/lt_9pQ2vLxK7sYdN1bTfR4mHc8jWgE3aZuQ5nS0oXpVtB.png"
},
"expires_at": "2026-08-21T14:03:11.000Z",
"created_at": "2026-08-19T14:03:11.482Z",
"external_ref": "cliente-4821"
}
Errores
| Campo | Tipo | Status | Descripción |
|---|---|---|---|
validation_failed | 422 | 422 | Body inválido, project_id inexistente, o el proyecto no tiene configuración activa en el modo de la clave. |
insufficient_tokens | 402 | 402 | Sin saldo. No se crea nada. Trae required, balance y top_up_url como extensiones. |
conflict | 409 | 409 | Idempotency-Key reutilizada con otro payload, o con un request todavía en curso. |
rate_limited | 429 | 429 | Throttling del stage. |
Listar sesiones
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
limit | integer | no | 1 a 100. Por defecto 25. |
cursor | string | no | Cursor opaco de la página anterior. |
status | enum | no | Filtra por uno de los ocho estados. Un valor fuera del enum devuelve 422. |
curl -sS "$KYCAR_API/v1/verification-sessions?status=needs_review&limit=50" \
-H "Authorization: Bearer $KYCAR_API_KEY"
{
"data": [
{
"id": "vs_01K2M4P6R8T0V2X4Z6B8D0F2H4",
"object": "verification_session",
"status": "needs_review",
"mode": "live",
"project_id": "prj_01J9Z2K3M4N5P6Q7R8S9T0V1W2",
"config_version": "cfg_00000003",
"created_at": "2026-08-19T14:03:11.482Z",
"external_ref": "cliente-4821"
}
],
"has_more": false
}
No hay filtro por project_id ni por external_ref en este endpoint. Si
necesitás buscar por tu referencia externa, guardá el vs_… que te devuelve la
creación junto a tu registro.
Consultar una sesión
curl -sS "$KYCAR_API/v1/verification-sessions/vs_01K2M4P6R8T0V2X4Z6B8D0F2H4" \
-H "Authorization: Bearer $KYCAR_API_KEY"
{
"id": "vs_01K2M4P6R8T0V2X4Z6B8D0F2H4",
"object": "verification_session",
"status": "rejected",
"mode": "live",
"project_id": "prj_01J9Z2K3M4N5P6Q7R8S9T0V1W2",
"config_version": "cfg_00000003",
"created_at": "2026-08-19T14:03:11.482Z",
"external_ref": "cliente-4821",
"result": {
"outcome": "rejected",
"reason_codes": ["DOC_FIELD_MISMATCH"],
"steps": [
{ "id": "consent", "type": "consent", "verdict": "approved" },
{ "id": "documento", "type": "document_ar", "verdict": "rejected" }
]
},
"completed_at": "2026-08-19T14:19:02.884Z"
}
Un id malformado y un id inexistente devuelven lo mismo: 404 con
code: "not_found". Es deliberado — la API no sirve para descubrir qué ids
existen.
Cancelar una sesión
Cierra una sesión que todavía no llegó a un estado terminal: frena la ejecución
del flujo, deja la sesión en canceled y emite el evento
verification_session.canceled.
curl -sS -X POST "$KYCAR_API/v1/verification-sessions/vs_01K2M4P6R8T0V2X4Z6B8D0F2H4/cancel" \
-H "Authorization: Bearer $KYCAR_API_KEY"
Devuelve 200 con el objeto sesión ya cancelado.
| Campo | Tipo | Status | Descripción |
|---|---|---|---|
conflict | 409 | 409 | La sesión ya estaba en un estado terminal. Cancelar dos veces devuelve este error, no un 200. |
not_found | 404 | 404 | No existe (o el id es inválido). |