Errores
Todas las respuestas de error comparten la misma forma — cómo leerlas y qué mandarnos cuando algo falla
Cualquier error de la API — de validación, de permisos o interno — se devuelve con el mismo cuerpo JSON. No hay formatos distintos por módulo.
{
"statusCode": 409,
"message": "Publication is out of stock",
"code": "PUBLICATION_OUT_OF_STOCK",
"error": null,
"metadata": {},
"path": "/marketplace/publications/redeem/c411df38-05b8-481c-9de2-aa27a16c6e55",
"traceId": "0f9c1a52-77b4-4f3e-9a21-6b8d0e4c5f11",
"timestamp": "2026-08-31T17:00:00.000Z"
}Campos
| Campo | Para qué te sirve |
|---|---|
statusCode | El status HTTP, repetido en el body. |
message | Texto legible. Puede cambiar entre versiones — no lo uses para ramificar lógica. |
code | Identificador estable de la causa. Este es el campo para hacer switch. |
error | Detalle adicional cuando existe (por ejemplo, errores de validación campo por campo). Suele venir null. |
metadata | Contexto extra del error, según el caso. Suele venir {}. |
path | La ruta que se llamó. |
traceId | Identificador único de esa request en nuestros logs. Ver Cuando algo falla. |
timestamp | Momento del error, ISO-8601. |
Rameá siempre por code, nunca por message. El texto está pensado para que lo lea una persona y puede cambiar sin previo aviso; el code es parte del contrato.
Los status que vas a ver
| Status | Cuándo | Qué hacer |
|---|---|---|
400 | Body o query inválidos. También un accountId malformado con idType=INTERNAL, o un idType fuera del enum. | Corregir la request. Reintentar no sirve. |
401 | Falta el header Authorization, o la API Key es inválida, expiró o fue eliminada. | Revisar la key. Ver Autenticación. |
403 | Dos causas distintas, ver abajo. | No reintentar. |
404 | El recurso no existe para tu cliente. Las consultas van acotadas a tu clientId, así que un recurso de otro cliente se ve igual que uno inexistente. | Verificar el ID. |
409 | Conflicto de estado. Dos causas distintas, ver abajo. | Depende de la causa. |
422 | La operación todavía no corresponde — típicamente, reclamar una recompensa de una mecánica sin completar. | Refrescá el estado. Revisá por qué ofreciste la acción. |
500 | Error inesperado de nuestro lado. | Reintentar con backoff. Si persiste, escalá con el traceId. |
Los dos 409
| Causa | Qué hacer |
|---|---|
El mismo operationId ya se está procesando. | Reintento con backoff, con el mismo operationId. Ver Idempotencia. |
| La recompensa se agotó. | No es reintentable. Al usuario: "te avisamos cuando esté disponible", nunca una pérdida. Alerta operativa para reponer stock. |
Los dos 403
Un 403 puede significar dos cosas muy distintas, y conviene distinguirlas antes de escribirnos:
- La feature no está habilitada para tu cliente. Cada módulo está detrás de un flag contratado. Si tu cliente no tiene, por ejemplo,
store, todo/marketplace/*responde403sin importar la key que uses. - mTLS. Si tu tenant tiene el certificado cliente como requisito, cualquier endpoint responde
403mientras no presentes un certificado válido y pineado a tu cliente.
Qué ve el usuario
Ninguno de estos errores se le muestra al usuario final como fallo de su operación: la gamificación nunca puede hacer fracasar la operación de negocio.
| Código | El usuario ve | Tu sistema hace |
|---|---|---|
400 | Nada | Loguear con traceId y corregir la integración. |
401 | Nada | Alerta operativa: toda la gamificación está caída. |
404 | Estado vacío | Revisar el id enviado y el idType. |
409 | Nada, o "te avisamos" si es stock | Reintento con backoff; si es stock, alerta para reponer. |
422 | Cuánto le falta | Refrescar el feed y revisar por qué la acción estaba habilitada. |
5xx · timeout | Nada | Reintento con el mismo operationId. La operación de negocio no se toca. |
Cuando algo falla
El traceId es lo único que necesitamos para encontrar tu request en nuestros logs. Loggealo siempre junto a la respuesta de error, no sólo el message.
if (!res.ok) {
const err = await res.json();
logger.error('UIN API error', {
code: err.code,
status: err.statusCode,
path: err.path,
traceId: err.traceId, // ← esto es lo que nos tenés que pasar
});
}Cuando abras un caso con el equipo de UIN, mandá traceId + timestamp + path. Con eso llegamos directo a la request; sin eso, buscar a ciegas puede llevar horas.
