Saltar al contenido principal

GET /jobs/{id}

Consulta el estado de un job de emisión masiva asíncrona.

Request

GET /api/v1/jobs/{job_id}

Headers

HeaderRequeridoDescripción
X-API-KeySiTu API key

Path Parameters

ParámetroTipoDescripción
job_idstringID del job retornado por POST /credentials/issue

Response: En progreso

{
"job_id": "abc123-task-id",
"status": "PROGRESS",
"progress": {
"current": 25,
"total": 50,
"status": "Procesando fila 25 de 50"
},
"batch_uuid": "550e8400-e29b-41d4-a716-446655440000"
}
Detalle de fallos por fila

Si el job termina con failed > 0, podés consultar los fallos persistidos por fila usando el batch_uuid que aparece en este response. Mientras el mapeo Redis no expire (7 días), también podés usar GET /jobs/{id}/failures. Después, usá GET /bulk-failures?batch_uuid=....

Granularidad de progress.current

Internamente, los lotes asíncronos pueden correr en una arquitectura por chunks (100 filas por chunk). Cuando esa ruta está activa, progress.current avanza en saltos de 100 (cuando un chunk termina) en vez de fila por fila, y progress.status se ve como "Procesando 200 de 1000..." en lugar de "Procesando fila 25 de 50". El shape del response es idéntico; solo cambia la granularidad del avance. No requiere cambios en el cliente.

Response: Completado

{
"job_id": "abc123-task-id",
"status": "SUCCESS",
"result": {
"total": 50,
"successful": 48,
"failed": 2,
"errors": [
{"row": 12, "email": "invalido@test", "error": "Invalid email: invalido@test"},
{"row": 37, "email": "[email protected]", "error": "Calificación inválida"}
],
"emails_sent": 48,
"emails_failed": 0,
"internal_count": 30,
"external_count": 18
}
}

Response: Fallido

{
"job_id": "abc123-task-id",
"status": "FAILURE",
"error": "Achievement not found"
}

Estados del job

StatusSignificado
PENDINGEn cola, esperando ser procesado
STARTEDEl worker comenzó a procesar
PROGRESSEn progreso, con info de avance
SUCCESSCompletado exitosamente
FAILUREFallo (ver campo error)

Campos del resultado (SUCCESS)

CampoDescripción
totalTotal de recipientes procesados
successfulCredenciales emitidas exitosamente
failedRecipientes con errores
errorsDetalle de errores por fila
emails_sentNotificaciones enviadas
emails_failedNotificaciones fallidas
internal_countRecipientes internos (miembros de la org)
external_countRecipientes externos

Patron de polling recomendado

import requests
import time

def poll_job(job_id, api_key, interval=2, max_attempts=300):
"""Consulta el estado de un job cada `interval` segundos."""
headers = {"X-API-Key": api_key}
base_url = "https://app.unicreda.com/api/v1"

for attempt in range(max_attempts):
response = requests.get(f"{base_url}/jobs/{job_id}", headers=headers)
data = response.json()

if data["status"] == "SUCCESS":
return data["result"]
elif data["status"] == "FAILURE":
raise Exception(f"Job failed: {data['error']}")
elif data["status"] == "PROGRESS":
progress = data.get("progress", {})
current = progress.get("current", 0)
total = progress.get("total", 0)
print(f" Progress: {current}/{total}")

time.sleep(interval)

raise TimeoutError("Job did not complete in time")

Errores

StatusDetalleCausa
403Access denied to this jobEl job fue creado con otro API key

Ejemplo

curl -X GET "https://app.unicreda.com/api/v1/jobs/abc123-task-id" \
-H "X-API-Key: uc_live_tu_key_aqui"