Referencia de la APISolicitudes KYC

Solicitudes KYC

Referencia completa de la API de solicitudes KYC de Certivant — crear, listar, enviar, aprobar, rechazar, escalar y reenviar solicitudes de verificación de identidad de personas físicas o empresas.

Una solicitud KYC representa un único intento de verificar la identidad de una persona (INDIVIDUAL) o la identidad de una empresa junto con sus directores y beneficiarios finales (BUSINESS). Todos los endpoints siguientes se encuentran bajo /api/v1/kyc/requests.

Todos los endpoints requieren una clave de API con el alcance correspondiente. Consulte Autenticación.


Crear una solicitud

POST /api/v1/kyc/requests    Alcance: kyc:write

Crea una nueva solicitud en estado PENDING_UPLOAD. Los datos del solicitante son opcionales; si no los envía, el solicitante los completa mediante la sesión alojada.

Cuerpo de la solicitud

{
  "type": "INDIVIDUAL",
  "purpose": "Financing an iPhone 16, 24 months",
  "externalRef": "your-id-here",
  "subTenantName": "Acme Corp",
  "subTenantExternalId": "cust_8842",
  "applicant": {
    "externalRef": "your-applicant-id",
    "fullName": "Jane Doe",
    "dateOfBirth": "1990-04-12",
    "nationality": "US",
    "email": "jane@example.com",
    "phone": "+14155551234",
    "emailVerified": false,
    "phoneVerified": false,
    "metadata": { "anyKey": "anyValue" }
  }
}
CampoTipoObligatorioNotas
typeenumsíINDIVIDUAL o BUSINESS
purposestringnoPor qué verifica a esta persona, en pocas palabras — p. ej. Financing an iPhone 16, 24 months, Opening an account. 3–300 caracteres. Se almacena cifrado. Si no envía ninguno, Certivant usa el motivo predeterminado del formulario (formId) y, si no hay, «New customer verification» (siempre almacenado en inglés). Se recomienda un motivo concreto: hace útil la detección de fraude. Consulte Motivo de la verificación
externalRefstringnoSu clave externa. Se devuelve en cada evento
subTenantNamestringnoModo socio: nombre visible del cliente final al que pertenece esta solicitud. Máximo 200 caracteres
subTenantExternalIdstringnoModo socio: su propio identificador interno para ese cliente final. Se puede filtrar en el endpoint de listado y se repite en cada webhook. Máximo 200 caracteres
formIdstringnoCrea la verificación a través de uno de sus formularios (se aplican sus requisitos de documentos y la solicitud queda asociada a él). El tipo del formulario debe coincidir con type. Obligatorio para una clave de API restringida a formularios específicos, y debe ser uno de ellos. Consulte Restricción de formularios
faceCheckSkippablebooleannoOmitido: el ajuste del formulario (formId), si no el de su organización (la verificación facial es obligatoria salvo que lo cambie). false fuerza que la verificación facial sea obligatoria. true ofrece la alternativa no biométrica, solo donde la ley la exija (p. ej. Quebec): el solicitante puede rechazar la verificación facial. Entonces no se ejecuta ninguna selfie ni prueba de vida, el documento de identidad se sigue recopilando y la solicitud pasa a revisión manual con una verificación de identidad en vivo recomendada. Un formulario puede activarlo con «Permitir que los solicitantes omitan la verificación facial»; el ajuste de la organización está en Ajustes → KYC/B.
applicant.externalRefstringnoClave externa del solicitante, separada de la referencia de la solicitud
applicant.fullNamestringnoSi se omite, se recopila mediante la sesión alojada
applicant.dateOfBirthstring (fecha ISO)noYYYY-MM-DD
applicant.nationalitystring (ISO 3166-1 alfa-2)noPor ejemplo, US, GB, FR
applicant.emailstringno
applicant.phonestring (E.164)no
applicant.emailVerifiedbooleannoEstablezca true si ya verificó el correo electrónico por su cuenta
applicant.phoneVerifiedbooleannoIgual que el anterior: omite el paso de verificación telefónica de Certivant
applicant.metadataobjectnoJSON arbitrario. Se devuelve en el endpoint GET

Atribución a socios y subtenants. Si realiza verificaciones para muchos clientes finales dentro de una misma organización (por ejemplo, una plataforma de firma electrónica que verifica a firmantes de cientos de empresas), establezca subTenantName y subTenantExternalId en cada solicitud. Así podrá filtrar el endpoint de listado por subTenantExternalId, ambos campos se repiten en cada webhook y el panel muestra un filtro de subtenant, todo ello sin crear una organización separada para cada cliente.

Motivo de la verificación

Cada solicitud tiene un motivo: por qué verifica a la persona, en pocas palabras. Enviarlo es opcional, pero se recomienda un motivo concreto porque hace útil la detección de fraude. Certivant lee el motivo y lo asocia a una de las aproximadamente 110 entradas de una lista de motivos — por ejemplo, financiación de un teléfono o dispositivo, plan móvil, activación de una SIM, préstamo personal, tarjeta de crédito, alquiler de coche, criptomonedas, cuenta bancaria, alquiler de vivienda, hipoteca, firma ante notario / escritura, seguro, empleo o verificación de edad. Cada motivo pertenece a una familia: Teléfonos y dispositivos, Líneas móviles y SIM, Préstamos y crédito, Vehículos, Bienes de alto valor, Movimientos de dinero y criptomonedas, Apertura de cuentas, Alquiler de vivienda, Propiedad e hipoteca, Otro (sin dinero en juego) o No claro.

  • Solo se compara la familia. La red de prevención del fraude compara entre empresas la familia — nunca el texto ni el motivo concreto. El texto en sí se almacena cifrado, nunca se comparte con otra empresa y solo viaja por HTTPS.
  • Solo cuenta lo que pone dinero o crédito en riesgo. Una solicitud solo cuenta para los patrones de fraude cuando hay dinero o crédito en juego. Una firma ante notario, una hipoteca, un seguro, los suministros, un empleo o la atención médica se registran, pero nunca cuentan: quien firma una escritura ante notario y financia un teléfono un mes después no queda marcado.
  • Los motivos sensibles nunca se comparten. La salud, los asuntos legales, la inmigración, el juego, los problemas de deudas, las citas, la religión o las donaciones, los fallecimientos o herencias y los bienes con restricción de edad se almacenan como «Otro».
  • Sea concreto. Un motivo como KYC o verification no dice qué compra la persona. Por defecto, la solicitud se crea igualmente, con una advertencia. Si su organización activó Rechazar motivos vagos (Configuración → Prevención del fraude → Reglas de la red antifraude), se rechaza con 422.
  • No incluya datos personales. Las direcciones de correo, los números de teléfono, de tarjeta y de documento y las fechas se eliminan antes de que una IA lea el motivo — no los escriba en él.

La respuesta de creación indica cómo se interpretó el motivo:

CampoValoresSignificado
purposeQualityinformativeEl motivo dice qué se compra, se financia o se abre.
genericDemasiado vago para clasificarlo con precisión.
unusableNo se pudo entender.
warnings (solo cuando procede)purpose_too_generic · purpose_unusable · purpose_contains_personal_dataQué corregir en el motivo. El último significa que se detectaron y eliminaron datos personales.

Los mismos campos se devuelven en POST /api/v1/kyc/forms/:formId/send. Para una visión completa, consulte Red antifraude.

El motivo se elige en este orden: el purpose que usted envía, luego el motivo predeterminado del formulario (se configura en el editor de formularios) y, por último, «New customer verification», siempre almacenado en inglés con exactamente ese texto. Por eso las integraciones que no envían ningún motivo, como los complementos de firma electrónica, nunca reciben un error. El motivo predeterminado nunca se rechaza (ni siquiera con Rechazar motivos vagos), no genera ninguna advertencia y no implica dinero en riesgo, así que no alimenta los patrones de la red antifraude.

Respuesta (201)

{
  "id": "req_01J...",
  "status": "PENDING_UPLOAD",
  "type": "INDIVIDUAL",
  "externalRef": "your-id-here",
  "subTenantName": "Acme Corp",
  "subTenantExternalId": "cust_8842",
  "pendingDocTypes": ["GOVERNMENT_ID", "SELFIE"],
  "purposeQuality": "informative",
  "applicant": { ... },
  "createdAt": "2026-05-27T10:00:00.000Z"
}

pendingDocTypes refleja la configuración KYC de su organización: lo que se requiere depende de si ha habilitado la prueba de vida, la prueba de domicilio, etc.

purposeQuality es informative, generic o unusable. Cuando el motivo requiere su atención, se añade un arreglo warnings con purpose_too_generic, purpose_unusable y/o purpose_contains_personal_data.

Errores

  • 400 VALIDATION_ERROR — el cuerpo no superó la validación de Zod. error.fields enumera cada ruta con error.
  • 403 FORBIDDEN — la clave no tiene kyc:write, o bien (error.reason = "form_not_allowed") la clave está restringida a formularios específicos y la solicitud no incluye formId o indica otro formulario.
  • 404 NOT_FOUND — el formId no es un formulario de su organización.
  • 409 CONFLICT — su externalRef ya lo utiliza otra solicitud de esta organización. Use una referencia distinta o consulte la solicitud existente.
  • 422 — su organización rechaza los motivos vagos (Rechazar motivos vagos) y purpose es demasiado genérico o inutilizable. Indique qué se compra o se financia. También lo devuelve POST /api/v1/kyc/forms/:formId/send.

Listar solicitudes

GET /api/v1/kyc/requests    Alcance: kyc:read

Parámetros de consulta

ParámetroTipoPredeterminadoNotas
statusenum—Filtra por PENDING_UPLOAD, PROCESSING, APPROVED, REJECTED, ESCALATED, CANCELLED
typeenum—INDIVIDUAL o BUSINESS
externalRefstring—Filtro de coincidencia exacta por su clave externa
subTenantExternalIdstring—Modo socio: devuelve solo las solicitudes etiquetadas con este identificador de cliente final
searchstring—Búsqueda de texto libre por nombre y correo electrónico del solicitante
pageinteger1Número de página, empezando en 1
limitinteger20Máximo 100

Respuesta

{
  "data": [
    { "id": "req_...", "status": "APPROVED", "type": "INDIVIDUAL", "createdAt": "...", "applicant": {...} },
    ...
  ],
  "pagination": {
    "total": 248,
    "page": 1,
    "limit": 20,
    "pages": 13
  }
}

Use el filtro externalRef para obtener una solicitud cuando solo conozca su propia clave externa. No necesita guardar el identificador req_… de Certivant si su externalRef es único.


Obtener una solicitud

GET /api/v1/kyc/requests/:id    Alcance: kyc:read

Devuelve la verificación completa: el solicitante, cada documento cargado (con los campos extraídos por OCR), cada comprobación automatizada, el desglose completo de riesgo, las señales de fraude y el registro de auditoría. Es todo lo que muestra la pantalla de detalle del panel, de modo que puede crear su propia interfaz de revisión sin enviar al personal a Certivant.

Respuesta

{
  "id": "req_...",
  "status": "ESCALATED",
  "type": "INDIVIDUAL",
  "externalRef": "user-9281",
  "subTenantName": null,
  "subTenantExternalId": null,
  "reviewedBy": null,
  "reviewNote": null,
  "completedAt": null,
  "createdAt": "2026-05-27T10:00:00.000Z",
  "updatedAt": "2026-05-27T10:03:12.000Z",

  "applicant": {
    "id": "app_...",
    "fullName": "Alex Singh",
    "dateOfBirth": "1988-11-03T00:00:00.000Z",
    "nationality": "GBR",
    "email": "alex@example.com",
    "emailVerified": true,
    "phone": "+447700900100",
    "phoneVerified": false,
    "metadata": {}
  },

  "documents": [
    {
      "id": "doc_...",
      "documentType": "id_card",
      "side": "front",
      "status": "done",
      "mimeType": "image/jpeg",
      "fileSize": 412938,
      "parsedData": {
        "fullName": "Alex Singh",
        "dateOfBirth": "1988-11-03",
        "documentNumber": "D1234567",
        "expiryDate": "2030-01-15",
        "nationality": "GBR",
        "issuingCountry": "GBR",
        "address": "12 High St, London"
      },
      "createdAt": "2026-05-27T10:01:00.000Z"
    }
  ],

  "checks": [
    { "id": "chk_1", "checkType": "ocr",        "provider": "aws_textract", "status": "passed", "score": 0.95, "startedAt": "...", "finishedAt": "..." },
    { "id": "chk_2", "checkType": "face_match", "provider": "azure_face",   "status": "passed", "score": 0.88 },
    { "id": "chk_3", "checkType": "liveness",   "provider": "azure_face",   "status": "passed", "score": 0.92 },
    { "id": "chk_4", "checkType": "sanctions",  "provider": "ofac",         "status": "failed", "score": 0.0 }
  ],

  "riskScore": {
    "overallScore": 62,
    "decision": "escalate",
    "autoDecision": true,
    "factors": [
      { "factor": "document_authenticity", "impact": 1.0, "description": "Barcode + metadata valid" }
    ],
    "rejectionReasons": [],
    "verdictMeta": {
      "factorVerdicts": [
        { "id": "1.1", "section": "Identity Document", "label": "Document authenticity", "weight": 15, "state": "pass", "evidence": ["barcode_valid"] },
        { "id": "4.2", "section": "Screening",         "label": "Sanctions / PEP",       "weight": 20, "state": "fail", "evidence": ["ofac_possible_match"] }
      ],
      "disqualifiers": [],
      "reviewTriggers": ["sanctions_possible_match"],
      "effectiveThresholdApprove": 80
    }
  },

  "fraudSignals": [
    { "signalType": "device_reuse", "severity": "low", "details": { "matchedFingerprint": "..." } }
  ],

  "auditLogs": [
    { "id": "log_1", "actorType": "api",    "actorId": "kyk_prod_ab",  "eventType": "request.created",   "payload": {}, "createdAt": "..." },
    { "id": "log_2", "actorType": "system", "actorId": "orchestrator", "eventType": "request.escalated", "payload": { "reason": "sanctions" }, "createdAt": "..." }
  ]
}

Referencia de campos

RutaNotas
documents[].parsedDataCampos extraídos por OCR (varían según el tipo de documento): fullName, dateOfBirth, documentNumber, expiryDate, nationality, issuingCountry, address. Es null hasta que se ejecuta el OCR
documents[].statuspending · processing · done · failed
checks[].checkTypeocr · face_match · liveness · sanctions · llm_consistency
checks[].statuspending · running · passed · failed · skipped · error
checks[].score0.0–1.0 (null en las comprobaciones de solo aprobado o rechazado). details contiene el resultado sin procesar del proveedor
riskScore.overallScorePuntuación compuesta de 0 a 100
riskScore.decisionapprove · reject · escalate. autoDecision: false = una persona anuló la decisión
riskScore.verdictMeta.factorVerdicts[]La matriz de PASS/FAIL/N-A que explica por qué la decisión quedó donde está. state es pass · fail · n/a
riskScore.verdictMeta.disqualifiersCódigos de nivel 1 que fuerzan un rechazo
riskScore.verdictMeta.reviewTriggersCódigos de nivel 2 que fuerzan una escalación
fraudSignals[]signalType (same_face · velocity · document_reuse · device_reuse), severity (low · medium · high)
auditLogs[]Historial a prueba de manipulaciones. actorType es api · system · user

Errores

  • 404 NOT_FOUND — no existe ninguna solicitud con ese identificador en esta organización. Las solicitudes pertenecen a organizaciones; no puede leer datos de otra organización aunque tenga una clave válida.

Mostrar una verificación en su propia aplicación

La respuesta de detalle está diseñada para mostrarse directamente: una sola llamada le ofrece todo lo que muestra el panel, de modo que sus revisores nunca tienen que iniciar sesión en Certivant.

GET /api/v1/kyc/requests/:id → datos del solicitante, documents[].parsedData, checks[] y riskScore.verdictMeta.

Para cada documento, GET /api/v1/kyc/requests/:id/documents/:docId/url → una URL firmada válida durante 15 minutos. Muestre las imágenes con <img src> y los PDF con <iframe>. La URL está prefirmada y no necesita el encabezado Authorization. Consulte Documentos → Obtener una URL de descarga.

Muestre checks[] (aprobado o rechazado, con su puntuación) y riskScore.verdictMeta.factorVerdicts[] para que el revisor vea exactamente por qué se escaló una solicitud. Después, actúe con POST /requests/:id/decision.

Obtenga las URL de los documentos bajo demanda, justo antes de mostrarlas. Caducan a los 15 minutos y nunca deben registrarse, almacenarse en caché ni exponerse a usuarios no autenticados.


Enviar a procesamiento

POST /api/v1/kyc/requests/:id/submit    Alcance: kyc:submit

Libera una solicitud PENDING_UPLOAD hacia el flujo de procesamiento automatizado. La solicitud debe tener cargados todos los documentos requeridos (pendingDocTypes debe estar vacío) antes de poder enviarla.

Si su organización exige verificación del correo electrónico y/o del teléfono (Configuración de KYC/B), asegúrese de que cada canal requerido esté verificado antes de enviar. Para ello, establezca applicant.emailVerified / applicant.phoneVerified: true al crear la solicitud (cuando los haya validado usted mismo) o haga que el solicitante complete el paso del código en una sesión alojada. Un canal requerido sin verificar no supera la comprobación de verificación de contacto durante el procesamiento.

Respuesta

{
  "id": "req_...",
  "status": "PROCESSING",
  "message": "Request submitted; you will receive a webhook when processing completes."
}

Errores

  • 400 BAD_REQUEST — pendingDocTypes no está vacío. Cargue primero los documentos que faltan.
  • 409 CONFLICT — la solicitud no está en PENDING_UPLOAD. Solo se puede enviar una vez.

Decisión manual (solicitudes escaladas)

POST /api/v1/kyc/requests/:id/decision    Alcance: kyc:manage

Anula una solicitud ESCALATED con una decisión humana. Este endpoint está pensado para herramientas internas; la mayoría de las decisiones se toman desde el panel.

Cuerpo de la solicitud

{ "decision": "APPROVED", "note": "Confirmed identity against internal CRM record" }
CampoTipoObligatorioNotas
decisionenumsíAPPROVED o REJECTED
notestringsíDe 1 a 1000 caracteres. Se almacena en el registro de auditoría y es visible para todos los revisores

Respuesta

{ "id": "req_...", "status": "APPROVED", "decision": "APPROVED", "reviewNote": "..." }

Errores

  • 409 CONFLICT — la solicitud no está en estado ESCALATED. No puede anular una aprobación automática.

Reenviar una solicitud rechazada

POST /api/v1/kyc/requests/:id/resubmit    Alcance: kyc:write

Restablece una solicitud REJECTED a PENDING_UPLOAD para que el solicitante pueda volver a intentarlo. Los documentos anteriores se eliminan y el solicitante carga documentos nuevos.

Respuesta

{ "id": "req_...", "status": "PENDING_UPLOAD" }

Errores

  • 409 CONFLICT — la solicitud no está en estado REJECTED. Solo se pueden reenviar las solicitudes rechazadas; las canceladas o aprobadas no.

Reenviar es una operación privilegiada. Asegúrese de que la política de su organización permita al solicitante reintentar. Algunos flujos regulados exigen una solicitud nueva en lugar de un reenvío, para que el registro de auditoría muestre claramente intentos separados.


Eliminar una solicitud

DELETE /api/v1/kyc/requests/:id    Alcance: kyc:write

Elimina de forma permanente la solicitud y todo lo asociado a ella: se propaga en cascada a sus documentos, comprobaciones y puntuaciones de riesgo, borra del almacenamiento las imágenes y PDF de identificación cargados y elimina el registro del solicitante cuando ninguna otra solicitud lo referencia. Use esta operación para atender la solicitud de eliminación de un cliente o para purgar una verificación de prueba.

Respuesta

{
  "success": true,
  "documentsDeleted": 3,
  "applicantDeleted": true
}
  • documentsDeleted — cuántos archivos almacenados se eliminaron.
  • applicantDeleted — si el solicitante se limpió por no tener otras referencias (false si aún tiene otras solicitudes).

Errores

  • 404 NOT_FOUND — no existe ninguna solicitud con ese ID en su organización.

Esta operación es irreversible: los documentos cargados se pierden. El registro de auditoría de solo adición se conserva (sus filas mantienen una referencia no estricta), de modo que el registro de que una solicitud existió y fue eliminada sobrevive por motivos de cumplimiento. Si solo desea borrar los datos personales del solicitante, use en su lugar Eliminar un solicitante.


Informar del resultado

POST /api/v1/kyc/requests/:id/outcome    Alcance: kyc:write

Opcional. Indique a Certivant si la compra o el crédito para el que se hizo la verificación se entregó realmente o se canceló. Llámelo cuando la solicitud ya esté resuelta.

Cuerpo de la solicitud

{ "fulfilled": true }
CampoTipoObligatorioNotas
fulfilledbooleanosítrue = la compra o el crédito se entregó. false = se canceló

Respuesta

{ "id": "req_...", "fulfilled": true, "recorded": true }

recorded: false significa que la solicitud aún no está en la red antifraude (por ejemplo, porque no tiene claves de identidad). No se pierde nada: puede enviar el resultado más tarde. También puede volver a llamar al punto de conexión en cualquier momento para cambiar la respuesta.

Errores

  • 404 NOT_FOUND — no hay ninguna solicitud con ese id en esta organización.
  • 409 CONFLICT — la solicitud aún no está resuelta. Su estado debe ser APPROVED, REJECTED, ESCALATED o PENDING_SECOND_REVIEW.

Por qué ayuda. En la red antifraude, una compra entregada cuenta por completo, mientras que una cancelada no cuenta en absoluto. Así, un cliente que inició tres financiaciones de teléfono y canceló dos no se confunde con alguien que se llevó tres teléfonos. Solo se comparte el resultado; nada más sale de su organización.


Obtener señales de fraude

GET /api/v1/kyc/requests/:id/fraud-signals    Alcance: kyc:read

Devuelve las señales de fraude de dispositivo, red y comportamiento recopiladas durante la verificación.

Respuesta

[
  {
    "signalType": "device_reused",
    "severity": "medium",
    "details": { "previousRequestIds": ["req_..."], "matchedFingerprint": "..." }
  },
  {
    "signalType": "vpn_detected",
    "severity": "low",
    "details": { "asn": 13335, "isp": "Cloudflare" }
  }
]

La gravedad es low, medium o high. Las señales de gravedad alta escalan automáticamente la solicitud a revisión manual.


Monitoreo continuo de AML

Una verificación aprobada puede volver a someterse a cribado en busca de nuevas coincidencias en sanciones, PEP y medios adversos (consulte Monitoreo continuo). El monitoreo es una función del plan y se factura por persona monitoreada al año.

LlamadaAlcanceEfecto
GET /api/v1/kyc/requests/:id/monitoringkyc:readEstado: enrolled, status (active, paused, cancelled), frequency, enrolledAt, lastScreenedAt, nextScreenAt, nextBillingAt, openAlerts
POST /api/v1/kyc/requests/:id/monitoringkyc:manageInicia el monitoreo. Cuerpo { "frequency": "daily" | "weekly" | "monthly" } (predeterminado monthly). Devuelve { "success": true, "frequency": "monthly", "chargedCents": 0 }
DELETE /api/v1/kyc/requests/:id/monitoringkyc:manageDetiene el monitoreo

POST devuelve 409 para una verificación que no está aprobada, 403 cuando su plan no incluye el monitoreo y 402 cuando no hay crédito para una persona más allá de la cuota incluida.

Las nuevas coincidencias llegan como el webhook kyc.monitoring.alert (consulte Eventos de webhook). data.monitoring contiene alertType (sanctions_match, pep_match, adverse_media, sanctions_unverifiable), severity y, para una PEP, pepTier: 1 jefes de Estado y ministros … 4 familiares y allegados cercanos. También puede aparecer adverseMedia: true. data.sanctions.listsChecked indica las listas consultadas; los proveedores de cribado nunca se nombran.

La propia verificación incluye el mismo pepTier / adverseMedia bajo data.sanctions en su webhook de decisión.


Eliminar un solicitante (supresión conforme al RGPD)

DELETE /api/v1/kyc/applicants/:applicantId    Alcance: kyc:manage

Elimina de forma permanente un solicitante y cada solicitud vinculada a él. Es el endpoint del derecho de supresión conforme al artículo 17 del RGPD. El registro de auditoría conserva un registro de borrado (tombstone) con la fecha y hora de la eliminación, pero sin datos personales.

Respuesta

{ "success": true, "deletedRequestIds": ["req_...", "req_..."] }

La supresión es irreversible. Consulte con su equipo de cumplimiento antes de llamar a este endpoint: según su jurisdicción, puede tener la obligación regulatoria de conservar los registros de verificación durante 5 a 7 años, lo que entra en conflicto con la eliminación.