Saltar al contenido principal
POST
cURL
Usa este endpoint para crear flujos de verificación (workflows) mediante la API sin tener que construir tú mismo los nodos del grafo del flujo. Envía un array features con las comprobaciones en el orden en que los usuarios deben completarlas. Didit lo convierte internamente en un flujo basado en nodos y añade automáticamente el paso de estado final. Este endpoint POST /v3/workflows/ solo crea flujos simples y lineales, es decir, una lista plana de features. Para ramificaciones, enrutamiento condicional, Document AI y nodos de rechazo o decisión, usa el formato de grafo basado en nodos que se documenta más abajo (es el que impulsa el editor visual de la consola y las herramientas de flujos del MCP de Didit). Consulta Configuración de funciones del flujo para ver todos los campos config que acepta cada función.

Flujo KYC básico

Flujo con cuestionario

Primero crea el cuestionario con POST /v3/questionnaires/. Después usa el questionnaire_id devuelto como questionnaire_uuid.
El orden de las funciones importa. Por ejemplo, coloca OCR antes de FACE_MATCH, NFC, DATABASE_VALIDATION o de las comprobaciones de AML de los usuarios que dependen de los datos del documento.

Referencia de configuración de funciones

Cada elemento de features[] tiene esta estructura:
El objeto config exacto depende de la función. Revisa la lista completa de campos, los valores predeterminados, la configuración obligatoria, los rangos de valores y los ejemplos en Configuración de funciones del flujo. Para OCR, omite config.documents_allowed, envía null o envía {} para permitir todos los tipos de documento admitidos. Inclúyelo solo cuando quieras restringir el flujo a países o tipos de documento concretos. Para QUESTIONNAIRE, config.questionnaire_uuid es obligatorio.

Configuración opcional del flujo

Al crear un flujo puedes incluir cualquiera de estos campos de nivel superior para controlar el comportamiento de las sesiones. Todos son opcionales y, si se omiten, se usan los valores predeterminados del flujo.

Ramificaciones y flujos basados en nodos (grafo)

Una lista lineal de features no puede expresar “si X, entonces Y”. Para la ramificación condicional (rechazar según un estado, enrutar según un campo extraído, condicionar un paso a una coincidencia), un paso de solicitud de Document AI o nodos terminales de rechazo/decisión, los flujos de Didit usan un grafo de nodos, la misma estructura que genera el constructor visual de la consola.
La forma más sencilla de crear un flujo basado en grafo es el Didit MCP: pídele a un agente en lenguaje natural (“después de la verificación de identidad, si la profesión es ≈ ‘Software Engineer’, añade un paso de prueba de fondos”) y construirá, validará y guardará el grafo por ti. La estructura que se describe a continuación es la que generan esas herramientas (y la consola).

Estructura del grafo

Un grafo es { start_node, nodes }. nodes es un mapa de id de nodo → nodo. Las aristas son implícitas: cada nodo apunta hacia delante mediante next (incondicional) o branches[].goto (condicional), o ambos. start_node debe ser un nodo de función. Las ramas se evalúan en orden y gana la primera coincidencia; un rules: [] vacío es el “else” que recoge todo lo demás (déjalo al final). session_status: "Determine" decide automáticamente a partir de los resultados combinados de las funciones.
Todo nodo de ramificación debe tener una rama else explícita: una rama con rules: [] que enrute las sesiones que no cumplen ninguna de las condiciones. No dependas del next del nodo de ramificación como alternativa: un next suelto aparece como una arista ambigua en el constructor y es fácil omitirlo. Cuando envías un nodo de ramificación con un next y sin rama else, la API convierte ese next en una rama else explícita por ti (así, { …, "branches": [<conditions>], "next": "liveness" } se guarda como branches: [<conditions>, { "id": "else", "rules": [], "goto": "liveness" }]). Crea tú mismo la rama else para que sea explícita; la conversión es una red de seguridad, no un sustituto.

Reglas de ramificación y operadores

Cada regla compara un campo con un valor mediante un operador:
  • Campos: nombran un resultado de función (kyc.status, aml.status, document_ai.status, face_match.score, …) o un valor extraído (kyc.full_name, kyc.age, kyc.nationality, kyc.extra_fields.profession, un campo de Document AI document_ai.<key>, expected_details.*). Una rama solo puede leer un campo cuya función se haya ejecutado en todas las rutas que llegan a ella.
  • Operadores: equals, not_equals, greater_than(_or_equals), less_than(_or_equals), contains, not_contains, in, not_in, is_empty, is_not_empty, regex y fuzzy_match (solo campos de texto; requiere un score de 0 a 100, un umbral de similitud; por ejemplo, profesión con una similitud ≥ 80% con “Software Engineer”).

Ramificar según el motivo por el que no se ejecutó NFC

Después de un nodo NFC, usa nfc.skip_reason con equals o in para enrutar las sesiones según el motivo por el que no se produjo la lectura del chip. El campo tiene estos siete valores estables:
  • USER_SKIPPED
  • DOCUMENT_WITHOUT_CHIP
  • CHIP_CERTIFICATE_UNAVAILABLE
  • DEVICE_WITHOUT_NFC
  • INTEGRATION_WITHOUT_NFC_ACCESS
  • MRZ_KEY_UNAVAILABLE
  • JPKI_UNAVAILABLE
Consulta Motivos de omisión de NFC para saber qué significa cada valor. Cuando NFC se completa correctamente, nfc.skip_reason es null, por lo que no coincide ninguna regla equals ni in para un motivo de omisión. El campo también se resuelve para los nodos NFC omitidos por una condición previa. Esto incluye los casos en los que no existe ningún informe ni advertencia de NFC, y los casos en los que allow_nfc_skip es false pero la condición del documento o del dispositivo impide que NFC se ejecute. Por tanto, puedes enrutar estas sesiones sin depender de una entrada de nfc_verifications[].
Las sesiones almacenadas antes de que la capacidad NFC pasara a tener tres estados pueden tener has_device_nfc_support: false. Por tanto, una sesión web antigua puede resolverse como DEVICE_WITHOUT_NFC en lugar de INTEGRATION_WITHOUT_NFC_ACCESS.
Este grafo usa equals para una omisión por parte del usuario, in para las omisiones por condición previa o por capacidad, y una rama else explícita para el NFC completado correctamente. La ramificación va después del nodo NFC y cada destino apunta hacia delante a un nodo terminal:
Para expresar “no se realizó NFC por ningún motivo conocido”, usa in con los siete valores. Mantén una rama else explícita para el NFC completado correctamente (nfc.skip_reason: null) y para cualquier valor futuro que tu grafo aún no reconozca.

Document AI (p. ej., prueba de fondos)

Un nodo de función DOCUMENT_AI solicita uno o más documentos y extrae campos con nombre:
Cada campo configurado se convierte en un valor document_ai.<key> utilizable en ramificaciones, y el resultado del paso es document_ai.status. Define "is_full_name": true en el campo que contiene el nombre completo del titular del documento. Su valor extraído se compara con el nombre completo de la identidad verificada (el nombre del OCR o de la verificación de identidad, o los datos esperados de la sesión), y document_ai_name_mismatch_action decide qué ocurre ante una discrepancia con una puntuación inferior a document_ai_name_match_score_threshold. Este indicador es opcional (un documento puede no marcar ningún campo) y como máximo un campo por documento puede definirlo. Consulta Configuración de funciones del flujo → Document AI para ver todos los campos de configuración de Document AI.

Endpoints y ciclo de vida del borrador

La edición del grafo se realiza por aplicación y usa los endpoints de la consola o de gestión (Bearer de usuario + read:workflows/write:workflows). Un grafo solo puede editarse en una versión en borrador, por lo que el ciclo de vida es crear borrador → definir grafo → publicar:

Advertencias de validación

El endpoint de validación responde { "is_valid": true, "graph": …, "warnings": [] }. Una advertencia es informativa: el grafo es válido, se guarda y se publica aunque haya advertencias. Cada entrada indica el nodo de rama y el brazo al que se refiere, para que un editor de flujos pueda señalar la condición exacta:
Un grafo no válido responde 400 con errors y una lista warnings elaborada en la medida de lo posible. Solo errors impide guardar.

Ejemplo práctico: dirigir a los ingenieros de software a la prueba de fondos

Después de la verificación de identidad: si fue rechazada, rechaza la sesión; si la profesión del titular ≈ “Software Engineer” (≥80% de similitud), solicita un documento de prueba de fondos; después, toma una decisión final.
El nodo final usa session_status: "Determine", que decide automáticamente (aprobar / rechazar / en revisión) en función de las funciones que realmente se ejecutaron en la sesión. Así, tanto la ruta de prueba de fondos como la ruta else se resuelven correctamente sin que ninguna rama lea document_ai.status (que no existe en la ruta que omite Document AI). Recuerda: una rama solo puede leer un campo cuya función se haya ejecutado en todas las rutas que llegan a ella. Envíalo como { "graph": <above> } al endpoint …/workflow-graph/ (valídalo primero). Para crear un flujo nuevo desde cero, usa didit_workflow_set_graph del MCP; para modificar un flujo existente, usa didit_workflow_edit_graph (operaciones pequeñas que conservan los nodos existentes y las listas de permitidos). Consulta el MCP de Didit.

Autorizaciones

x-api-key
string
header
requerido

La clave de API de tu aplicación, que encontrarás en Developers -> API keys en la Business Console. La clave principal tiene acceso completo. Una clave con nombre puede tener un alcance limitado: ninguno, lectura o escritura por recurso, limitada a algunos flujos o a sesiones aprobadas, a una lista de direcciones IP y a una fecha de caducidad. 401 significa que la clave es incorrecta, se revocó o expiró; 403 significa que no se envió ninguna clave, que la clave no tiene acceso a este recurso o acción, o que la solicitud provino de una dirección fuera de su lista de IP; 404 en una ruta de sesión significa que la sesión está fuera de los flujos o estados de la clave. Una clave sin acceso a contenido multimedia recibe las URL de imágenes, videos y PDF como null, y una clave sin permiso de escritura en sesiones recibe los enlaces y tokens de sesión como null. Consulta https://docs.didit.me/console/api-keys.

Cuerpo

application/json

Crea un flujo de verificación (workflow) lineal simple. La API convierte internamente esta lista de funciones en un grafo de flujo basado en nodos. Lista ESTRICTA de campos permitidos: cualquier clave que no figure aquí (incluida workflow_type) se rechaza con un 400.

features
object[]
requerido

Funciones de verificación en orden de ejecución. La API enlaza cada elemento con el siguiente y añade automáticamente un nodo de estado final.

Minimum array length: 1
workflow_label
string
predeterminado:ID Verification

Nombre visible del flujo de verificación (máx. 50 caracteres). Si se omite, el valor predeterminado es "ID Verification": defínelo siempre para que los flujos se puedan distinguir.

Maximum string length: 50
Ejemplo:

"Standard KYC"

is_default
boolean

Establece este flujo de verificación (workflow) como predeterminado para las nuevas sesiones.

status
enum<string>

Omite este campo para crear un flujo publicado y listo para sesiones. Usa draft solo cuando quieras guardarlo sin publicarlo.

Opciones disponibles:
draft,
published
is_white_label_enabled
boolean
predeterminado:false

Activa la personalización de marca blanca para las sesiones creadas con este flujo de verificación (workflow).

is_desktop_allowed
boolean
predeterminado:false

Permite que el flujo de verificación se ejecute en navegadores de escritorio.

max_retry_attempts
integer
predeterminado:3

Número máximo de reintentos permitidos tras una verificación rechazada. 0 bloquea al usuario tras el primer rechazo.

Rango requerido: 0 <= x <= 10
retry_window_days
integer | null
predeterminado:7

Ventana móvil en días que se usa para contar los reintentos. null aplica un límite sobre todo el historial.

Rango requerido: 1 <= x <= 365
face_liveness_max_attempts
integer
predeterminado:3

Número máximo de envíos de prueba de vida por sesión. Valor predeterminado: 3 (un intento inicial más dos reintentos). Este valor también se copia en los nodos de prueba de vida y de estimación de edad generados en el flujo, salvo que la configuración a nivel de función lo sobrescriba.

Rango requerido: 1 <= x <= 3
face_match_max_attempts
integer
predeterminado:3

Número máximo de envíos de coincidencia facial por sesión. Valor predeterminado: 3 (un intento inicial más dos reintentos). Este valor también se copia en los nodos de coincidencia facial generados en el flujo, salvo que la configuración a nivel de función lo sobrescriba.

Rango requerido: 1 <= x <= 3
session_expiration_time
integer
predeterminado:604800

Segundos antes de que expire una sesión sin finalizar. Mínimo 1 hora (3600), máximo 4 semanas (2419200).

Rango requerido: 3600 <= x <= 2419200

Respuesta

Flujo creado. El cuerpo de la respuesta es la configuración COMPLETA del flujo: la misma serialización sin procesar de VerificationSettings que devuelve GET /v3/workflows/{settings_uuid}/ (~190 campos: cada interruptor de función, umbral, acción y el workflow_graph generado), no el elemento compacto de la lista. Guarda el uuid (también expuesto como workflow_id) para poder referenciarlo en llamadas posteriores de creación de sesiones. Nota: features es una cadena unida con " + " y los precios son números JSON.

Los campos siguientes están tipados; el objeto también incluye todas las demás columnas de la configuración del flujo (activación de funciones, umbrales, acciones ante advertencias, documentos permitidos, callbacks) como propiedades adicionales. Los campos que no se aplican al workflow_type son null.

uuid
string<uuid>

Identificador por versión (settings_uuid). Cada versión de un flujo tiene el suyo.

workflow_id
string<uuid>

Identificador estable compartido por todas las versiones del flujo. Las sesiones creadas con él usan la última versión publicada.

workflow_label
string

Nombre visible del flujo.

workflow_type
enum<string> | null

Plantilla del flujo. null en los flujos de grafo creados sin plantilla.

Opciones disponibles:
kyc,
kyb,
adaptive_age_verification,
biometric_authentication,
address_verification,
questionnaire_verification,
email_verification,
phone_verification,
null
is_default
boolean

Si este es el flujo predeterminado de la aplicación.

is_archived
boolean

Los flujos archivados no pueden iniciar nuevas sesiones.

version
integer

Número de versión dentro del flujo.

status
enum<string>

Las versiones en borrador son editables; las versiones publicadas son inmutables y se usan para las nuevas sesiones.

Opciones disponibles:
draft,
published
published_at
string<date-time> | null

Cuándo se publicó esta versión. null para los borradores.

is_simple_workflow
boolean

true cuando el flujo no tiene un workflow_graph personalizado.

is_editable
boolean

true solo para las versiones draft.

workflow_url
string<uri>

URL pública que inicia una sesión con este flujo.

workflow_graph
object | null

Estructura de grafo del flujo de verificación (workflow) (nodos y aristas). null para flujos simples.

features
string

Funciones habilitadas unidas con " + ", por ejemplo "OCR + LIVENESS".

total_price
number | null

Precio por sesión; en los flujos de tipo grafo, la ruta más cara.

min_price
number | null

Precio de la ruta más económica del flujo.

max_price
number | null

Precio de la ruta más cara del flujo.

special_add_on_prices
object | null

Precios de complementos específicos de la organización, o null si no hay ninguno configurado.

max_retry_attempts
integer

Reintentos permitidos tras una verificación rechazada.

retry_window_days
integer | null

Días durante los que se permiten los reintentos.

session_expiration_time
integer

Segundos antes de que expire una sesión sin finalizar.

questionnaire
object | null

El cuestionario asociado al flujo, o null.

kyb_role_settings
object[]

Configuración de verificación por rol para las personas clave de KYB.

created_at
string<date-time>
updated_at
string<date-time>
signature_availability
object

Qué niveles de Firma electrónica pueden firmar en este momento. Consúltalo antes de definir signature_level. Se devuelve en los flujos kyc, kyb y de grafo.

is_bank_verification_enabled
boolean

Indica si un flujo de verificación (workflow) simple de KYC o KYB ejecuta la verificación bancaria. Se ejecuta después de los pasos de contacto (y de la verificación de ubicación) y antes de la validación de base de datos, el análisis AML y el análisis de IP. La verificación bancaria aún no está disponible de forma general: se rechaza su activación donde no esté habilitada.

bank_verification_config
object

Configuración de verificación bancaria de un flujo simple, con las mismas claves que admite un nodo BANK_VERIFICATION (por ejemplo, bank_countries y bank_method_order). Las claves desconocidas se descartan. Todas las claves son opcionales y una clave ausente mantiene su valor predeterminado, por lo que {} significa todos los valores predeterminados. Consulta Configuración de verificación bancaria.

Ejemplo:
is_geolocation_enabled
boolean

Indica si un flujo de verificación (workflow) simple de KYC ejecuta la verificación de ubicación. Se ejecuta después de los pasos de contacto y antes de la verificación bancaria y la validación de base de datos. Los flujos de empresas (KYB) no pueden ejecutarla.

geolocation_config
object

Configuración de verificación de ubicación de un flujo simple, con las mismas claves que admite un nodo GEOLOCATION (por ejemplo, is_geolocation_geofencing_enabled y geolocation_max_attempts). Las claves desconocidas se descartan. Todas las claves son opcionales y una clave ausente conserva su valor predeterminado, por lo que {} significa todos los valores predeterminados.

Ejemplo:
Última modificación el 1 de noviembre de 2026