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 invitar a un usuario del portal que se corta por un error de red puede repetirse con la misma clave, garantizando que solo se cree un usuario y solo se envíe una invitació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 '{
"email": "joao@example.com",
"tenant_id": "cliente-1042"
}' \
-X POST 'https://api.dashboards.sandbox.kobana.com.br/v1/portal_users'
Cómo funciona
Cuando el servidor recibe una solicitud con X-Idempotency-Key:
- Reserva la clave de forma atómica, en el ámbito de tu organización. Dos organizaciones distintas pueden usar la misma clave sin conflicto.
- Calcula la huella de la solicitud — SHA-256 de
método + ruta + cuerpo en bruto. Ese hash se almacena junto a la clave. - Ejecuta el handler. Si devuelve una respuesta, el servidor registra
status_code, cuerpo y cabeceras relevantes vinculados a la clave. - 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 cabeceraX-Idempotent-Replay: trueque 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 conflictcondetails.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
| Escenario | Status | error.code | details.reason |
|---|---|---|---|
| Otra solicitud con la misma clave en ejecución | 409 | conflict | idempotency_request_in_progress |
| Misma clave reutilizada con un cuerpo distinto | 409 | conflict | idempotency_key_reused |
| Clave vacía o mayor que 255 caracteres | 400 | bad_request | invalid_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
5xxo 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/DELETEse ignora silenciosamente — preferimos que el cliente la omita para dejar claro qué es idempotente por contrato y qué depende de la clave.