Saltar al contenido principal

Idempotencia

La API soporta idempotencia para reintentar solicitudes de forma segura, sin ejecutar la misma operación dos veces. Útil cuando una llamada se interrumpe en tránsito y no recibes respuesta — por ejemplo, una solicitud para crear una suscripción que falla por un error de red puede reintentarse con la misma clave, garantizando que solo se cree una suscripción.

Cómo usarlo

Envía la cabecera X-Idempotency-Key: <clave> en cualquier solicitud POST, PUT o PATCH. La clave es opaca y la generas en tu lado. Recomendamos UUID v4 u otra cadena aleatoria con entropía suficiente para evitar colisiones.

curl -i \
-H "Authorization: Bearer $KOBANA_TOKEN" \
-H 'Content-Type: application/json' \
-H 'X-Idempotency-Key: 8c0f5d6e-3f8b-4cb5-9a47-d8f5b15e9b21' \
-H 'User-Agent: Kevin Mitnick <kmitnick@kobana.com.br>' \
-d '{
"subscription": {
"billing_account_id": "ba_01HXY123",
"plan_id": "plan_01HPRO",
"billing_cycle": "monthly"
}
}' \
-X POST 'https://api.billing.sandbox.kobana.com.br/v1/subscriptions'

Cómo funciona

Cuando el servidor recibe una solicitud con X-Idempotency-Key:

  1. Reserva la clave de forma atómica, en el ámbito de tu organización. Dos organizaciones distintas pueden usar la misma clave sin conflicto.
  2. Calcula la huella de la solicitud — SHA-256 de método + ruta + cuerpo en bruto. Ese hash se almacena junto a la clave.
  3. Ejecuta el handler. Si devuelve una respuesta, el servidor registra status_code, cuerpo y cabeceras relevantes vinculados a la clave.
  4. Marca la clave como completada. Cualquier nueva solicitud que reutilice la clave dentro de 24 horas recibe la respuesta original verbatim — mismo status_code, mismo cuerpo, mismas cabeceras — más la cabecera X-Idempotent-Replay: true que indica que se trata de una reejecución.

La capa guarda el resultado independientemente de éxito o fracaso. Los reintentos con la misma clave devuelven el mismo resultado, incluyendo errores 5xx.

Límites

  • Longitud máxima de la clave: 255 caracteres.
  • Retención: las claves expiran automáticamente 24 horas después de su creación. Tras expirar, una nueva solicitud con la misma clave genera un resultado nuevo.
  • Ámbito: por organización. Una clave usada en una organización no interfiere con otra.
  • Caracteres aceptados: cualquier cadena UTF-8 imprimible.

Cuándo el resultado no se guarda

La capa solo guarda el resultado cuando el handler ha comenzado a ejecutarse. No se registra nada en los siguientes casos — es seguro reenviar la solicitud:

  • La clave está vacía o supera los 255 caracteres → respuesta 400 bad_request.
  • El parser del envoltorio de la API rechaza la solicitud antes del handler (JSON inválido, autenticación ausente, etc.).
  • El handler lanza una excepción durante la ejecución — la reserva se libera para que el siguiente reintento pueda correr limpio.
  • Otra solicitud con la misma clave está ejecutándose en paralelo → respuesta 409 conflict con details.reason = "idempotency_request_in_progress".

Conflictos

Si la misma clave se reutiliza con una solicitud diferente (cualquier cambio en método, ruta o cuerpo), la API responde 409 conflict con details.reason = "idempotency_key_reused". Esto protege contra reuso accidental — por ejemplo, persistir la clave junto a la operación en tu lado y luego intentar crear dos recursos diferentes con el mismo identificador.

Respuesta de error

{
"error": {
"code": "conflict",
"message": "X-Idempotency-Key was already used with different request parameters. Reuse the original parameters or generate a new key.",
"details": { "reason": "idempotency_key_reused" }
}
}

Otras respuestas posibles

EscenarioStatuserror.codedetails.reason
Otra solicitud con la misma clave en ejecución409conflictidempotency_request_in_progress
Misma clave reutilizada con un cuerpo distinto409conflictidempotency_key_reused
Clave vacía o mayor que 255 caracteres400bad_requestinvalid_idempotency_key

Métodos aceptados

Método¿Acepta X-Idempotency-Key?
POST✅ Sí
PUT✅ Sí
PATCH✅ Sí
GET❌ No (ya es idempotente por definición)
DELETE❌ No (ya es idempotente por definición)

Enviar la clave en GET o DELETE no tiene efecto — la API procesa la solicitud normalmente sin registrar nada.

Identificando una reejecución

Toda respuesta servida desde el registro lleva la cabecera:

X-Idempotent-Replay: true

Puedes usar esta cabecera en tu lado para distinguir la primera ejecución de una reejecución hecha por el servidor.

Buenas prácticas

  • Una clave por operación lógica. No reutilices la misma clave para crear dos recursos diferentes — recibirás 409 conflict.
  • Persiste la clave junto al estado de la operación en tu lado, para que el reintento tras un crash o reinicio use la misma clave.
  • Combínalo con backoff exponencial ante 5xx o timeout — la clave garantiza que el reintento no duplica el recurso. Como los fallos también se registran, puedes detener los reintentos en cuanto llegue el status code esperado.
  • Descarta la clave a las 24 horas. No tiene sentido mantenerla en tu lado después: el servidor ya ha descartado el registro.
  • No envíes la clave en métodos que no la aceptan. En GET/DELETE se ignora silenciosamente — preferimos que el cliente la omita para dejar claro qué es idempotente por contrato y qué depende de la clave.