La respuesta del operador es tuya, no nuestra
Cuando un envío falla, el operador devuelve un motivo. Guardarse ese motivo y entregar solo la etiqueta convierte el diagnóstico en un ticket de soporte — y traslada a tu equipo un trabajo que ya estaba hecho. Este texto trata de por qué las plataformas lo hacen, por qué nosotros dejamos de hacerlo, y qué cambia en la guardia.

Lo que te llevas
- El error normalizado es un contrato, la respuesta cruda es evidencia, y las dos caben en el mismo payload. El error era tener que elegir una.
- Número inválido, bloqueo del operador y teléfono sin señal son tres problemas con tres respuestas distintas. Bajo una sola etiqueta, los tres se vuelven la misma línea de log.
- Normalizar no es pereza: es lo que permite cambiar de proveedor sin reescribir tu lógica. La pereza era descartar el original después.
- Un campo nuevo no rompe integraciones, pero sí rompe un parser configurado para rechazar claves desconocidas. Por eso existe un plazo, y por eso el plazo se anuncia antes.
El evento que no explica nada
Toda plataforma de mensajería recibe dos cosas cuando un envío falla. La primera es la respuesta cruda del proveedor de canal, con el código y el texto que emitió. La segunda es la clasificación que la plataforma hace de esa respuesta, para que quepa en un vocabulario estable. Casi todas entregan la segunda y se quedan con la primera.
El efecto aparece en la guardia. El evento dice que falló y ahí se detiene. No hay forma de distinguir un número que no existe de un bloqueo del operador de un teléfono sin señal desde ayer. Son tres problemas con tres respuestas distintas — el primero pide corregir un registro, el segundo pide hablar con quien lleva la ruta, el tercero pide solo esperar — y ninguno aparece en el payload.
Entonces el equipo abre un ticket. Del otro lado, alguien consulta un log y responde por escrito, horas después, con un dato que ya estaba en el sistema en el instante exacto del fallo. El trabajo no se hizo en ese intervalo: se trasladó. Y se trasladó a quien tiene menos contexto sobre la operación del cliente que el propio cliente.
Lo que vuelve esto incómodo es que la información nunca estuvo perdida. Llegó, se leyó, se usó para decidir la clasificación, y se descartó justo después. No es un caso de dato que nadie tenía; es un caso de dato que alguien tuvo un instante y no pasó adelante.
Por qué la plataforma normaliza, y por qué eso no es pereza
Vale defender la normalización antes de criticar lo que se hace con ella, porque existe por un buen motivo. Cada proveedor de canal tiene su propio diccionario de errores, con códigos propios, agrupaciones propias y mensajes en idiomas distintos. Escribir lógica de negocio directamente encima de eso significa reescribirla entera cada vez que cambia la ruta — y la ruta cambia por motivos comerciales, de calidad, de disponibilidad, muchas veces sin que quien integra se entere.
La clasificación resuelve eso. Da un vocabulario que no depende de quién entregó el mensaje, y es sobre ese vocabulario que deben escribirse el reintento, la alerta y el informe. Una integración acoplada al campo normalizado sobrevive a un cambio de proveedor sin una línea alterada, y esa promesa vale mucho más de lo que parece el día en que hay que cumplirla.
Así que la pereza no es normalizar: es descartar el original después. Las dos cosas resuelven problemas distintos y no compiten por espacio. La clasificación existe para que decida la máquina; el original existe para que entienda una persona. Entregar solo la primera es asumir que nadie va a necesitar la segunda — y la existencia de la cola de tickets demuestra que esa suposición es falsa.
Dos campos, dos trabajos
Hay un argumento honesto en contra de exponer el código del proveedor, y merece tomarse en serio. Exponerlo acopla a quien integra con un proveedor que esa persona no eligió y que puede cambiarse sin aviso. Un código que hoy significa bloqueo puede no existir en el proveedor siguiente, y la lógica escrita encima se rompe en la migración — en silencio, que es peor.
El argumento es correcto, y justamente por eso la respuesta son dos campos y no uno. El campo normalizado lleva la clase del error y nunca cambia de significado. El campo crudo lleva proveedor, código y mensaje tal como llegaron. Uno sirve para que decida la aplicación, el otro para que entienda una persona. Nombrarlos por separado es lo que impide que se confundan.
Esa separación es lo que convierte el cambio de proveedor en un evento sin drama. La evidencia cambia, porque es del proveedor. El contrato se queda, porque es nuestro. Quien escribió la lógica sobre el campo normalizado no reescribe nada, y quien leía el campo crudo en la guardia verá códigos distintos — lo cual es correcto, porque quien respondió de hecho es otro.
Viene con una responsabilidad que conviene decir en voz alta: quien lee el campo crudo necesita saber que no es un contrato. Está en la documentación y está en la lista de arriba, pero repetirlo no cuesta nada. Escribe una condicional sobre el código del proveedor y funcionará durante meses, y fallará el día de la migración, y el defecto parecerá nuestro.
Qué cambia en la guardia
La ganancia no es filosófica y aparece rápido. Con el proveedor y el código originales en el mismo evento, la primera persona que mira ya separa un problema de registro de un problema de ruta. El registro se arregla internamente y ahora; la ruta se convierte en una conversación con quien la opera. Son caminos distintos, y elegir el equivocado cuesta el turno entero.
Cambia también lo que pasa cuando el ticket hace falta de verdad. En lugar de abrir con "los mensajes están fallando", abre con el proveedor, el código, el mensaje original y la hora. Quien lo recibe no tiene que pedir información antes de empezar a mirar, y la primera respuesta deja de ser una pregunta.
Y cambia lo que se puede automatizar. Una alerta que dispara sobre el campo normalizado es estable pero gruesa: avisa de que subió la clase de error. Con el campo crudo en el mismo evento, esa alerta puede llevar en el cuerpo qué código concreto subió — sin que nadie escriba lógica encima. Contexto en una notificación y acoplamiento en la lógica son cosas distintas, y solo la segunda es peligrosa.
Por qué un campo nuevo aún necesita plazo
La promesa publicada es que pueden aparecer campos nuevos y que los campos existentes no cambian de tipo ni de significado. Funciona porque quien consume tolera claves desconocidas. Y no todo el mundo las tolera: un webhook que valida el payload contra un schema estricto rechaza el evento entero por un campo que ni siquiera quería leer.
Eso no es un error de quien integró. La validación estricta es una decisión defendible, y en algunos sectores es obligatoria. Lo que significa en la práctica es que "añadir un campo es retrocompatible" es verdad desde el punto de vista del formato y no lo es desde el de todo consumidor real — y la distancia entre esas dos afirmaciones es donde se rompen las integraciones.
Por eso el campo se anunció el 18 de julio para entrar en vigor el 18 de agosto, en el changelog y por correo, con la acción necesaria escrita en la propia entrada. Un mes no es cortesía. Es reconocer que la compatibilidad es un contrato de dos lados, y que el lado del cliente a veces tiene que tocar código antes de que el cambio llegue.
La regla vale igual en la dirección contraria. Nada se elimina sin seis meses de aviso, con sustituto documentado desde el primer día y con las dos rutas funcionando en paralelo durante todo el periodo. Una obsolescencia anunciada sin coexistencia real no es una obsolescencia: es una eliminación con preaviso, y la diferencia la nota quien tiene que reescribir una integración contra una fecha.
El principio, para cuando el caso sea otro
La regla que sale de aquí es más general que este campo. Cuando la plataforma procesa un dato de un tercero para producir una abstracción, se queda con dos cosas en la mano, y la abstracción es la menos informativa de las dos. Entregar solo la abstracción es cómodo para quien la construyó y caro para quien depende de ella en un mal momento.
La prueba es simple y sirve para cualquier campo: si alguien de tu equipo tuvo que abrir un ticket para descubrir algo que la plataforma ya sabía en el instante del evento, ese algo tenía que estar en el evento. No como contrato, no como promesa de estabilidad — como evidencia, nombrada de forma que nadie confunda una cosa con la otra.
Por eso este es un post sobre un campo y no sobre una funcionalidad. El campo es pequeño. Lo que dice sobre quien construye la plataforma es que el dato del cliente es del cliente, incluso cuando es feo, incluso cuando llega en otro idioma, e incluso cuando entregarlo significa admitir que la ruta falló por un motivo que preferiríamos no enseñar.