Ir al contenido

Consultar jobs

Cuando disparas un proceso con la API pública obtienes un job (ejecución). Un job es asíncrono: el endpoint de disparo responde de inmediato con un job en estado pending, y el robot lo va avanzando hasta un estado final. Esta página explica cómo consultar su estado y resultado, qué estados existen y cómo detener una ejecución en curso.

Todos los endpoints aquí descritos pertenecen a la API pública y se autentican con la cabecera X-API-Key: nora_ak_.... Consulta autenticación para crear y gestionar tus claves. La URL base de producción es https://nora.valisoftconsulting.com y el prefijo de la API es /api/v1.

Un job pasa por uno de estos seis estados. Solo completed, failed y cancelled son finales (el job ya no cambiará).

EstadoSignificado¿Final?
pendingCreado y encolado, aún sin asignar a una máquina.No
assignedAsignado a una máquina; el agente está por arrancarlo.No
runningEl robot se está ejecutando.No
completedTerminó correctamente. El resultado está en output_data.
failedTerminó con error. El detalle está en error_message.
cancelledCancelado o detenido antes de completar.
flowchart TD
    A[pending] --> B[assigned]
    B --> C[running]
    C --> D[completed]
    C --> E[failed]
    A --> F[cancelled]
    B --> F
    C --> F
GET /api/v1/jobs/{job_id}

Devuelve el job completo. Requiere el scope jobs:read (o una clave sin restricción de scopes). Límite de uso: 60 solicitudes por minuto por clave o IP.

Ventana de terminal
curl https://nora-api.valisoftconsulting.com/api/v1/jobs/3f1c0b4a-7c2e-4a1d-9b8e-1a2b3c4d5e6f \
-H "X-API-Key: nora_ak_xxxxxxxxxxxxxxxx"

Como toda la API pública, la respuesta va envuelta en {"success": true, "data": ...}:

{
"success": true,
"data": {
"id": "3f1c0b4a-7c2e-4a1d-9b8e-1a2b3c4d5e6f",
"tenant_id": "9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d",
"process_id": "b2c3d4e5-f6a7-8b9c-0d1e-2f3a4b5c6d7e",
"machine_id": "c3d4e5f6-a7b8-9c0d-1e2f-3a4b5c6d7e8f",
"status": "completed",
"priority": 3,
"input_data": { "factura": "F001-123" },
"output_data": { "total": 1180.0, "estado": "registrada" },
"logs": null,
"error_message": null,
"started_at": "2026-06-19T14:03:11Z",
"finished_at": "2026-06-19T14:04:02Z",
"retry_count": 0,
"stop_requested": false,
"progress_percent": 100,
"progress_message": "Listo",
"created_at": "2026-06-19T14:03:00Z",
"updated_at": "2026-06-19T14:04:02Z",
"process_name": "Registro de facturas",
"machine_name": "BOT-CONTA-01"
}
}

Campos más relevantes:

CampoTipoDescripción
statusstringEstado actual (ver tabla de estados).
output_dataobjeto | nullResultado del robot. Disponible al completed.
error_messagestring | nullMensaje de error cuando el estado es failed.
progress_percententero | nullAvance reportado por el robot (0–100).
progress_messagestring | nullMensaje de avance del robot.
stop_requestedbooleantrue si se solicitó detener el job.
started_at / finished_atfecha-hora | nullInicio y fin reales de la ejecución.
process_name / machine_namestring | nullNombres del proceso y la máquina asociados.

Como la ejecución es asíncrona, para obtener el resultado se consulta el job de forma periódica hasta que alcance un estado final (completed, failed o cancelled).

sequenceDiagram
    participant C as Cliente
    participant API as NORA API
    C->>API: POST /api/v1/jobs/trigger
    API-->>C: { data: { id, status: "pending" } }
    loop cada N segundos
        C->>API: GET /api/v1/jobs/{job_id}
        API-->>C: { data: { status } }
    end
    Note over C: status final → leer output_data / error_message
import time
import requests
BASE = "https://nora-api.valisoftconsulting.com/api/v1"
HEADERS = {"X-API-Key": "nora_ak_xxxxxxxxxxxxxxxx"}
FINAL = {"completed", "failed", "cancelled"}
def esperar_job(job_id: str, timeout: int = 600, intervalo: int = 5) -> dict:
"""Consulta el job hasta que termine o se agote el tiempo."""
limite = time.time() + timeout
while time.time() < limite:
r = requests.get(f"{BASE}/jobs/{job_id}", headers=HEADERS)
r.raise_for_status()
job = r.json()["data"]
if job["status"] in FINAL:
return job
time.sleep(intervalo)
raise TimeoutError(f"El job {job_id} no terminó en {timeout}s")
job = esperar_job("3f1c0b4a-7c2e-4a1d-9b8e-1a2b3c4d5e6f")
if job["status"] == "completed":
print("Resultado:", job["output_data"])
else:
print("No completó:", job["status"], job.get("error_message"))
POST /api/v1/jobs/{job_id}/stop

Solicita la detención de una ejecución. Requiere el scope jobs:stop (o una clave sin restricción de scopes). Límite de uso: 30 solicitudes por minuto por clave o IP.

Esta operación marca el job con stop_requested = true; el agente detecta la señal y detiene el robot. Solo se puede detener un job en estado running: con cualquier otro estado la API responde 422 con code: "VALIDATION_ERROR".

Ventana de terminal
curl -X POST \
https://nora-api.valisoftconsulting.com/api/v1/jobs/3f1c0b4a-7c2e-4a1d-9b8e-1a2b3c4d5e6f/stop \
-H "X-API-Key: nora_ak_xxxxxxxxxxxxxxxx"

Devuelve el job actualizado (envuelto en data), con stop_requested en true:

{
"success": true,
"data": {
"id": "3f1c0b4a-7c2e-4a1d-9b8e-1a2b3c4d5e6f",
"status": "running",
"stop_requested": true
}
}

Los errores siguen el formato estándar de la API: {"success": false, "error": {"code": "...", "message": "..."}}.

HTTPcodeCuándo ocurre
401UNAUTHORIZEDFalta X-API-Key o la clave es inválida.
403FORBIDDENLa clave no tiene el scope requerido (jobs:read o jobs:stop).
404NOT_FOUNDEl job no existe o no pertenece a tu organización.
422VALIDATION_ERRORIntentas detener un job que no está running.
429RATE_LIMIT_EXCEEDEDSe superó el límite de solicitudes por minuto.