Constaia
Endpoints

Revisiones

Referencia de la revisión humana por API. Lista los análisis pendientes con GET /v1/reviews, descarga el original con GET /v1/analyses/{id}/file y decide con POST /v1/analyses/{id}/review.

Cuando un análisis necesita que lo mire una persona, puedes resolverlo desde el panel o desde tu propio backend con estos endpoints. Guía paso a paso en Revisión humana desde tu backend.

Método y rutaQué hace
GET /v1/reviewsLista los análisis pendientes de revisión (o ya decididos).
GET /v1/analyses/{id}/fileDescarga el documento original, si sigue guardado.
POST /v1/analyses/{id}/reviewAprueba o rechaza un análisis pendiente de revisión.

Solo funcionan con una clave secreta (ck_test_… o ck_live_…). Con una clave publicable (pk_…) la respuesta es 403 publishable_key_not_allowed.

Cuándo un análisis queda pendiente de revisión

Un análisis con veredicto entra en la cola de revisión (review.status: "pending") cuando:

  • su veredicto es review;
  • su veredicto es invalid y la plantilla usada pide revisión humana para los inválidos;
  • su veredicto es valid y la plantilla usada no aprueba solos los válidos.

Mientras está pendiente, verdict.final_status es null. Al decidir pasa a valid (aprobado) o invalid (rechazado). Sin expect no hay veredicto y el análisis no se puede revisar (409 not_reviewable).

El objeto review del análisis:

review (pendiente)
"review": {
  "status": "pending",
  "decision": null,
  "assignee": null,
  "reviewed_by": null,
  "reviewed_at": null,
  "reason": null,
  "note": null
}
CampoDescripción
statuspending, approved o rejected.
decisionapprove, reject o null si aún no se ha decidido.
assigneePersona del equipo a la que se asignó en el panel, o null.
reviewed_byQuién decidió: el id de un usuario del panel o, si se decidió por API, el id de la clave (key_…).
reviewed_atCuándo se decidió.
reasonMotivo breve de la decisión (hasta 200 caracteres).
noteNota interna (hasta 2000 caracteres).

review es null en los análisis que no necesitan revisión.

Listar revisiones

GET /v1/reviews
ParámetroTipoDescripción
statuspending | decided | approved | rejected | allPor defecto pending. decided son los aprobados y los rechazados.
typestringFiltra por tipo de documento, p. ej. es_dni.
templatestringFiltra por plantilla (tpl_…).
metadata[clave]stringFiltra por un valor de metadata. Repetible: deben coincidir todas.
limitentero 1–100Elementos por página. Por defecto 10.
starting_afterstringId (an_…) del último análisis de la página anterior.

Solo incluye análisis del modo de tu clave (test o live). Orden:

  • pending: los más antiguos primero, como una cola: atiende primero lo que lleva más tiempo esperando.
  • El resto: los más recientes primero.
Respuesta
{
  "object": "list",
  "data": [
    {
      "id": "an_01J9Z8Q3K4M5N6P7Q8R9S0T1V3",
      "object": "analysis",
      "status": "completed",
      "verdict": { "status": "review", "final_status": null, "…": "…" },
      "review": { "status": "pending", "decision": null, "…": "…" },
      "storage": { "mode": "review", "kept": true, "reason": "pending_review", "expires_at": "2026-10-29T10:05:01Z", "file_deleted_at": null },
      "file_url": "https://api.constaia.com/v1/files/…",
      "metadata": { "registration_id": "124" }
    }
  ],
  "has_more": false,
  "url": "/v1/reviews"
}

Cada elemento es el objeto analysis completo. La paginación funciona como en el resto de listados: ver Paginación.

curl -G https://api.constaia.com/v1/reviews \
  -H "Authorization: Bearer $CONSTAIA_API_KEY" \
  --data-urlencode "status=pending" \
  --data-urlencode "metadata[event]=42" \
  --data-urlencode "limit=50"

Descargar el original

GET /v1/analyses/{id}/file

Devuelve el documento original tal como se subió, solo si sigue guardado (storage.kept: true). Con el modo de almacenamiento por defecto (review) eso ocurre mientras el análisis espera revisión y durante el margen posterior a la decisión. Ver Almacenamiento y privacidad.

Respuesta 200 con el binario:

CabeceraValor
Content-TypeEl del original: image/jpeg, image/png, image/webp, image/heic o application/pdf.
Content-Dispositioninline; filename="an_….jpg"
Cache-Controlprivate, no-store

Errores:

HTTPcodeCuándo
404resource_missingEl análisis no existe o no es de tu cuenta.
404file_not_storedEl original no se guardó (no hacía falta revisarlo o se analizó con storage: "none") o ya se borró tras su plazo. param es id. Los datos extraídos siguen disponibles.

Alternativa sin clave: mientras el original está guardado, el campo file_url del análisis trae una URL firmada que caduca a los 15 minutos. Es útil para enseñar el documento en tu pantalla de revisión; no la guardes, pide el análisis de nuevo cuando necesites otra.

curl -o original.jpg \
  https://api.constaia.com/v1/analyses/an_01J9Z8Q3K4M5N6P7Q8R9S0T1V3/file \
  -H "Authorization: Bearer $CONSTAIA_API_KEY"

Decidir una revisión

POST /v1/analyses/{id}/review
CampoTipoDescripción
decisionapprove | rejectObligatorio.
reasonstring (≤ 200) | nullMotivo breve, p. ej. "Datos coinciden con el formulario". Opcional.
notestring (≤ 2000) | nullNota interna. Opcional.

Responde 200 con el objeto analysis actualizado:

  • review.status: approved o rejected; review.decision: approve o reject.
  • review.reviewed_by: el id de la clave con la que decidiste (key_…); review.reviewed_at, review.reason y review.note.
  • verdict.final_status: valid si apruebas, invalid si rechazas.
  • storage.expires_at pasa a la hora de la decisión más review_retention_hours_after_decision (24 h por defecto). Si ese plazo es 0, el original se borra al decidir y storage.kept pasa a false.

Además se envía el webhook analysis.reviewed y la decisión queda en el registro de auditoría de la cuenta a nombre de la clave de API.

Respuesta (extracto)
{
  "id": "an_01J9Z8Q3K4M5N6P7Q8R9S0T1V3",
  "object": "analysis",
  "verdict": { "status": "review", "final_status": "valid", "…": "…" },
  "review": {
    "status": "approved",
    "decision": "approve",
    "assignee": null,
    "reviewed_by": "key_01J9Z8Q3K4M5N6P7Q8R9S0T1V9",
    "reviewed_at": "2026-09-30T08:12:40Z",
    "reason": "Datos coinciden con el formulario",
    "note": null
  },
  "storage": { "mode": "review", "kept": true, "reason": null, "expires_at": "2026-10-01T08:12:40Z", "file_deleted_at": null }
}

Reintentos seguros

  • Envía la cabecera Idempotency-Key: la misma clave con el mismo cuerpo devuelve la misma respuesta, con la cabecera Idempotent-Replayed: true. Ver Idempotencia.
  • Repetir la misma decisión sobre un análisis ya decidido devuelve el análisis tal cual (200) y no envía otro webhook.
  • Una decisión distinta sobre un análisis ya decidido devuelve 409 already_reviewed. Solo un propietario o administrador puede cambiarla, desde el panel.

Errores

HTTPcodeCuándo
403publishable_key_not_allowedUsaste una clave publicable (pk_…).
404resource_missingEl análisis no existe o no es de tu cuenta.
409already_reviewedEl análisis ya tiene otra decisión.
409not_reviewableEl análisis no tiene veredicto: no se indicó expect o aún no ha terminado.
422invalid_parameterEl cuerpo no es válido (decision falta o no es approve/reject, reason o note demasiado largos).
curl https://api.constaia.com/v1/analyses/an_01J9Z8Q3K4M5N6P7Q8R9S0T1V3/review \
  -H "Authorization: Bearer $CONSTAIA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: review-an_01J9Z8Q3K4M5N6P7Q8R9S0T1V3" \
  -d '{ "decision": "approve", "reason": "Datos coinciden con el formulario" }'

Plantillas y plazos

Si usas plantillas, cada una puede fijar su propio almacenamiento y sus plazos de revisión. El objeto template incluye siempre estos campos:

CampoTipoDescripción
storagenone | review | temporary | persistentModo de almacenamiento de los análisis hechos con la plantilla.
review_retention_hours_after_decisionentero 0–720 | nullHoras que se conserva el original tras decidir. null = el valor de la cuenta (24 por defecto).
review_max_daysentero 1–90 | nullDías máximos que se conserva un original pendiente si nadie decide. null = el valor de la cuenta (30 por defecto).

Los valores de la cuenta se cambian en el panel (Ajustes de la cuenta).

Siguientes pasos

En esta página