Ir al contenido

Idempotencia

Si se corta la conexión después de mandar un pedido que crea o cambia algo, no sabés si llegó. Con una clave de idempotencia lo repetís tranquilo: si ya se había hecho, recibís la misma respuesta y no se hace de nuevo.

Cómo se usa

Mandá el encabezado Idempotency-Key con un valor único por cada cosa que querés que pase una sola vez. Un UUID alcanza. Si tenés que reintentar, usá el mismo valor y el mismo cuerpo.

Un pedido que se puede repetir
curl -X POST "https://panel.kaptativa.app/api/v1/gestion/clientes" \
  -H "Authorization: Bearer TU_TOKEN" \
  -H "Idempotency-Key: 8b1f6c1e-2d0a-4a53-9c0b-0c4e3d7a9f21" \
  -H "Content-Type: application/json" \
  -d '{"nombre":"Ana","apellido":"García"}'
  • Vale en toda operación que no sea de consulta, tanto por su recurso como llamándola por nombre. En las consultas no hace falta: repetirlas no cambia nada.
  • La clave tiene de 1 a 200 caracteres visibles de ASCII: letras sin acento, números y signos, sin espacios en las puntas. Una clave que no cumple responde 422 con el código idempotencia.
  • Se guarda por token: dos tokens pueden usar la misma clave sin pisarse.
  • Se conserva 24 horas. Pasado ese tiempo, la misma clave vuelve a ejecutar el pedido.
  • El mismo cuerpo con las claves del JSON en otro orden es el mismo pedido.

Qué responde un pedido repetido

Respuestas con una clave ya usada
SituaciónRespuestaQué hacer
La misma clave con el mismo pedido, ya terminado bienLa respuesta guardada del primero (el mismo 200 y el mismo cuerpo), con el encabezado Idempotent-Replayed: true. No se ejecuta de nuevo.Nada: es la respuesta que te faltaba.
La misma clave con el mismo pedido, que la primera vez terminó en errorSe ejecuta de nuevo: un pedido rechazado o que falló no cambió nada, y la clave se suelta.Corregí lo que el error decía y repetí, con la misma clave si querés.
La misma clave mientras el primero sigue en curso409 con el código idempotencia.Esperá un momento y repetí el pedido.
La misma clave con otra operación u otros campos422 con el código idempotencia.Es un error de tu lado: cada pedido distinto lleva su propia clave.

La misma operación pedida por su recurso y llamada por su nombre cuentan como dos pedidos distintos, porque la respuesta tiene otra forma: repetir la clave por el otro camino responde 422. Reintentá siempre por el mismo camino.

Lo que la idempotencia no garantiza

Detecta repetidos, no hace atómico el pedido

La clave se anota antes de ejecutar y la respuesta se guarda al terminar. Si el servidor se corta justo entre el cambio y el guardado de la respuesta, la clave queda en curso: al repetir vas a recibir 409 y no la respuesta original.

En ese caso, que es raro, consultá el recurso para ver si el cambio quedó hecho (por ejemplo, buscá el cliente por su email) antes de mandarlo con una clave nueva.

Una operación que hace dos pasos

POST /v1/gestion/tarjetas con vence crea la tarjeta y después le pone el vencimiento. Si ese segundo paso falla, la respuesta es un error y la clave se suelta, pero la tarjeta ya quedó creada: repetir el pedido crea otra. Ante un error con vence, buscá la tarjeta antes de reintentar.

  • El servidor MCP no tiene idempotencia: ahí decide una persona con un asistente, no un sistema que reintenta solo.
  • Un pedido repetido también cuenta para los límites de uso.

En la práctica

  1. Generá la clave cuando nace la intención, no en cada intento: al crear el pedido en tu sistema, no dentro del bucle de reintentos.
  2. Guardala junto con el registro que estás por mandar, así un reinicio de tu proceso reintenta con la misma.
  3. Reintentá con espera creciente ante un corte, un 500, un 429 o un 409 de pedido en curso.
Reintento con la misma clave, en JavaScript
import { randomUUID } from "node:crypto";

async function mandar(direccion, cuerpo, clave = randomUUID()) {
  for (let intento = 0; intento < 5; intento++) {
    const respuesta = await fetch(direccion, {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.KAPTATIVA_TOKEN}`,
        "Content-Type": "application/json",
        "Idempotency-Key": clave,
      },
      body: JSON.stringify(cuerpo),
    }).catch(() => null);
    // Sin respuesta, 409 de pedido en curso, 429 o 5xx: se espera y se repite con la misma clave
    const repetir = !respuesta || [409, 429].includes(respuesta.status) || respuesta.status >= 500;
    if (!repetir) return respuesta;
    const espera = Number(respuesta?.headers.get("retry-after")) || 2 ** intento;
    await new Promise((listo) => setTimeout(listo, espera * 1000));
  }
  throw new Error("La API no respondió después de cinco intentos");
}

Ojo con el 409: también lo usa el código servicio, cuando una regla del negocio no deja hacer el cambio. Ese no se arregla esperando. Si tu integración puede recibirlo, mirá error.codigo antes de repetir.