Volver al blog Conectividad

Claves de idempotencia en una API SMS: cómo evitar duplicados ante reintentos y timeouts

Una clave idempotente puede ayudar a controlar los reintentos de una solicitud HTTP, pero solo si la API define su alcance y comportamiento. Aprende qué acordar antes de repetir un envío y cómo separar la aceptación de la solicitud del estado de entrega.

Diagrama de integración SMS que muestra una clave idempotente, reintentos HTTP y consulta del estado del mensaje

Qué problema resuelve la idempotencia al enviar SMS

Un cliente puede enviar una solicitud HTTP y perder la conexión antes de recibir la respuesta. En ese punto no sabe necesariamente si el servidor procesó la solicitud. Si repite a ciegas un envío que la API trata como una operación nueva, puede provocar una segunda aceptación y, potencialmente, un mensaje duplicado.

Una clave de idempotencia es un mecanismo que una API puede ofrecer para reconocer que varias solicitudes corresponden a una misma operación. Su utilidad depende del contrato concreto de esa API: el estándar HTTP no define por sí solo una clave idempotente ni sus reglas para un endpoint de envío SMS.

  • Objetivo: evitar que el reintento de una misma operación se interprete como una nueva solicitud.
  • Límite: evitar una aceptación duplicada no equivale a garantizar que el mensaje se entregue una sola vez.
  • Antes de implementar reintentos, comprueba en la documentación de la API si admite claves, qué alcance tienen y qué respuesta devuelve al repetirlas.
Qué problema resuelve la idempotencia al enviar SMS

Repetir una petición HTTP no siempre significa repetir el mismo envío

La semántica HTTP distingue entre métodos idempotentes y no idempotentes. Según RFC 9110, una operación es idempotente cuando realizar varias solicitudes idénticas tiene el mismo efecto previsto en el servidor que realizar una sola. La especificación identifica métodos como PUT y DELETE; no clasifica POST como idempotente por defecto.

Por eso, no debe suponerse que reenviar un POST de envío SMS sea seguro. Si la conexión se interrumpe antes de recibir la respuesta, el cliente puede desconocer si la solicitud se ejecutó. RFC 9110 recomienda no reintentar automáticamente una operación no idempotente salvo que se conozca que su semántica es idempotente o se pueda determinar que la solicitud original no se aplicó.

  • Un timeout describe lo que observó el cliente, no necesariamente lo que ocurrió en el servidor.
  • Un rechazo recibido es distinto de una respuesta perdida: si la API devolvió una respuesta, utiliza su código y contrato para decidir el siguiente paso.
  • No conviertas todos los errores HTTP, cierres de conexión o timeouts en un reenvío automático.
Repetir una petición HTTP no siempre significa repetir el mismo envío

Genera una clave estable por operación de negocio

La clave debe identificar una operación lógica que el sistema pueda reconocer en todos sus intentos, por ejemplo, la solicitud de un OTP asociada a un evento interno concreto. Si se genera una clave nueva en cada reintento, la API no tendrá un identificador común con el que relacionar las solicitudes.

La clave no debería construirse incluyendo datos personales o secretos innecesarios. Define su generación y almacenamiento dentro de tu sistema, y evita reutilizarla para una operación distinta. La forma exacta de generar claves, su formato y entropía no está fijada por las fuentes disponibles: debe acordarse con la documentación de la API y los requisitos de seguridad de tu integración.

  • Asigna una clave al crear la operación de negocio, antes del primer intento HTTP.
  • Conserva la misma clave para los reintentos de esa operación.
  • Crea una clave distinta para una operación nueva, aunque coincidan destinatario y contenido.
  • No incluyas credenciales, tokens ni información personal sin necesidad.

Define el ámbito y la duración antes de depender de la clave

Una clave solo es inequívoca dentro del ámbito que establezca la API. El contrato debe aclarar si se interpreta por cuenta, endpoint, operación u otra combinación, así como cuánto tiempo se conserva la asociación entre clave y solicitud. No hay una duración universal establecida para las API SMS.

Si el cliente reintenta después de que la API haya dejado de conservar la clave, el servidor podría tratar la solicitud como nueva. Por tanto, la ventana de retención debe cubrir el periodo durante el que tu sistema puede necesitar recuperar una respuesta perdida, y la aplicación debe conocer qué hacer cuando ese periodo vence.

  • Confirma el ámbito de unicidad de la clave y evita asumir que es global.
  • Documenta la ventana de retención y el comportamiento posterior a su vencimiento.
  • Alinea el periodo de reintentos del cliente con la retención que garantiza el contrato.
  • Si la API no documenta estos puntos, solicita aclaración antes de automatizar reenvíos.

Acuerda qué ocurre si se repite la clave con otro payload

Una clave reutilizada con datos distintos es un caso crítico. El contrato debería precisar cómo compara la API las solicitudes y qué sucede cuando una misma clave llega con un payload incompatible. Una política prudente es que la integración no reutilice la clave para cambiar destinatario, contenido u otros campos que alteren la operación; la respuesta concreta ante el conflicto debe obtenerse de la documentación del servicio.

También conviene saber qué resultado recibe el cliente cuando repite exactamente la solicitud. Algunas APIs pueden devolver un resultado asociado a la primera operación, pero no hay evidencia disponible para afirmar que todas lo hagan. No presupongas reproducción de la respuesta original, ni un código de conflicto específico, sin confirmación del proveedor.

  • Mantén inmutable el payload asociado a una clave durante los reintentos.
  • Define qué campos forman parte de la identidad de la operación.
  • Verifica el comportamiento ante una clave repetida con payload diferente.
  • Registra la respuesta recibida sin interpretarla como prueba de entrega al terminal.

Diseña el tratamiento de timeouts y respuestas perdidas

Cuando no llega una respuesta, la primera decisión no es simplemente reenviar: hay que determinar si la API ofrece una forma segura de repetir la solicitud con la misma clave o de consultar la operación. Si no existe un contrato de idempotencia o un mecanismo para conocer el resultado, el estado puede quedar indeterminado; un nuevo POST podría crear otra operación.

Separa en tu lógica los errores cuya respuesta fue recibida de los casos en que no se recibió ninguna respuesta. Para estos últimos, aplica únicamente las opciones documentadas por la API. No trates un timeout como prueba de que el servidor no ejecutó la solicitud.

  • Guarda la clave y los datos necesarios para correlacionar el intento antes de enviar la petición.
  • Ante una respuesta perdida, reintenta con la misma clave solo si el contrato confirma que es seguro.
  • Si existe una consulta de operación o estado, úsala antes de crear un envío nuevo.
  • Si no hay una vía documentada para resolver la incertidumbre, evita el reenvío ciego y gestiona el caso como indeterminado.

Controla solicitudes simultáneas y persistencia

Dos procesos pueden intentar enviar al mismo tiempo la misma operación, por ejemplo, si una cola vuelve a entregar un trabajo mientras otro trabajador aún lo procesa. La integración debe evitar que la concurrencia local genere claves distintas para el mismo evento de negocio o que pierda la relación entre clave y payload.

La evidencia disponible no define un método universal de almacenamiento atómico ni un mecanismo concreto de bloqueo para una API SMS. Diseña el control en la capa de tu aplicación y confirma cómo la API resuelve solicitudes simultáneas con la misma clave. No asumas que deduplica carreras concurrentes salvo que el contrato lo especifique.

  • Persiste la clave y la identidad de la operación antes de despachar el envío.
  • Haz que los trabajadores concurrentes recuperen la misma clave para la misma operación.
  • Define qué registro local prevalece si dos procesos intentan crear la operación a la vez.
  • Prueba solicitudes simultáneas y verifica el comportamiento documentado del endpoint.

La aceptación no confirma el estado final del mensaje

La clave idempotente, cuando la API la admite, se ocupa de la repetición de una solicitud dentro de un contrato definido. No confirma que el mensaje haya llegado al terminal ni reemplaza el seguimiento de estados. Mantén separados, en el modelo de datos y en los informes, el resultado de la petición HTTP y la información posterior sobre el mensaje.

Si la solicitud fue aceptada pero aún no conoces el estado final, conserva los identificadores y datos de correlación que entregue la API y utiliza los mecanismos de consulta documentados. No generes un envío nuevo solo porque el estado tarde en actualizarse. Un DLR recibido tampoco debe presentarse como verificación independiente de recepción en el terminal si no existe esa verificación.

  • Registra por separado la clave de idempotencia, el resultado HTTP y los identificadores de mensaje disponibles.
  • Consulta o reconcilia estados mediante las capacidades documentadas por la API.
  • No confundas aceptación, estado informado por la ruta y recepción independientemente verificada.
  • No prometas entrega única extremo a extremo basándote únicamente en la idempotencia de la API.
FAQ

Preguntas frecuentes

¿Una clave de idempotencia garantiza que el SMS se entregue una sola vez?

No. Puede ayudar a evitar que una API acepte más de una vez la misma operación, si el servicio define y aplica ese contrato. No demuestra recepción en el terminal ni garantiza entrega única extremo a extremo.

¿Debo reintentar un envío SMS cuando se produce un timeout?

No de forma ciega. Un timeout no demuestra que el servidor no procesó la solicitud. Reintenta con la misma clave solo si la API documenta ese comportamiento, o consulta la operación mediante un mecanismo documentado.

¿Qué sucede si uso la misma clave con un payload diferente?

Depende del contrato de la API. No hay una regla universal demostrada para las API SMS. Mantén el payload inmutable para cada clave y confirma qué respuesta produce el servicio ante una solicitud incompatible.

¿Cuánto tiempo debe conservarse una clave?

La duración depende de la API. Confirma su ventana de retención y alinea con ella el periodo de reintentos de tu cliente; no presupongas una duración estándar.

¿Un DLR confirma que el usuario recibió el mensaje en su teléfono?

No debe tratarse automáticamente como prueba independiente de recepción en el terminal. Conserva la diferencia entre un estado DLR informado y una verificación independiente, si esta está disponible.

Fuentes consultadas

  1. HTTP Semantics (RFC 9110)IETF
  2. SMPP Protocol Specification v3.4SMPP Developers Forum