MIRA · Referencia de API para desarrolladores
API de validación documental
El servicio MIRA expone endpoints ejecutables para validar PDF, imágenes y evidencia multimedia mediante QR, códigos de barras, detección de rostros, detección de firmas, comparación de imágenes, prompts y OCR de texto. Cada endpoint ejecuta una sola regla y devuelve su propio resultado. La orquestación de varias reglas en una decisión completa se realiza con los endpoints de workflow.
AUTHAutenticación
Para consumir un endpoint protegido de MIRA primero se obtiene un access token y luego se envía en la cabecera de la solicitud:
Authorization: Bearer {ACCESS_TOKEN}El backend no ejecuta los flujos OAuth: recibe y valida el access token emitido por Cognito. El JWT debe contener token_use=access; un ID token no es válido. GET /health y la interfaz Swagger son públicos y no requieren Bearer token.
Flujo 1 · Usuarios — Authorization Code con PKCE
Se usa cuando hay una persona frente a una aplicación web o móvil. PKCE protege el intercambio del código y permite que una aplicación pública no guarde un client_secret. Primero se dirige el navegador a una URL como esta:
https://mitra-trust.auth.us-east-1.amazoncognito.com/oauth2/authorize
?response_type=code
&client_id={PUBLIC_CLIENT_ID}
&redirect_uri={URL_CALLBACK_ENCODED}
&scope=openid+email
&code_challenge={CODE_CHALLENGE}
&code_challenge_method=S256
&state={RANDOM_STATE}Después del login, Cognito redirige al callback registrado con un code. La aplicación debe comprobar que el state recibido coincida con el que guardó y luego intercambia el código por tokens:
curl --request POST "https://mitra-trust.auth.us-east-1.amazoncognito.com/oauth2/token" \
--header "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=authorization_code" \
--data-urlencode "client_id={PUBLIC_CLIENT_ID}" \
--data-urlencode "code={AUTHORIZATION_CODE}" \
--data-urlencode "redirect_uri={URL_CALLBACK}" \
--data-urlencode "code_verifier={CODE_VERIFIER}"{
"access_token": "eyJraWQiOi...",
"id_token": "eyJraWQiOi...",
"refresh_token": "...",
"expires_in": 3600,
"token_type": "Bearer"
}Solo se usa access_token para llamar a MIRA. Los usuarios autorizados deben pertenecer al grupo de Cognito MIRA_ADMIN o MIRA_STANDARD, y el claim client_id del token debe corresponder al App Client de frontend configurado con COGNITO_CLIENT_ID. Si la federación está configurada (Microsoft Entra ID, Okta, SAML/OIDC), MIRA siempre recibe un token emitido por Cognito, nunca el token del IdP externo.
Flujo 2 · Sistemas — Client Credentials
Se usa para integraciones backend-to-backend, procesos batch o servicios automáticos. No representa a un usuario ni abre un navegador. El sistema necesita un client_id, un client_secret (en un gestor de secretos) y el scope mira-api/execute.
curl --request POST "https://mitra-trust.auth.us-east-1.amazoncognito.com/oauth2/token" \
--user "{CLIENT_ID}:{CLIENT_SECRET}" \
--header "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=client_credentials" \
--data-urlencode "scope=mira-api/execute"El client_secret se usa únicamente al solicitar el token a Cognito y nunca debe enviarse a una API de MIRA.
BASEConvenciones
- Las rutas JSON reciben
Content-Type: application/json. - Todos los endpoints documentales aceptan Base64 puro.
- QR, BARCODE, FACE, SIGNATURE e IMAGE solo eliminan el prefijo exacto
data:application/pdf;base64,. - PROMPT y TEXT aceptan un Data URL genérico y eliminan todo lo anterior a la primera coma.
- Los documentos y videos no deben superar los 20 MB.
- Las páginas se numeran desde
1.
HTTPHeaders comunes
| Campo | Obligatorio | Descripción |
|---|---|---|
Authorization: Bearer {ACCESS_TOKEN} | Sí | Access token de Cognito válido. |
Content-Type: application/json | Sí | En endpoints JSON. Permite deserializar el cuerpo JSON. |
Content-Type: multipart/form-data | Sí | En EVIDENCE. curl agrega el boundary automáticamente con --form; no debe escribirse manualmente. |
Idempotency-Key: {UUID} | Sí | En creación/ejecución de workflows. Evita duplicados ante reintentos. |
Resumen de endpoints
| Método | Ruta | Plugin | Entrada |
|---|---|---|---|
| POST | /rule/document/qr/read | qr | PDF en Base64 |
| POST | /rule/document/barcode/read | barcode | PDF en Base64 |
| POST | /rule/document/face/read | face | PDF en Base64 |
| POST | /rule/document/signature/read | signature | PDF en Base64 |
| POST | /rule/document/image/validate | image | PDF y referencias en Base64 |
| POST | /rule/document/prompt/evaluate | prompt | PDF o imagen en Base64 |
| POST | /rule/document/text/read | text | PDF o imagen en Base64 |
| POST | /api/rule/evidence/prompt/evaluate | evidence | Archivo multipart |
| POST | /api/admin/workflows/{workflowId}/versions | workflow | Definición JSON |
| POST | /api/workflows/{workflowId}/execute | workflow | Documento JSON |
| GET | /api/workflow-executions/{executionId} | workflow | Parámetro de ruta |
REGLASEndpoints de reglas
Todos los endpoints de reglas reciben un cuerpo JSON con Content-Type: application/json y un Bearer token válido. Los campos marcados como “No” pueden omitirse; omitir no equivale a enviar null.
01Lectura de códigos QR
Busca códigos QR dentro de un PDF y los compara con los valores esperados.
Solicitud
{
"pdfBase64": "JVBERi0xLjQK...",
"rule": {
"id": "RULE-QR-01",
"type": "QR",
"weight": 20,
"minMatch": 100,
"expectedCount": 1,
"expectedValues": ["https://example.com/document/123"],
"pages": [1, 2]
}
}Campos
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
pdfBase64 | string | Sí | PDF en Base64 puro o con el prefijo exacto data:application/pdf;base64,. No puede estar vacío. |
rule | object | No | Configuración de la regla QR. Si se omite, cualquier QR detectado puede aprobar. |
rule.id | string | No | Identificador informativo. |
rule.type | string | No | Tipo informativo. |
rule.weight | decimal | No | Peso de la regla. |
rule.minMatch | integer | No | Umbral informativo. |
rule.expectedCount | integer | No | Cantidad esperada informativa. |
rule.expectedValues | string[] | No | Valores QR aceptados. |
rule.pages | integer[] | No | Páginas a analizar, numeradas desde 1. Si se omite o queda vacío, se analizan todas. |
Comportamiento
Si expectedValues está vacío, cualquier QR detectado obtiene score=100. Con valores esperados, la comparación es exacta tras recortar espacios laterales y pasar a minúsculas.
score solo puede ser 0 o 100. detectedCount cuenta combinaciones únicas de valor normalizado y página. passed es true únicamente con un QR de score=100.
Respuesta de ejemplo
{
"hasQr": true,
"passed": true,
"score": 100,
"foundValue": "https://example.com/document/123",
"detectedCount": 1,
"foundValues": [
{ "value": "https://example.com/document/123", "page": 1, "score": 100 }
]
}02Lectura de códigos de barras
Busca códigos CODE 128, CODE 39, EAN-13, EAN-8, UPC-A, UPC-E, PDF417, ITF y Codabar en un PDF.
Solicitud
{
"pdfBase64": "JVBERi0xLjQK...",
"rule": {
"id": "RULE-BARCODE-01",
"type": "BARCODE",
"weight": 15,
"minMatch": 100,
"expectedCount": 1,
"expectedValues": ["7801234567894"],
"regions": [ { "pages": [1] } ]
}
}Campos
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
pdfBase64 | string | Sí | PDF en Base64 puro o con el prefijo exacto data:application/pdf;base64,. No puede estar vacío. |
rule | object | No | Configuración BARCODE. Si se omite, se aplican los predeterminados. |
rule.id | string | No | Identificador. Predeterminado: null. |
rule.type | string | No | Tipo devuelto. Predeterminado: BARCODE. |
rule.weight | number | No | Peso. Predeterminado: 0. |
rule.minMatch | integer | No | Match mínimo para aprobar. |
rule.expectedCount | integer | No | Metadata de cantidad esperada. |
rule.expectedValues | string[] | No | Códigos aceptados. Predeterminado: lista vacía (permite cualquiera). |
rule.regions | object[] | No | Regiones usadas únicamente para seleccionar páginas. |
rule.regions[].pages | integer[] | No | Páginas a analizar. Sin regiones se analizan todas. |
Comportamiento
La comparación aplica Trim() y elimina el espacio ASCII, pero no tabulaciones ni todos los espacios Unicode; distingue mayúsculas y minúsculas. Devuelve como máximo un código por página. expectedCount es metadata y no interviene en passed.
foundMatch solo puede ser 0 o 100. Como minMatch no se restringe, un valor ≤ 0 puede aprobar sin detecciones y uno > 100 nunca aprueba. scoreContribution es el weight completo si aprueba; si no, 0.
Respuesta de ejemplo
{
"id": "RULE-BARCODE-01",
"type": "BARCODE",
"weight": 15,
"minMatch": 100,
"expectedCount": 1,
"foundValue": "7801234567894",
"foundMatch": 100,
"passed": true,
"scoreContribution": 15,
"details": {
"detectedCount": 1,
"foundValues": [ { "value": "7801234567894", "format": "EAN_13", "page": 1 } ]
}
}03Detección de rostros
Detecta rostros mediante Google Cloud Vision.
Solicitud
{
"pdfBase64": "JVBERi0xLjQK...",
"rule": {
"id": "RULE-FACE-01",
"type": "FACE",
"weight": 20,
"minMatch": 100,
"expectedCount": 1,
"regions": [ { "pages": [1] } ]
}
}Campos
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
pdfBase64 | string | Sí | PDF en Base64 puro o con el prefijo exacto data:application/pdf;base64,. No puede estar vacío. |
rule | object | No | Configuración FACE. Si se omite, se usa la predeterminada. |
rule.id | string | No | Identificador de la regla. Predeterminado: null. |
rule.type | string | No | Tipo devuelto. Predeterminado: FACE. |
rule.weight | integer | No | Peso. Predeterminado: 0. |
rule.minMatch | integer | No | Porcentaje mínimo para aprobar. Predeterminado: 0. |
rule.expectedCount | integer | No | Rostros esperados. Predeterminado: 1; si se envía, debe ser > 0. |
rule.regions[].pages | integer[] | No | Páginas a analizar, desde 1. Sin regiones se analiza solo la página 1. |
Comportamiento
Sin regiones solo se analiza la primera página; las regiones seleccionan páginas, no recortan por coordenadas. Páginas ≤ 0 se descartan; una página mayor al total puede terminar en 500.
foundMatch = min(100, detectedCount × 100 / expectedCount). Si aprueba, scoreContribution es el weight completo; si no, el aporte proporcional weight × foundMatch / 100, redondeado a dos decimales.
Respuesta de ejemplo
{
"id": "RULE-FACE-01",
"type": "FACE",
"weight": 20,
"minMatch": 100,
"foundMatch": 100,
"passed": true,
"scoreContribution": 20,
"expectedCount": 1,
"details": {
"detectedCount": 1,
"foundValues": [
{ "value": "face_detected", "page": 1, "x": 0.32, "y": 0.11, "width": 0.18, "height": 0.24, "confidence": 0.98 }
]
}
}04Detección de firmas
Busca firmas cerca de palabras como firma, mandante, mandatario y notario, combinando Document AI con detección de tinta.
Solicitud
{
"pdfBase64": "JVBERi0xLjQK...",
"rule": {
"id": "RULE-SIGNATURE-01",
"type": "SIGNATURE",
"weight": 25,
"minMatch": 80,
"expectedCount": 1,
"regions": [
{ "pages": [1], "x": 0.1, "y": 0.7, "width": 0.8, "height": 0.2 }
]
}
}Campos
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
pdfBase64 | string | Sí | PDF en Base64 puro o con el prefijo exacto data:application/pdf;base64,. No puede estar vacío. |
rule | object | No | Configuración SIGNATURE. Si se omite, se usa la predeterminada. |
rule.id | string | No | Identificador de la regla. Predeterminado: null. |
rule.type | string | No | Tipo devuelto. Predeterminado: SIGNATURE. |
rule.weight | integer | No | Peso. Predeterminado: 0. |
rule.minMatch | integer | No | Umbral entre 0 y 100. Predeterminado: 0. |
rule.expectedCount | integer | No | Firmas esperadas. Predeterminado: 1; debe ser > 0. |
rule.regions[] | object[] | No | Metadata devuelta en la respuesta (páginas, x, y, width, height informativos). |
Comportamiento
Las regiones se devuelven como metadata; la implementación determina dinámicamente la zona de búsqueda a partir de las palabras clave (configurables a petición del cliente). La confidence es una métrica heurística de tinta entre 0 y 100.
minMatch cumple dos funciones: cada zona candidata debe alcanzar esa confianza de tinta para contarse, y luego foundMatch también debe alcanzar el umbral para aprobar.
Respuesta de ejemplo
{
"id": "RULE-SIGNATURE-01",
"type": "SIGNATURE",
"weight": 25,
"minMatch": 80,
"foundMatch": 100,
"passed": true,
"scoreContribution": 25,
"expectedCount": 1,
"regions": [
{ "pages": [1], "x": 0.1, "y": 0.7, "width": 0.8, "height": 0.2, "hasCoordinates": true }
],
"details": {
"detectedCount": 1,
"foundValues": [
{ "value": "signature_detected_near_keyword", "keyword": "firma", "page": 1,
"x": 0.2, "y": 0.7, "width": 0.45, "height": 0.12,
"confidence": 92, "inkPixels": 430, "contourCount": 4 }
]
}
}05Validación de imágenes
Busca en el PDF una o más imágenes de referencia.
Solicitud
{
"pdfBase64": "JVBERi0xLjQK...",
"rule": {
"id": "RULE-IMAGE-01",
"type": "IMAGE",
"weight": 20,
"minMatch": 80,
"expectedValues": ["iVBORw0KGgoAAAANSUhEUg..."],
"regions": [
{ "pages": "1,2", "x": 0, "y": 0, "width": 1, "height": 0.5 }
]
}
}Campos
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
pdfBase64 | string | Sí | PDF en Base64 puro o con el prefijo exacto. No puede estar vacío. |
rule | object | Sí | Configuración de la regla IMAGE. |
rule.type | string | No | Predeterminado: IMAGE. Si se envía, debe ser exactamente IMAGE. |
rule.minMatch | integer | No | Similitud mínima para aprobar. Predeterminado: 80. No se restringe al rango 0..100. |
rule.expectedValues | string[] | Sí | Una o más referencias no vacías (Base64 puro o Data URL) que deben decodificar como imagen. |
rule.regions[].pages | string | No | Páginas separadas por coma, p.ej. "1,2". Vacío significa todas. |
Comportamiento
Las coordenadas de regions no se usan para recortar. La búsqueda se realiza en el cuadrante superior izquierdo que cubre el 45% del ancho y el 45% del alto de cada página seleccionada.
Se conserva una sola coincidencia. Cuando una página alcanza minMatch, las siguientes no se procesan, por lo que no se garantiza el máximo global. scoreContribution = weight × foundMatch / 100 si aprueba; si no, 0.
Respuesta de ejemplo
{
"id": "RULE-IMAGE-01",
"type": "IMAGE",
"weight": 20,
"minMatch": 80,
"foundMatch": 92.5,
"passed": true,
"scoreContribution": 18.5,
"expectedValues": ["iVBORw0KGgoA..."],
"details": {
"detectedCount": 1,
"foundValues": [
{ "value": null, "page": 1, "x": 0.2, "y": 0.1, "width": 0.3, "height": 0.15, "similarity": 92.5 }
]
}
}06Evaluación mediante prompt
Evalúa un PDF o una imagen.
Solicitud
{
"pdfBase64": "JVBERi0xLjQK...",
"mimeType": "application/pdf",
"rule": {
"id": "RULE-PROMPT-01",
"type": "PROMPT",
"weight": 30,
"minMatch": 80,
"expectedValues": ["vigente", "firmado"],
"prompt": "Verifica si el documento está vigente y firmado."
}
}Campos
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
pdfBase64 | string | Sí | PDF o imagen en Base64 puro o como Data URL. No puede estar vacío. |
mimeType | string | No | Predeterminado: application/pdf. Para imágenes: image/jpeg o image/png. |
rule | object | Sí | Configuración de la regla PROMPT. |
rule.minMatch | integer | No | Umbral entre 0 y 100. Predeterminado: 80. |
rule.expectedValues | string[] | No | Valores que orientan la evaluación. Predeterminado: lista vacía. |
rule.prompt | string | Sí | Instrucción de negocio, con entre 10 y 4000 caracteres útiles. |
Comportamiento
La regla debe tener type=PROMPT; prompt entre 10 y 4000 caracteres; minMatch entre 0 y 100; weight no negativo. expectedValues puede estar vacío.
foundMatch es un entero en 0..100. details.detectedCount es exactamente la cantidad de objetos en details.values.
Respuesta de ejemplo
{
"id": "RULE-PROMPT-01",
"type": "PROMPT",
"weight": 30,
"minMatch": 80,
"foundMatch": 90,
"passed": true,
"scoreContribution": 27,
"details": {
"detectedCount": 1,
"result": "El documento está vigente y contiene una firma.",
"values": [
{ "name": "vigencia", "value": "vigente",
"evidence": "Fecha de vencimiento posterior a la fecha actual",
"page": 1, "timestamp": null, "confidence": 0.95 }
]
}
}07Lectura y validación de texto
Extrae texto con OCR y busca los valores esperados.
Solicitud
{
"documentBase64": "JVBERi0xLjQK...",
"mimeType": "application/pdf",
"rule": {
"id": "RULE-TEXT-01",
"type": "TEXT",
"weight": 20,
"minMatch": 80,
"expectedValues": ["RUT 12.345.678-9"],
"regions": [
{ "pages": "1", "x": 0, "y": 0, "width": 1, "height": 0.5 }
]
}
}Campos
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
documentBase64 | string | Sí | PDF o imagen en Base64 puro o como Data URL. No puede estar vacío. |
mimeType | string | No | Predeterminado: application/pdf. Admite PDF, TIFF, JPEG y PNG. Para imagen o TIFF debe enviarse explícitamente. |
rule.expectedValues | string[] | Sí | Uno o más textos esperados; no admite elementos vacíos. |
rule.regions[].pages | string | No | Páginas separadas por coma. Vacío o sin enteros positivos significa todas. |
rule.regions[].x/y/width/height | decimal | No | Posición esperada entre 0 y 1; el rango no se valida. Para aplicar coordenadas deben enviarse las cuatro. |
Comportamiento
La comparación pasa a minúsculas, elimina acentos, reemplaza signos por espacios y colapsa espacios. Coincidencia exacta = 100; si un texto contiene al otro = 95; en otros casos usa distancia de Levenshtein.
Se devuelve solo la mejor coincidencia. foundMatch combina la similitud textual con la confianza OCR normalizada a 0..100. detectedCount indica si se construyó un candidato (0 o 1), no si aprobó.
Respuesta de ejemplo
{
"id": "RULE-TEXT-01",
"type": "TEXT",
"weight": 20,
"minMatch": 80,
"foundMatch": 98,
"passed": true,
"scoreContribution": 19.6,
"details": {
"detectedCount": 1,
"expectedValue": "RUT 12.345.678-9",
"matchedText": "RUT 12.345.678-9",
"similarity": 100,
"ocrConfidence": 98,
"page": 1,
"result": "Se encontró texto similar con 98% de confianza combinada.",
"foundValues": [
{
"expectedValue": "RUT 12.345.678-9",
"matchedText": "RUT 12.345.678-9",
"page": 1,
"similarity": 100,
"ocrConfidence": 98,
"combinedConfidence": 98,
"boundingBox": { "x": 0.1, "y": 0.2, "width": 0.3, "height": 0.04 }
}
]
}
}08Evaluación de evidencia multimedia
Recibe un archivo directamente (multipart). PDF e imágenes se procesan en memoria; los videos se suben a Google Cloud Storage y se evalúan desde allí.
Solicitud
curl --request POST "$BASE_URL/api/rule/evidence/prompt/evaluate" \
--header "Authorization: Bearer $ACCESS_TOKEN" \
--form "file=@evidencia.mp4;type=video/mp4" \
--form 'rule={"id":"RULE-EVIDENCE-01","type":"PROMPT","weight":30,"minMatch":80,"expectedValues":["casco"],"prompt":"Verifica si todas las personas utilizan casco."}' \
--form "fps=1" --form "startOffset=0s" --form "endOffset=60s"Campos
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
file | Archivo | Sí | PDF, imagen o video no vacío. |
rule | string JSON | Sí | Regla PROMPT serializada como JSON válido. |
mimeType | string | No | Sobrescribe el Content-Type del archivo. Si se omite, se usa file.ContentType. |
fps | number | No | Solo video. Debe ser > 0 y ≤ 24. |
startOffset / endOffset | string | No | Solo video. La validación local únicamente exige que terminen en s, p.ej. 0s, 60s. |
Comportamiento
Formatos admitidos: PDF, JPEG, PNG, MP4, QuickTime, WebM y MPEG. El formato se decide por mimeType o el Content-Type declarado; el handler no inspecciona la firma binaria ni la extensión.
La respuesta tiene la misma estructura que una evaluación PROMPT. En video, los elementos pueden incluir timestamp en lugar de page. El objeto de video no se elimina automáticamente tras procesarse.
Respuesta de ejemplo
{
"id": "RULE-EVIDENCE-01",
"type": "PROMPT",
"weight": 30,
"minMatch": 80,
"foundMatch": 95,
"passed": true,
"scoreContribution": 28.5,
"details": {
"detectedCount": 1,
"result": "El video muestra que todas las personas utilizan casco.",
"values": [
{ "name": "uso de casco", "value": "cumple",
"evidence": "Las personas visibles utilizan casco de seguridad.",
"page": null, "timestamp": "00:00:12", "confidence": 0.96 }
]
}
}ORQUESTACIÓNWorkflows
Los endpoints de workflow combinan varias reglas en una sola decisión, con ejecución secuencial, puntaje ponderado y creación y ejecución idempotentes.
09Crear una versión del workflow
Crea y publica una nueva versión del workflow. La versión guarda el orden de los plugins, sus parámetros y la regla que calcula el resultado general. Disponible solo para el grupo MIRA_ADMIN.
POST /api/admin/workflows/{workflowId}/versions
Authorization: Bearer {ACCESS_TOKEN}
Idempotency-Key: {UUID}
Content-Type: application/jsonSolicitud
{
"name": "Validación de contrato",
"basedOnVersion": 2,
"changeNote": "Se agrega validación de firma",
"activate": true,
"definition": {
"schemaVersion": 1,
"execution": {
"mode": "SEQUENTIAL",
"onTechnicalError": "FAIL",
"timeoutSeconds": 180
},
"steps": [
{
"id": "validar-qr",
"pluginId": "qr",
"pluginContractVersion": 1,
"required": true,
"weight": 40,
"parameters": { "expectedValues": ["CONTRATO-123"], "pages": [1] }
},
{
"id": "validar-firma",
"pluginId": "signature",
"pluginContractVersion": 1,
"required": true,
"weight": 60,
"parameters": { "minMatch": 80, "expectedCount": 1 }
}
],
"decision": {
"type": "WEIGHTED_THRESHOLD",
"minScore": 80,
"requireAllRequired": true
}
}
}Campos
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
workflowId | string | Sí | Identificador del workflow enviado en la ruta. |
Idempotency-Key | string (UUID) | Sí | Identificador único de la solicitud, enviado como header. |
name | string | Sí | Nombre del workflow. |
basedOnVersion | integer | No | Última versión conocida. Se omite al crear la primera versión. |
activate | boolean | Sí | Indica si la nueva versión queda como versión activa. |
definition | object | Sí | Definición completa del workflow (schemaVersion, execution, steps, decision). |
definition.execution.mode | string | Sí | Orden de ejecución. En el ejemplo, SEQUENTIAL. |
definition.steps[].weight | number | Sí | Puntaje máximo que puede aportar el paso. |
definition.decision.type | string | Sí | Tipo de decisión: ALL_REQUIRED, ANY o WEIGHTED_THRESHOLD. |
Comportamiento
Una versión publicada no se modifica: cualquier cambio crea una nueva. Con activate: true, esa versión queda como activeVersion. Si otro administrador ya creó una versión más nueva, el servicio debería responder 409 Conflict.
Idempotency-Key evita crear dos versiones ante reintentos. La misma clave y contenido devuelven el resultado original; reutilizarla con contenido distinto debe producir 409 Conflict. En WEIGHTED_THRESHOLD, los pesos deben sumar 100.
Respuesta de ejemplo
{
"workflowId": "validacion-contrato",
"version": 3,
"status": "PUBLISHED",
"active": true,
"definitionHash": "sha256:5d322e...",
"createdAt": "2026-07-28T18:20:00Z"
}10Ejecutar el workflow
Procesa el documento con la versión seleccionada del workflow. Puede ejecutarse de forma síncrona (/execute, resultado inmediato) o asincrónica (/executions, se consulta después).
POST /api/workflows/{workflowId}/execute # sincrono
POST /api/workflows/{workflowId}/executions # asincrono (202 Accepted)
Authorization: Bearer {ACCESS_TOKEN}
Idempotency-Key: {UUID}
Content-Type: application/jsonSolicitud
{
"version": 3,
"inputs": {
"mainDocument": {
"fileName": "contrato.pdf",
"mimeType": "application/pdf",
"contentBase64": "JVBERi0xLjQK..."
}
},
"metadata": { "caseId": "CASE-93452" }
}Campos
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
workflowId | string | Sí | Identificador del workflow enviado en la ruta. |
Idempotency-Key | string (UUID) | Sí | Identificador único de la ejecución, como header. Evita duplicar ejecuciones ante reintentos. |
version | integer | No | Versión publicada a ejecutar. Si se omite, se usa activeVersion. |
inputs.mainDocument.mimeType | string | Sí | Tipo MIME del documento, p.ej. application/pdf. |
inputs.mainDocument.contentBase64 | string | Sí | Contenido del documento codificado en Base64. |
metadata.caseId | string | No | Identificador del caso asociado. Es informativo y no modifica la decisión. |
Comportamiento
La ejecución síncrona espera a que terminen todos los pasos y devuelve el resultado final (recomendada para workflows cortos). Si se supera timeoutSeconds, debería responder 504 Gateway Timeout con código WORKFLOW_TIMEOUT.
La ejecución asincrónica responde 202 Accepted con un statusUrl. La ejecución guarda siempre la versión resuelta y su definitionHash completo (SHA-256). Un passed=false es una validación rechazada, no un error técnico: la respuesta sigue siendo 200 OK.
Respuesta de ejemplo
{
"executionId": "exe_01K1T9B8MZWR",
"workflowId": "validacion-contrato",
"workflowVersion": 3,
"definitionHash": "sha256:5d322e...",
"status": "COMPLETED",
"decision": { "passed": false, "score": 40, "minScore": 80 },
"steps": [
{ "id": "validar-qr", "pluginId": "qr", "status": "COMPLETED", "passed": true, "match": 100, "scoreContribution": 40 },
{ "id": "validar-firma", "pluginId": "signature", "status": "COMPLETED", "passed": false, "match": 0, "scoreContribution": 0 }
]
}11Consultar una ejecución del workflow
Consulta el estado y la salida de una ejecución asincrónica usando el executionId recibido al iniciar el workflow. No recibe body.
GET /api/workflow-executions/{executionId}
Authorization: Bearer {ACCESS_TOKEN}Campos
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
executionId | Ruta | Sí | Identificador entregado al crear la ejecución. |
Comportamiento
Los estados propuestos son QUEUED → RUNNING → COMPLETED (o FAILED). COMPLETED significa que el motor terminó técnicamente; la decisión funcional está en decision.passed.
Respuesta de ejemplo
{
"executionId": "exe_01K1T9B8MZWR",
"workflowId": "validacion-contrato",
"workflowVersion": 3,
"definitionHash": "sha256:5d322e...",
"status": "COMPLETED",
"decision": { "passed": false, "score": 40, "minScore": 80 },
"steps": [
{ "id": "validar-qr", "pluginId": "qr", "status": "COMPLETED", "passed": true, "match": 100, "scoreContribution": 40 },
{ "id": "validar-firma", "pluginId": "signature", "status": "COMPLETED", "passed": false, "match": 0, "scoreContribution": 0 }
]
}HTTPErrores
| Código | Significado |
|---|---|
401 Unauthorized | Falta el token o expiró, firma o emisor no válidos, no es un access token, client_id no permitido, o un cliente técnico sin el scope mira-api/execute. |
403 Forbidden | Token válido, pero un usuario humano no pertenece a MIRA_ADMIN/MIRA_STANDARD, o el plugin solicitado está deshabilitado. |
409 Conflict | Ya existe una versión más nueva del workflow, o se reutilizó un Idempotency-Key con contenido distinto. |
500 Internal Server Error | Error inesperado de procesamiento, p.ej. una página superior al total del PDF en FACE. |
504 Gateway Timeout | Un workflow síncrono superó timeoutSeconds (código WORKFLOW_TIMEOUT). |