Saltar al contenido principal

Respuestas de error

Las tres APIs (instance-api, saascore-api, services-api) responden todos los errores con el mismo formato: RFC 9457 application/problem+json. Un cliente decide cómo reaccionar leyendo el campo code (estable y legible por máquina), no el texto de detail.

Envelope

Campos del cuerpo de error:

CampoTipoPresenciaSignificado
typestring (URI)siempreURI dereferenciable del error: https://docs.fidelizador.com/errors/<code-kebab>. Es el code con guiones.
titlestringsiempreFrase HTTP del status (Conflict, Not Found, ...). Legible por humanos, no para máquina.
statusnumbersiempreCódigo HTTP, repetido en el cuerpo.
detailstringsiempreMensaje en inglés (fallback para integradores y logs). Descriptivo en 4xx de cliente (404/409/422); genérico en 401/403 y 5xx (el motivo real solo va al log). El frontend nunca localiza desde detail — usa code para derivar la traducción.
codestringsiempreDiscriminador estable. El valor sobre el que un cliente hace switch. Independiente del status y del type.
trace_idstringsiempreID de traza OTel para correlación cross-servicio. Presente en todos los errores.
errorsarraysolo 422Lista de errores por campo (ver Errores por campo).

Miembros extra: algunos errores agregan campos planos adicionales (p. ej. limit y upgrade_url en el 402 de billing). Un cliente debe ignorar los campos que no conoce.

Ejemplo (409, observado):

{
"type": "https://docs.fidelizador.com/errors/domain-already-exists",
"title": "Conflict",
"status": 409,
"detail": "Domain already exists: example.com",
"code": "domain_already_exists",
"trace_id": "dbb56202f13e1c15473bc6044ede8539"
}

Toda respuesta (éxito o error) lleva además el header X-Request-Id (correlación + audit) y, cuando hay traza OTel activa, X-Trace-Id; el request_id no va en el cuerpo. Para el formato de éxito (2xx) — envelope bare / colección, status codes y paginación — ver Paginación y formato de respuesta.

Tabla resumen

El sufijo de type es siempre el code con guiones — no se repite por fila.

20 de 20

400Request mal formado1 código
bad_requesttodasPetición malformada (query/body inválido).
401No autenticado1 código
unauthorizedtodasCredencial ausente, inválida o expirada.
402Límite de plan o suscripción6 códigos
plan_user_limit_exceededsaascore-apiAgregar usuario supera el cupo de asientos del plan.
plan_send_limit_exceededinstance-apiEnviar supera la cuota de envíos del plan para el ciclo de reset del medidor (incluye limit/remaining/reset_at).
plan_custom_domains_limit_exceededinstance-apiCrear un dominio supera el cupo de dominios personalizados del plan.
plan_senders_limit_exceededinstance-apiCrear un remitente supera el cupo de remitentes del plan.
plan_api_access_control_unavailableinstance-apiCrear o editar una API key con permisos finos (acceso scoped) pero el plan no incluye el control de acceso de API.
subscription_inactivesaascore-apiinstance-apiSin suscripción usable / entitlement no resoluble (fail-closed).
403Sin permiso2 códigos
forbiddentodasSin permiso: scope, rol, o instancia deshabilitada.
ip_not_allowedinstance-apiLa dirección de origen no está en la whitelist de la instancia ni en la de la credencial.
404Recurso no encontrado2 códigos
<recurso>_not_found (not_found solo en ruta inexistente)todasEl recurso no existe.
mail_outside_retentioninstance-apiEl mail_id consultado es anterior a la ventana de retención en línea.
405Método no permitido1 código
method_not_allowedtodasVerbo HTTP incorrecto.
409Conflicto1 código
<dominio> (p. ej. domain_already_exists)todasViolación de unicidad o regla de negocio. Siempre específico de dominio.
413Request demasiado grande1 código
request_too_largeinstance-apiLa petición supera alguna cota de tamaño (cuerpo, descompresión, adjunto, mensaje o ancho de banda).
415Media type no soportado1 código
unsupported_media_typetodasContent-Type no soportado.
422Validación fallida1 código
validation_errortodasFalla de validación de esquema (incluye errors[]).
429Rate limit excedido1 código
rate_limit_exceededinstance-apiLímite de ancho de banda de la instancia (incluye header Retry-After).
500Error interno1 código
internal_errortodasError no manejado. Cuerpo siempre genérico.
503Servicio no disponible1 código
service_unavailableinstance-apiUna dependencia no respondió. El detail nombra cuál.
En esta página