Referencia de la API

Errores

problem+json (RFC 7807) y la lista completa de códigos de error.

Todos los errores de aplicación de la plataforma se devuelven como application/problem+json (RFC 7807), con la misma forma:

{
  "type": "https://docs.kyc.ar/errores#validation_failed",
  "title": "validation_failed",
  "status": 422,
  "code": "validation_failed",
  "detail": "project_id: el proyecto no existe"
}

code es estable y público: programá contra él. detail es texto para humanos y puede cambiar de redacción sin aviso; status tampoco alcanza para decidir, porque hay códigos distintos que comparten status (rate_limited y usage_limit_exceeded son 429; session_expired y link_consumed son 410).

El campo type apunta al ancla de esta página: el type de cualquier error te trae exactamente a su sección. Algunos errores agregan campos propios —miembros de extensión de RFC 7807, como required y balance en un 402— y nunca pisan los campos reservados.

Todos los códigos

CódigoStatusDónde apareceQué significa
unauthorized401API públicaCredenciales inválidas
forbidden403DashboardOperación no permitida para esta identidad
insufficient_scope403API públicaLa clave no tiene ese permiso
not_found404API públicaEl recurso no existe
validation_failed422API públicaEl request no cumple el contrato
conflict409API públicaEl estado actual no admite la operación
insufficient_tokens402API públicaSaldo insuficiente
rate_limited429API públicaDemasiadas operaciones en poco tiempo
session_expired410QR y flujoEl link de verificación venció
link_consumed410QR y flujoEl link ya fue utilizado
step_not_current409Flujo del usuario finalEl paso no está esperando esa respuesta
usage_limit_exceeded429ReservadoLímite de uso excedido
internal500Toda la plataformaError interno

Detalle por código

unauthorized 401

Credenciales inválidas

El contexto de autorización de la request llegó ausente o malformado. En la práctica es un error de plataforma, no de tu integración: una clave inválida se corta antes, en el authorizer, y devuelve un 403 del gateway.

Si lo ves de forma sostenida, escribinos con el momento exacto.

forbidden 403

Operación no permitida para esta identidad

La identidad es válida pero no puede hacer esa operación: cuenta suspendida, cuenta pendiente de aprobación intentando operar en modo live, o un rol de sólo lectura intentando una mutación.

Ojo con no confundirlo con el 403 del gateway de la API pública, que tiene cuerpo {"message":"Forbidden"} y no es problem+json.

insufficient_scope 403

La clave no tiene ese permiso

La clave es válida, pero los permisos con los que se emitió no habilitan esa operación. Reintentar no sirve y volver a autenticarse tampoco: hay que usar (o emitir) una clave con el permiso que falta.

El cuerpo trae el miembro de extensión required_scope con el permiso exacto que se necesitaba, para que no tengas que deducirlo del detail. La lista completa está en Autenticación → Permisos.

Las claves emitidas antes de que existieran los permisos no ven nunca este error: conservan acceso completo.

not_found 404

El recurso no existe

La sesión, el endpoint de webhook o la entrega no existen dentro de tu cuenta.

Un id malformado y un id de otra cuenta devuelven exactamente esto mismo. Es deliberado: la API no confirma la existencia de recursos ajenos ni sirve para enumerar ids.

validation_failed 422

El request no cumple el contrato

Body inválido, campo desconocido (los cuerpos son estrictos), query param fuera de rango, cursor de paginación corrupto. El detail nombra los campos: project_id: el proyecto no existe.

También se usa para condiciones de negocio detectables en el request: un proyecto sin configuración publicada en el modo de tu clave, un mes que supera el máximo exportable en línea, o una entrega de prueba que se intenta re-entregar.

conflict 409

El estado actual no admite la operación

Los tres casos habituales:

  • cancelar una sesión que ya estaba en un estado terminal;
  • reutilizar una Idempotency-Key con un payload distinto al original;
  • disparar una prueba o una re-entrega sobre un endpoint disabled.

Reintentar sin cambiar nada va a dar el mismo 409: es un error de estado, no transitorio.

insufficient_tokens 402

Saldo insuficiente

No hay tokens para cubrir el costo de la sesión. No se crea nada: ni sesión, ni link, ni asiento contable.

El cuerpo trae miembros de extensión para que no tengas que parsear el detail: required (lo que cuesta la sesión), balance (lo que hay, puede faltar en una carrera de saldo) y top_up_url (a dónde ir a recargar).

Tratalo como incidente operativo, no como rechazo de identidad: la persona del otro lado no hizo nada mal.

rate_limited 429

Demasiadas operaciones en poco tiempo

Superaste el cupo de una operación con límite propio: prueba y re-entrega de webhook comparten 10 por minuto por cuenta.

Los intentos rechazados también cuentan para la ventana: reintentar en bucle no acerca el desbloqueo. Esperá a la ventana siguiente.

El throttling general del stage (20 rps, ráfaga 40) lo aplica API Gateway y devuelve su propio 429, sin cuerpo problem+json.

session_expired 410

El link de verificación venció

El link pasó su expires_at. No hay forma de extenderlo: la salida es crear una sesión nueva.

Lo vas a ver en los endpoints de QR y en el flujo del usuario final.

El link ya fue utilizado

El link de verificación es de un solo uso: una vez que la persona lo abre y lo canjea, el token deja de servir y el QR responde este error.

step_not_current 409

El paso no está esperando esa respuesta

Interno del flujo que corre la persona: se intentó responder un paso que no es el actual, o que ya está siendo procesado.

No aparece en la API pública. Está documentado porque el código es público y podés verlo en trazas de soporte.

usage_limit_exceeded 429

Límite de uso excedido

Código reservado del contrato de errores. Hoy ningún endpoint lo emite; se documenta para que un cliente que haga un switch exhaustivo sobre code lo contemple sin sorpresas.

internal 500

Error interno

Algo falló de nuestro lado. El cuerpo nunca expone detalle interno: si necesitás soporte, mandanos el momento exacto y, si lo tenés, el external_ref o el id del recurso.

Es reintentable con backoff. En POST de creación de sesión, reintentá con la misma Idempotency-Key para no crear duplicados.