Reintentar API sin duplicados en n8n, paso a paso
En pocas palabras: Usá una clave de idempotencia estable derivada de datos invariantes (como el orderId), no un timestamp ni $execution.id. El nodo “Retry on Fail” de n8n repite la petición, pero la deduplicación la garantiza esa clave: Stripe la lee en Idempotency-Key; PayPal, en PayPal-Request-Id.
Reintentar API sin duplicados en n8n exige tres cosas: una clave de operación estable, reintentar solo los fallos transitorios y registrar el resultado ya confirmado. El nodo “Retry on Fail” repite la petición fallida, pero no evita duplicados solo: si el POST ya se ejecutó del otro lado, lo vuelve a mandar igual.
Reintentar una petición HTTP en n8n es volver a ejecutar un nodo que falló. La idempotencia es la garantía de que repetir la misma operación produce el mismo resultado, sin efectos secundarios extra. n8n aporta el mecanismo de reintento; la idempotencia la ponés vos con una clave estable y, cuando la API lo soporta, con su cabecera de idempotencia nativa (Stripe, PayPal).
En 30 segundos
- Un timeout puede esconder una operación exitosa: la orden se creó, pero la respuesta nunca volvió a n8n.
- Reintentá con la MISMA clave de operación (derivada de datos invariantes como el orderId), nunca con un timestamp o el $execution.id.
- Stripe usa la cabecera
Idempotency-Key; PayPal usaPayPal-Request-Id. Con esas claves, dos POST idénticos devuelven la misma operación. - Reintentá timeouts, 429 y 500/502/503/504. NO reintentes a ciegas 400, 401, 403 ni la mayoría de los 404.
- Para APIs sin idempotencia nativa, guardá un ledger en base de datos ANTES de llamar y consultalo antes de reintentar.
¿Por qué los reintentos crean duplicados en n8n?
Porque un timeout no significa que la operación haya fallado. Ponele que tu workflow crea una orden de pago con un POST. La API la procesa, la guarda, empieza a devolver el 200, y justo ahí se corta la red. n8n nunca recibe la respuesta, marca el nodo como fallido y lo reintenta. Resultado: dos órdenes del lado del proveedor, un solo cliente.
Esa es la diferencia que casi nadie configura bien: fallo de red distinto de fallo real. Cuando la petición nunca llegó al servidor, reintentar es seguro. Cuando llegó, se ejecutó y solo se perdió la respuesta, reintentar duplica. Y desde afuera un timeout se ve igual en los dos casos.
El nodo “Retry on Fail” de n8n no distingue nada de esto. Repite el nodo tal cual. Si el POST no tenía protección contra duplicados, lo repite y ya está el problema. Por eso el reintento por sí solo no alcanza: necesitás que la operación sea idempotente o que vos la vuelvas idempotente. Complementá con expresiones para validar respuestas.
¿Cuál es la diferencia entre una operación idempotente y una que no lo es?
Una operación idempotente da el mismo resultado la ejecutes una o cien veces. El estándar HTTP define GET, HEAD, OPTIONS y TRACE como métodos seguros, y considera idempotentes a PUT, DELETE y a los métodos seguros. POST no es idempotente por defecto: cada POST puede crear un objeto nuevo.
Eso sí: la semántica HTTP es solo el punto de partida. La documentación del proveedor es el contrato real. Un DELETE puede ser inofensivo de repetir (borrás algo que ya no está, no pasa nada). Pero un POST que cobra un pago, reserva stock o dispara un email necesita protección explícita contra duplicados. No te fíes del método, fijate qué hace la API.
Un ejemplo concreto. Con Stripe, un POST que crea un cargo es peligroso de reintentar sin protección: podés cobrar dos veces. Con una API de emails transaccionales sin idempotencia nativa, reintentar manda dos correos al mismo cliente. La corrección no es la misma en cada caso, y por eso conviene ir paso a paso.
Paso 1: crear una clave de operación única y estable
La clave de operación es un identificador único que representa una acción de negocio, derivado de datos que NO cambian entre reintentos. Se arma con un template de n8n a partir de campos invariantes, no con valores que muten en cada corrida.
- Usá datos invariantes. El orderId, el paymentId o el email del cliente identifican la operación de negocio y son iguales en el intento 1 y en el intento 3.
- Sintaxis n8n típica:
create-order:{{ $json.orderId }}. Así la clave queda pegada a la orden, no a la ejecución. - Nunca uses timestamps ni $execution.id. Cambian en cada reintento, y una clave distinta rompe la idempotencia: para la API es una operación nueva.
El punto es que la clave tiene que ser idéntica en todos los reintentos del mismo nodo. Si cambia, perdés todo el beneficio. Es el error más común y el más silencioso, porque el workflow “funciona” hasta el día que hay un timeout real. Lo explicamos a fondo en registrar intentos en bases externas.
Paso 2: usar las claves de idempotencia nativas de cada API
Cuando la API tiene idempotencia nativa, mandás tu clave estable en la cabecera HTTP que el proveedor define y él se encarga de deduplicar. Con dos POST que llevan la misma clave, la API ejecuta la operación una sola vez y devuelve el resultado guardado en el segundo intento. Es la opción más limpia y la que deberías priorizar.
- Stripe: según la documentación oficial de Stripe, se envía la cabecera
Idempotency-Key. Reintentos con la misma clave devuelven la respuesta original. - PayPal: según la referencia de idempotencia de PayPal, la cabecera es
PayPal-Request-Id, con formato UUID recomendado. - APIs sin soporte nativo: muchas APIs de email o de terceros no tienen esta cabecera. Ahí vas al Paso 4, con un ledger propio.
En el nodo HTTP Request de n8n esto se configura en la sección de Headers: agregás el header con el nombre exacto que pide el proveedor y como valor tu clave estable del Paso 1. Si la API exige UUID v4, generalo una vez desde un dato invariante y guardalo, no lo regeneres en cada corrida.
| Proveedor | Cabecera de idempotencia | Método afectado | Qué hacés en n8n |
|---|---|---|---|
| Stripe | Idempotency-Key | POST (cargos, clientes) | Header con clave estable |
| PayPal | PayPal-Request-Id | POST (órdenes, pagos) | Header con UUID derivado |
| API de email sin soporte | Ninguna | POST (envío) | Ledger en base de datos |
| Endpoint DELETE genérico | No necesaria | DELETE | Reintento directo (idempotente) |
Paso 3: configurar reintentos acotados con backoff exponencial
Los reintentos se activan en la configuración del nodo, con “Retry on Fail”, un máximo de intentos y una espera entre cada uno. La clave está en acotarlos: sin límite, un fallo permanente se convierte en un bucle que golpea la API para siempre y te puede ganar un baneo por rate limit.
- Max retries: 3 es un valor razonable para arrancar. Más que eso rara vez ayuda si el fallo no es transitorio.
- Backoff exponencial: esperá 1s, 2s, 5s entre intentos en vez de martillar cada 100ms. Le das aire al servicio para recuperarse.
- Respetá el 429. Ante “Too Many Requests”, esperá la ventana que indica el header
Retry-Afterantes de volver a intentar.
Los límites no son un detalle. Un reintento infinito contra un endpoint caído multiplica la carga justo cuando el servicio está peor, y encima consume ejecuciones de tu instancia. Si corrés n8n self-hosted en un VPS, por ejemplo en donweb.com, ese bucle también te come CPU y memoria de tu propio servidor.
Paso 4: un ledger de duplicados para APIs sin idempotencia nativa
Cuando la API no tiene cabecera de idempotencia, la deduplicás vos con una tabla en base de datos. La idea es guardar la clave ANTES de llamar a la API y, ante un timeout, consultar esa tabla antes de reintentar. Si la operación ya figura como completada, usás el resultado guardado en lugar de volver a llamar.
Un esquema mínimo en Postgres tiene cuatro columnas: idempotency_key (única), status (pending / done), external_id (el ID que devolvió la API) y timestamp. El flujo en n8n queda así: insertás la fila como “pending”, llamás a la API, y al recibir respuesta actualizás a “done” con el external_id. Si un reintento encuentra la clave ya en “done”, corta y devuelve el external_id sin llamar de nuevo. Tema relacionado: configurar correctamente tus requests.
¿Y si el nodo murió justo entre el insert y la respuesta? Ahí la fila queda en “pending” y tu lógica decide: consultás a la API por esa clave si tiene endpoint de búsqueda, o marcás para revisión manual. No es magia, pero cierra el hueco que la idempotencia nativa te cerraría sola.
¿Cómo decidir qué código de error se reintenta?
La regla corta: reintentá los fallos transitorios, no los del cliente. Un timeout o un reset de conexión son candidatos claros a reintento con la misma clave. Un 400 o un 403 no se arreglan repitiendo lo mismo, hay que corregir la petición primero. Este es el mapa de decisión que conviene tener a mano.
| Situación | Acción | Riesgo de duplicado |
|---|---|---|
| Timeout o reset de red | Reintentar con la misma clave de operación | Alto: el servidor pudo haber ejecutado la acción |
| 429 Too Many Requests | Esperar la ventana (Retry-After) y reintentar | Controlado si la operación es idempotente |
| 500, 502, 503, 504 | Reintento acotado si el proveedor lo permite | Potencialmente alto en peticiones que cambian estado |
| 400, 401, 403, casi todos los 404 | Corregir petición, credenciales o permisos primero | El reintento a ciegas casi nunca arregla la causa |
Ojo con los 500 en operaciones que cambian estado. Un 502 puede significar que tu petición sí llegó al backend y se ejecutó, y que solo falló el proxy de vuelta. Por eso, para POST de pago, reintentar un 5xx sin clave de idempotencia es igual de riesgoso que reintentar un timeout.
Errores comunes al configurar reintentos en n8n
- Regenerar la clave en cada intento. Usar
$execution.ido un timestamp como clave de idempotencia la vuelve inútil: cada reintento pide una operación nueva y duplicás igual. Derivá la clave de datos del negocio. - Reintentar errores 4xx. Poner “Retry on Fail” sin filtrar el código de estado hace que un 401 por token vencido reintente tres veces y falle tres veces. Reintentá solo timeouts, 429 y 5xx.
- Dejar los reintentos sin tope. Sin max retries ni backoff, un endpoint caído genera un bucle que satura la API y tu instancia. Poné 3 intentos y espera creciente.
- Confiar en que POST es seguro. Asumir que “Retry on Fail” evita duplicados por sí solo es el malentendido de fondo. n8n repite el nodo, no deduplica nada.
Preguntas Frecuentes
¿Cómo evita n8n crear duplicados al reintentar una petición?
n8n por sí solo no lo evita: el nodo “Retry on Fail” repite la petición fallida tal cual. La deduplicación la lográs con una clave de operación estable enviada en la cabecera de idempotencia de la API (como Idempotency-Key en Stripe) o, si la API no la soporta, con un ledger propio en base de datos.
¿Qué es una clave de idempotencia?
Es un identificador único que representa una operación de negocio y que enviás a la API para que ejecute esa acción una sola vez, aunque la petición llegue repetida. Si mandás dos POST con la misma clave, la API procesa el primero y devuelve el resultado guardado en el segundo, sin duplicar. Cubrimos ese tema en detalle en alertar sobre fallos de API.
¿Cómo sé si una API es idempotente antes de reintentar?
Mirá el método HTTP y la documentación del proveedor. GET, HEAD, PUT y DELETE se consideran idempotentes por semántica; POST no lo es por defecto. Pero la regla final la pone la API: buscá en su documentación si soporta una cabecera de idempotencia y qué garantiza cada endpoint.
¿Cuál es la diferencia entre reintento e idempotencia?
El reintento es el mecanismo que vuelve a ejecutar una petición fallida; la idempotencia es la garantía de que repetir esa petición no genera efectos secundarios extra. n8n aporta el reintento con “Retry on Fail”; la idempotencia la asegurás vos con una clave estable y la cabecera de la API.
¿Cómo implemento reintentos seguros para órdenes de pago en n8n?
Generá una clave estable desde el orderId, enviala en la cabecera de idempotencia del proveedor (Idempotency-Key en Stripe, PayPal-Request-Id en PayPal), activá “Retry on Fail” con máximo 3 intentos y backoff exponencial, y reintentá solo timeouts, 429 y 5xx. Nunca reintentes con una clave que cambie entre intentos.
Conclusión
El cambio de mentalidad es simple: el reintento y la deduplicación son dos problemas distintos, y n8n solo te resuelve el primero. “Retry on Fail” repite el nodo, nada más. Si querés reintentar API sin duplicados, la idempotencia la ponés vos.
Qué hacer hoy, en orden: derivá una clave de operación estable de datos invariantes, mandala en la cabecera de idempotencia cuando la API la soporte, acotá los reintentos a 3 con backoff exponencial, y para las APIs sin soporte nativo montá un ledger en base de datos. Reintentá timeouts, 429 y 5xx; no toques los 4xx. Con eso, un timeout deja de ser una lotería de órdenes duplicadas.
Fuentes
- Retry Failed n8n API Requests Without Creating Duplicates – guía original del patrón (dev.to, 13/08/2026)
- Stripe API – Idempotent Requests (documentación oficial de la cabecera Idempotency-Key)
- PayPal REST API – Idempotency (referencia oficial de PayPal-Request-Id)
- Guía de claves de idempotencia para integración de APIs (Didit)
- Integración segura con APIs de terceros: reintentos, timeouts e interruptores (Koder)






