Saltar al contenido principal
Un aspecto clave de la confiabilidad de Midaz es asegurar que las operaciones sean seguras de reintentar y nunca se procesen más de una vez. Ya sea que esté manejando transacciones o creando entidades, su integración debe ser resiliente, incluso cuando enfrenta problemas de red, tiempos de espera o interrupciones temporales. Esta página explica cómo Midaz protege contra la duplicación usando claves de idempotencia, y cómo puede implementarlas para manejar reintentos en su sistema con confianza.

Hacer que los reintentos sean seguros

En sistemas del mundo real, las solicitudes de API fallidas son comunes. Tal vez ocurra un tiempo de espera de red. Tal vez su servicio se caiga justo después de enviar una solicitud. En estos casos, es natural reintentar, pero ¿cómo puede estar seguro de que Midaz no procesará la misma operación dos veces? Ahí es donde entran las claves de idempotencia. Al adjuntar una clave única a cada solicitud, le está diciendo a Midaz: “Esta es la misma operación. Si ya la has procesado, no la hagas de nuevo.” Midaz almacena esta clave temporalmente y la usa para determinar si la solicitud es nueva, ya completada o todavía en proceso. Esto protege su sistema de duplicados mientras le da control total sobre su estrategia de reintentos.

Idempotencia en Midaz


Midaz usa claves de idempotencia para asegurar que las operaciones de transacción sean seguras de reintentar y nunca se procesen más de una vez. Este mecanismo está disponible en todos los endpoints de transacciones: /transactions/json, /transactions/dsl, /transactions/inflow, /transactions/outflow, /transactions/annotation y /transactions/{id}/revert.
Otros productos de Lerian también soportan idempotencia a través de sus propios encabezados — consulte la sección Idempotencia en los productos Lerian a continuación. Esta página se enfoca en la idempotencia para la API del Midaz Ledger.
Los endpoints commit y cancel de transacciones usan un bloqueo basado en Redis para prevenir el procesamiento concurrente de la misma transacción, pero no soportan idempotencia completa (sin respuestas en caché ni encabezado X-Idempotency-Replayed).
Para usarlo, su solicitud puede incluir dos encabezados:
  • X-Idempotency: la clave única que identifica la solicitud.
  • X-TTL: el tiempo de vida (en segundos) que Midaz debe almacenar esta clave en caché.
Si no envía el encabezado X-Idempotency, Midaz genera uno automáticamente calculando un hash SHA-256 del cuerpo de la solicitud. Esto significa que cuerpos de solicitud idénticos enviados a la misma organización y ledger se deduplicarán automáticamente.
Esto es lo que sucede detrás de escena:
  1. Cuando llega una nueva clave, Midaz la marca como pending, procesa la solicitud y almacena la respuesta completa en caché.
  2. Si la misma clave se usa nuevamente dentro de la ventana TTL:
    1. Si la operación todavía se está ejecutando, Midaz devuelve un 409 Conflict (código de error 0084) con X-Idempotency-Replayed: false.
    2. Si está terminada, Midaz devuelve exactamente la misma respuesta con un código de estado 201 Created y X-Idempotency-Replayed: true.
  3. Si la transacción falla por errores de validación o saldo insuficiente, Midaz elimina la clave de idempotencia, permitiéndole reintentar con la misma clave después de corregir el problema.
En Midaz, las claves de idempotencia están delimitadas por organización y ledger. Esto significa que el mismo valor de clave se puede usar independientemente en diferentes organizaciones o ledgers sin conflicto. Otros productos de Lerian utilizan diferentes estrategias de alcance — consulte la tabla comparativa para más detalles.

Resumen del flujo de trabajo

La Figura 1 muestra el ciclo de vida completo de una solicitud idempotente:
Cómo funciona:
  • Si la solicitud no incluye una clave de idempotencia existente, Midaz crea una nueva (o genera una automáticamente a partir del hash del cuerpo de la solicitud), procesa la solicitud, almacena la respuesta y la devuelve con X-Idempotency-Replayed: false.
  • Si la clave ya existe:
    • Si la operación todavía se está ejecutando, Midaz devuelve un 409 Conflict con X-Idempotency-Replayed: false.
    • Si la operación está completa, Midaz omite la ejecución y devuelve la respuesta en caché con un código de estado 201 Created y X-Idempotency-Replayed: true.
  • Si la solicitud original falló por errores de validación o saldo, la clave se limpia automáticamente, para que pueda reintentar con la misma clave de forma segura.
Este comportamiento garantiza que cada solicitud se maneje de manera segura, predecible y sin duplicación, incluso cuando se reintenta.

Ejemplo de solicitud

Aquí se muestra cómo enviar una solicitud idempotente para crear una transacción:
POST /v1/organizations/{organization_id}/ledgers/{ledger_id}/transactions/json HTTP/1.1
X-Idempotency: 7fb8e1d098cd4730bb932d038b3b8651
X-TTL: 60
Content-Type: application/json

{
  "description": "Pago de suscripción mensual",
  "code": "SUB-2025-001",
  "send": {
    "asset": "USD",
    "value": "1500",
    "source": {
      "from": [
        {
          "accountAlias": "customer-usd-1",
          "amount": {
            "asset": "USD",
            "value": "1500"
          }
        }
      ]
    },
    "distribute": {
      "to": [
        {
          "accountAlias": "merchant-usd-1",
          "amount": {
            "asset": "USD",
            "value": "1500"
          }
        }
      ]
    }
  }
}
Si la solicitud tiene éxito y la envía nuevamente dentro de 60 segundos, Midaz devolverá el resultado en caché con:
HTTP/1.1 201 Created
X-Idempotency-Replayed: true
Si la envía nuevamente mientras la original todavía se está procesando, recibirá:
HTTP/1.1 409 Conflict
X-Idempotency-Replayed: false

Generación de claves


Puede proporcionar su propia clave X-Idempotency o dejar que Midaz genere una automáticamente.

Generación automática de claves

Si omite el encabezado X-Idempotency, Midaz calcula un hash SHA-256 del cuerpo de la solicitud y lo usa como clave de idempotencia. Esto significa que enviar el mismo cuerpo JSON exacto a la misma organización y ledger se deduplicará automáticamente, sin trabajo adicional. Esto es suficiente para la mayoría de escenarios de reintento donde el cuerpo de la solicitud no cambia entre intentos.

Generación personalizada de claves

Use una clave personalizada cuando necesite:
  • Correlacionar la clave de idempotencia con un ID en su propio sistema (por ejemplo, un ID de pedido).
  • Reintentar con la misma clave después de corregir un payload que falló validación o saldo, ya que Midaz elimina la clave en esos casos.
  • Mantener la misma clave cuando el payload sea semánticamente el mismo, aunque su serialización cambie entre intentos.
La clave debe ser determinística: si se reintenta la misma operación lógica, la clave permanece igual. Un enfoque común es usar un UUID o un hash basado en su referencia interna:
import uuid

# Opción 1: Usar un ID de negocio existente como clave
idempotency_key = f"order-{order_id}"

# Opción 2: Generar un UUID y almacenarlo para reintentos
idempotency_key = str(uuid.uuid4())

Mejores prácticas


Siempre valide el header X-Idempotency-Replayed

Cuando su sistema recibe una respuesta de un endpoint de transacción, siempre verifique el header de respuesta X-Idempotency-Replayed antes de procesar el resultado. Este header le indica si la respuesta es de una operación nueva o una reproducción en caché:
  • X-Idempotency-Replayed: false — Esta es una respuesta nueva. La transacción acaba de procesarse.
  • X-Idempotency-Replayed: true — Esta es una respuesta en caché. La transacción ya fue procesada anteriormente.
No verificar este header es un error de integración común. Sin él, su sistema puede interpretar una respuesta reproducida como una nueva transacción, lo que lleva a procesamiento duplicado de su lado — aunque Midaz solo la ejecutó una vez.
Por ejemplo, si su sistema liquida boletos bancarios basándose en las respuestas de transacción, debe verificar X-Idempotency-Replayed para evitar liquidar el mismo boleto dos veces.

Use claves de idempotencia explícitas para flujos críticos

Si bien Midaz genera claves automáticamente a partir del cuerpo de la solicitud, para flujos financieros críticos (liquidaciones, pagos, transferencias), siempre proporcione una clave X-Idempotency explícita vinculada al ID de su proceso de negocio. Esto le brinda:
  • Control total sobre la deduplicación, incluso si el cuerpo de la solicitud cambia ligeramente entre reintentos.
  • Un rastro de auditoría claro que vincula las transacciones de Midaz con sus operaciones internas.
  • Protección contra casos extremos donde la serialización de la solicitud podría diferir.

Establezca valores TTL apropiados

Elija valores TTL que coincidan con su ventana de reintentos:
  • Para operaciones sincrónicas con reintentos rápidos: 60–120 segundos.
  • Para flujos de trabajo asíncronos con posibles retrasos: 300–600 segundos.
  • Para procesamiento por lotes con ventanas de reintento largas: considere TTLs más largos y claves explícitas.

Estrategia de reintentos


Cuando una solicitud falla, cómo reintenta es importante. Aquí están los patrones recomendados para manejar diferentes escenarios de fallo:

Fallos reintentables

Estos fallos son seguros de reintentar con la misma clave de idempotencia:
EscenarioQué hacer
Timeout de red o error de conexiónReintente con la misma clave y cuerpo. Si la solicitud original fue procesada, obtendrá la respuesta en caché.
Error 5xx del servidorReintente con retroceso exponencial. El servidor puede estar temporalmente sobrecargado.
409 Conflict con X-Idempotency-Replayed: falseLa solicitud anterior todavía se está procesando. Espere y reintente después de una breve pausa.
Error de validación o saldoCorrija el problema en su solicitud, luego reintente con la misma clave de idempotencia (Midaz elimina la clave en estos fallos).

Fallos no reintentables

Estos fallos requieren un enfoque diferente:
EscenarioQué hacer
400 Bad Request (error de esquema)Corrija el formato de la solicitud. No reintente el mismo payload.
401 Unauthorized / 403 ForbiddenVerifique sus credenciales de autenticación. Reintentar no ayudará.
404 Not FoundVerifique los IDs de organización, ledger o cuenta en la ruta de su solicitud.

Retroceso exponencial

Para errores transitorios, use retroceso exponencial con jitter para evitar sobrecargar el servidor:
import time
import random
import requests

def create_transaction_with_retry(idempotency_key, payload, max_retries=5, base_delay=1.0):
    """Reintenta con la misma clave de idempotencia en cada intento."""
    for attempt in range(max_retries):
        try:
            response = requests.post(
                f"{BASE_URL}/v1/organizations/{org_id}/ledgers/{ledger_id}/transactions/json",
                headers={
                    "X-Idempotency": idempotency_key,
                    "X-TTL": "300",
                    "Content-Type": "application/json",
                },
                json=payload,
            )
            response.raise_for_status()
            return response.json()
        except requests.exceptions.RequestException:
            if attempt == max_retries - 1:
                raise
            delay = base_delay * (2 ** attempt) + random.uniform(0, 1)
            time.sleep(delay)
Una secuencia típica de reintentos con este patrón sería: 1s, 2s, 4s, 8s, 16s (más jitter aleatorio en cada intento).

Prevención de duplicación de entidades


Para algunos endpoints, no necesita claves de idempotencia para evitar la duplicación. Midaz aplica restricciones de unicidad en recursos críticos. Si intenta crear una entidad que entra en conflicto con una existente, el sistema bloquea la solicitud y devuelve un 409 Conflict con un error descriptivo:
RecursoCampo únicoCódigo de error
LedgerNombre (dentro de la organización)0002
AssetNombre o código (dentro del ledger)0003
SegmentNombre (dentro del ledger)0015
AccountAlias (dentro de la organización y ledger)0020
Account TypeValor de clave (dentro de la organización y ledger)0108
Esto garantiza que sus datos permanezcan limpios, sin ambigüedades y fáciles de gestionar, incluso cuando múltiples servicios están operando en paralelo o cuando los reintentos ocurren automáticamente. A diferencia de las claves de idempotencia, estas restricciones son permanentes y no expiran.

Idempotencia en los productos Lerian


Múltiples productos de Lerian soportan idempotencia, cada uno con su propia convención de headers. La mayoría de los productos retornan el header de respuesta X-Idempotency-Replayed para indicar si la respuesta es un replay del caché. Midaz siempre incluye este header (false para solicitudes nuevas, true para replays), mientras que los demás servicios solo lo agregan cuando la respuesta es un replay — si el header está ausente, la solicitud fue procesada como nueva. PIX Direct no retorna este header.
ProductoEncabezado de solicitudAcepta X-TTLX-Idempotency-ReplayedAlcanceEndpoints cubiertos
MidazX-IdempotencySí (predeterminado 300s)Siempre (false/true)Por organización y ledgerCreación, anotación y reversión de transacciones (6 endpoints)
MatcherX-Idempotency-Key (también acepta Idempotency-Key)NoSolo en replayPor tenant, método y rutaTodos los endpoints POST/PUT/PATCH (~33 endpoints vía middleware global)
TEDX-Idempotency-KeyNoSolo en replayPor clave de idempotencia (sin scoping por tenant)Envío, devolución y cancelación de mensajes (3 endpoints)
PIX IndirectX-IdempotencySolo en replayPor cuentaInicio de cashout, proceso de cashout y reembolso (3 endpoints)
PIX DirectIdempotency-KeyNoNoPor claveCreación de pago e inicio de devolución (2 endpoints)
ReporterX-IdempotencyNoSolo en replayPor claveCreación de reportes y plantillas (2 endpoints)
Midaz siempre incluye el header X-Idempotency-Replayed en la respuesta (false para solicitudes nuevas, true para replays). Los demás servicios (Matcher, TED, PIX Indirect y Reporter) solo agregan este header cuando la respuesta es un replay — si el header está ausente, la solicitud fue procesada como nueva. PIX Direct no retorna este header; su middleware de idempotencia hace replay de la respuesta completa de forma transparente sin un indicador de replay.
Fees Engine, Tracer, Auth y CRM actualmente no soportan encabezados de idempotencia. Las validaciones de Tracer son stateless y naturalmente seguras para reintentar. Las operaciones de tokens de Auth son inherentemente idempotentes. CRM y las entidades de onboarding dependen de restricciones de unicidad en su lugar.

Preguntas frecuentes


Midaz genera una automáticamente calculando un hash SHA-256 del cuerpo de la solicitud. Esto significa que cuerpos de solicitud idénticos enviados a la misma organización y ledger se deduplicarán automáticamente. Solo necesita proporcionar una clave personalizada si desea controlar la deduplicación independientemente del cuerpo de la solicitud.
Sí. Las claves de idempotencia están delimitadas por organización y ledger, por lo que el mismo valor de clave usado en diferentes organizaciones o ledgers no entrará en conflicto. Sin embargo, dentro de la misma organización y ledger, cada clave debe ser única por operación.
En Midaz, las claves de idempotencia están delimitadas por organización y ledger, no por endpoint. Si reutiliza la misma clave en un endpoint diferente dentro de la misma organización y ledger, recibirá la respuesta en caché del endpoint original. Siempre use claves únicas para cada operación distinta.
Solo se usa el TTL de la primera solicitud. Cambiarlo más tarde no tiene efecto.
Sí. Midaz reproduce la respuesta completa, incluyendo código de estado (201 Created), encabezados y cuerpo, para solicitudes completadas.
La ventana predeterminada es de 300 segundos (5 minutos).
Si la transacción falla por errores de validación o saldo insuficiente, Midaz elimina la clave de idempotencia del caché. Esto le permite corregir el problema y reintentar con la misma clave.