Content-Type: application/problem+json. Sin wrapper error: {} ni details
genérico.
Cada
type resuelve a esta página: el slug final es el ancla de su
sección, como #not-found-404.La forma común
Seis campos, siempre presentes:string
requerido
URI canónica y estable del tipo. Es el único campo que conviene comparar en código.
string
requerido
Texto estable por tipo. No describe la ocurrencia.
integer
requerido
El mismo código HTTP de la respuesta.
string
requerido
Describe esta ocurrencia. No lo parsees: no es una interfaz y puede
cambiar sin aviso.
string
requerido
Alias corto en
snake_case. Es un string abierto: pueden aparecer códigos
nuevos sin romper un cliente viejo. El slug de type
es el mismo código en kebab-case.string
requerido
Identifica la ocurrencia y coincide con el header
X-Request-ID. Es lo que va
en un reporte de bug.string
Opcional en RFC 9457, y la API no lo emite.
X-Request-ID. El 401 suma
WWW-Authenticate: Bearer, y el 429, Retry-After.
El catálogo completo
Las extensiones van al nivel raíz del Problem, no anidadas.
invalid_request — 400
El cuerpo o los parámetros no cumplen el contrato: falta un campo requerido,
sobra uno no declarado, o un valor no valida.
array
requerido
Al menos un elemento, con
code y detail obligatorios y un pointer
opcional: un JSON Pointer RFC 6901 al campo culpable, que empieza con /.
Con él marcás el input equivocado en vez de mostrar un texto genérico.unauthorized — 401
No mandaste Authorization, o la clave que mandaste no vale. Es el mismo
error para las dos causas: distinguirlas le diría a un atacante si una clave
existe.
forbidden_connection — 403
La clave autenticó bien, pero el connection_id pedido no pertenece a esa
tienda.
403 y no 404 porque la conexión viaja en el path: el cliente ya sabe que
la pidió. Para recursos de catálogo es al revés: ver not_found.
forbidden_scope — 403
La clave autenticó bien, pero no tiene el scope de la operación:
recommendations:read, catalog:read o signals:write. Una clave no cambia
de scopes: hace falta otra que lo tenga.
not_found — 404
El recurso no existe, o existe y es de otra tienda. Ningún detail dice cuál de los dos es.
conflict — 409
El request choca con el estado actual: una regresión de source_version
en la ingesta de catálogo. Una señal más vieja que la aplicada no pisa el
catálogo.
cart_items_limit_exceeded — 422
El carrito de un pedido de recomendaciones supera el límite configurado.
integer
requerido
El límite vigente,
200 por defecto. Viene en la respuesta para que no lo
hardcodees.integer
requerido
Cuántos ítems mandaste.
signal_batch_limit_exceeded — 422
Un lote de señales del storefront trae más de las permitidas.
integer
requerido
El límite vigente,
50 por defecto. El SDK ya parte los lotes con este número.integer
requerido
Cuántas señales mandaste.
rate_limited — 429
La clave gastó sus 60 pedidos por minuto; Retry-After dice cuántos segundos
esperar. Ver Cuota y caché.
internal_error — 500
Algo se rompió del lado del servidor. El detail nunca trae el stack, el
mensaje interno ni el nombre de un componente.
request_id es imprescindible: conecta lo que viste con el log del
servidor.
signals_unavailable — 503
El almacén de señales del storefront no está disponible. Es transitorio:
reintentá con espera. El SDK lo hace solo, con el mismo signal_id, y un
reintento nunca cuenta dos veces.
Cómo manejarlos desde el SDK
El SDK traduce cualquiera de estos Problems a unCrossUpApiError tipado y
preserva las extensiones que no conoce, para no romperse cuando la API sume
campos.
Usá
isCrossUpApiError(err) y no err instanceof CrossUpApiError:
instanceof falla si hay dos copias del paquete en el árbol de módulos.- No se mira el
Content-Type, se mira la forma del cuerpo. Un proxy puede reescribir el header, y el error se tipa igual. - El status del transporte manda. Si el cuerpo declara otro, la diferencia
queda en
extensions.status: es la prueba de que algo en el medio reescribe respuestas. errorFromResponsenunca lanza. Ante HTML, cuerpo vacío o JSON que no es un Problem devuelve un error sintético concode: "unexpected_response", el status real y el cuerpo crudo.