Pular para o conteúdo principal
Um aspecto fundamental da confiabilidade do Midaz é garantir que as operações sejam seguras para retentativa e nunca processadas mais de uma vez. Seja ao lidar com transações ou criar entidades, sua integração deve ser resiliente, mesmo diante de falhas de rede, timeouts ou interrupções temporárias. Esta página explica como o Midaz protege contra duplicações usando chaves de idempotência, e como você pode implementá-las para lidar com retentativas no seu sistema com confiança.

Tornando as retentativas seguras

Em sistemas reais, falhas em requisições de API são comuns. Talvez ocorra um timeout de rede. Talvez seu serviço caia logo após enviar uma requisição. Nesses casos, é natural tentar novamente, mas como você pode ter certeza de que o Midaz não processará a mesma operação duas vezes? É aí que as chaves de idempotência entram em ação. Ao anexar uma chave única a cada requisição, você está dizendo ao Midaz: “Esta é a mesma operação. Se você já a processou, não faça novamente.” O Midaz armazena essa chave temporariamente e a utiliza para determinar se a requisição é nova, já foi concluída ou ainda está sendo processada. Isso protege seu sistema contra duplicatas enquanto oferece controle total sobre sua estratégia de retentativa.

Idempotência no Midaz


O Midaz usa chaves de idempotência para garantir que as operações de transação sejam seguras para retentativa e nunca processadas mais de uma vez. Este mecanismo está disponível em todos os endpoints de transações: /transactions/json, /transactions/dsl, /transactions/inflow, /transactions/outflow, /transactions/annotation e /transactions/{id}/revert.
Outros produtos da Lerian também suportam idempotência através de seus próprios headers — veja a seção Idempotência nos produtos Lerian abaixo. Esta página foca na idempotência para a API do Midaz Ledger.
Os endpoints commit e cancel de transações usam um lock baseado em Redis para prevenir processamento concorrente da mesma transação, mas não suportam idempotência completa (sem respostas em cache ou header X-Idempotency-Replayed).
Para usá-lo, sua requisição pode incluir dois headers:
  • X-Idempotency: a chave única que identifica a requisição.
  • X-TTL: o tempo de vida (em segundos) que o Midaz deve armazenar essa chave em cache.
Se você não enviar o header X-Idempotency, o Midaz gera um automaticamente calculando um hash SHA-256 do corpo da requisição. Isso significa que corpos de requisição idênticos enviados para a mesma organização e ledger são automaticamente deduplicados.
Veja o que acontece nos bastidores:
  1. Quando uma nova chave chega, o Midaz a marca como pending, processa a requisição e armazena a resposta completa em cache.
  2. Se a mesma chave for usada novamente dentro da janela de TTL:
    1. Se a operação ainda estiver em execução, o Midaz retorna um 409 Conflict (código de erro 0084) com X-Idempotency-Replayed: false.
    2. Se estiver concluída, o Midaz retorna exatamente a mesma resposta com código de status 201 Created e X-Idempotency-Replayed: true.
  3. Se a transação falhar por erros de validação ou saldo insuficiente, o Midaz deleta a chave de idempotência, permitindo que você retente com a mesma chave após corrigir o problema.
No Midaz, as chaves de idempotência são escopadas por organização e ledger. Isso significa que o mesmo valor de chave pode ser usado independentemente em diferentes organizações ou ledgers sem conflito. Outros produtos da Lerian utilizam estratégias de escopo diferentes — consulte a tabela comparativa para mais detalhes.

Resumo do fluxo

A Figura 1 mostra o ciclo de vida completo de uma requisição idempotente:
Como funciona:
  • Se a requisição não incluir uma chave de idempotência existente, o Midaz cria uma nova (ou gera uma automaticamente a partir do hash do corpo da requisição), processa a requisição, armazena a resposta e a retorna com X-Idempotency-Replayed: false.
  • Se a chave já existir:
    • Se a operação ainda estiver em execução, o Midaz retorna um 409 Conflict com X-Idempotency-Replayed: false.
    • Se a operação estiver concluída, o Midaz ignora a execução e retorna a resposta em cache com código de status 201 Created e X-Idempotency-Replayed: true.
  • Se a requisição original falhou por erros de validação ou saldo, a chave é limpa automaticamente, permitindo que você retente com a mesma chave de forma segura.
Esse comportamento garante que cada requisição seja tratada de forma segura, previsível e sem duplicação, mesmo quando retentada.

Exemplo de requisição

Veja como enviar uma requisição idempotente para criar uma transação:
POST /v1/organizations/{organization_id}/ledgers/{ledger_id}/transactions/json HTTP/1.1
X-Idempotency: 7fb8e1d098cd4730bb932d038b3b8651
X-TTL: 60
Content-Type: application/json

{
  "description": "Pagamento de assinatura mensal",
  "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"
          }
        }
      ]
    }
  }
}
Se a requisição for bem-sucedida e você enviá-la novamente dentro de 60 segundos, o Midaz retornará o resultado em cache com:
HTTP/1.1 201 Created
X-Idempotency-Replayed: true
Se você enviá-la novamente enquanto a original ainda estiver sendo processada, você receberá:
HTTP/1.1 409 Conflict
X-Idempotency-Replayed: false

Geração de chaves


Você pode fornecer sua própria chave X-Idempotency ou deixar o Midaz gerar uma automaticamente.

Geração automática de chaves

Se você omitir o header X-Idempotency, o Midaz calcula um hash SHA-256 do corpo da requisição e o usa como chave de idempotência. Isso significa que enviar o mesmo corpo JSON exato para a mesma organização e ledger será automaticamente deduplicado — sem trabalho adicional. Isso é suficiente para a maioria dos cenários de retentativa onde o corpo da requisição não muda entre tentativas.

Geração personalizada de chaves

Use uma chave personalizada quando precisar:
  • Correlacionar a chave de idempotência com um ID no seu próprio sistema (ex: um ID de pedido).
  • Retentar com um corpo de requisição modificado e ainda assim deduplicar (ex: após corrigir um campo).
  • Controlar o formato da chave para fins de log ou auditoria.
A chave deve ser determinística: se a mesma operação lógica for retentada, a chave permanece a mesma. Uma abordagem comum é usar um UUID ou um hash baseado na sua referência interna:
import uuid

# Opção 1: Usar um ID de negócio existente como chave
idempotency_key = f"order-{order_id}"

# Opção 2: Gerar um UUID e armazená-lo para retentativas
idempotency_key = str(uuid.uuid4())

Boas práticas


Sempre valide o header X-Idempotency-Replayed

Quando seu sistema recebe uma resposta de um endpoint de transação, sempre verifique o header de resposta X-Idempotency-Replayed antes de processar o resultado. Esse header indica se a resposta é de uma operação nova ou um replay do cache:
  • X-Idempotency-Replayed: false — Esta é uma resposta nova. A transação acabou de ser processada.
  • X-Idempotency-Replayed: true — Esta é uma resposta em cache. A transação já foi processada anteriormente.
Não verificar esse header é um erro de integração comum. Sem ele, seu sistema pode interpretar uma resposta repetida como uma nova transação, levando a processamento duplicado do seu lado — mesmo que o Midaz tenha executado apenas uma vez.
Por exemplo, se seu sistema liquida boletos com base nas respostas de transação, você deve verificar X-Idempotency-Replayed para evitar liquidar o mesmo boleto duas vezes.

Use chaves de idempotência explícitas para fluxos críticos

Embora o Midaz gere chaves automaticamente a partir do corpo da requisição, para fluxos financeiros críticos (liquidações, pagamentos, transferências), sempre forneça uma chave X-Idempotency explícita vinculada ao ID do seu processo de negócio. Isso oferece:
  • Controle total sobre a deduplicação, mesmo se o corpo da requisição mudar ligeiramente entre retentativas.
  • Um rastro de auditoria claro vinculando as transações do Midaz às suas operações internas.
  • Proteção contra casos extremos onde a serialização da requisição pode diferir.

Defina valores de TTL apropriados

Escolha valores de TTL que correspondam à sua janela de retentativa:
  • Para operações síncronas com retentativas rápidas: 60–120 segundos.
  • Para fluxos assíncronos com possíveis atrasos: 300–600 segundos.
  • Para processamento em lote com janelas de retentativa longas: considere TTLs maiores e chaves explícitas.

Estratégia de retentativas


Quando uma requisição falha, como você retenta é importante. Aqui estão os padrões recomendados para lidar com diferentes cenários de falha:

Falhas retentáveis

Estas falhas são seguras para retentar com a mesma chave de idempotência:
CenárioO que fazer
Timeout de rede ou erro de conexãoRetente com a mesma chave e corpo. Se a requisição original foi processada, você receberá a resposta em cache.
Erro 5xx do servidorRetente com backoff exponencial. O servidor pode estar temporariamente sobrecarregado.
409 Conflict com X-Idempotency-Replayed: falseA requisição anterior ainda está sendo processada. Aguarde e retente após uma breve pausa.
Erro de validação ou saldoCorrija o problema na sua requisição, depois retente com a mesma chave de idempotência (o Midaz deleta a chave nessas falhas).

Falhas não retentáveis

Estas falhas requerem uma abordagem diferente:
CenárioO que fazer
400 Bad Request (erro de esquema)Corrija o formato da requisição. Não retente o mesmo payload.
401 Unauthorized / 403 ForbiddenVerifique suas credenciais de autenticação. Retentar não vai ajudar.
404 Not FoundVerifique os IDs de organização, ledger ou conta no path da sua requisição.

Backoff exponencial

Para erros transitórios, use backoff exponencial com jitter para evitar sobrecarregar o servidor:
import time
import random
import requests

def create_transaction_with_retry(idempotency_key, payload, max_retries=5, base_delay=1.0):
    """Retenta com a mesma chave de idempotência em cada tentativa."""
    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)
Uma sequência típica de retentativas com esse padrão seria: 1s, 2s, 4s, 8s, 16s (mais jitter aleatório em cada tentativa).

Prevenindo duplicação de entidades


Para alguns endpoints, você não precisa de chaves de idempotência para evitar duplicação. O Midaz aplica restrições de unicidade em recursos críticos. Se você tentar criar uma entidade que conflite com uma existente, o sistema bloqueia a requisição e retorna um 409 Conflict com um erro descritivo:
RecursoCampo únicoCódigo de erro
LedgerNome (dentro da organização)0002
AssetNome ou código (dentro do ledger)0003
SegmentNome (dentro do ledger)0015
AccountAlias (dentro da organização e ledger)0020
Account TypeValor da chave (dentro da organização e ledger)0108
Isso garante que seus dados permaneçam limpos, sem ambiguidade e fáceis de gerenciar, mesmo quando vários serviços estão operando em paralelo ou quando retentativas ocorrem automaticamente. Diferente das chaves de idempotência, essas restrições são permanentes e não expiram.

Idempotência nos produtos Lerian


Múltiplos produtos da Lerian suportam idempotência, cada um com sua própria convenção de headers. A maioria dos produtos retorna o header de resposta X-Idempotency-Replayed para indicar se a resposta é um replay do cache. O Midaz sempre inclui este header (false para requisições novas, true para replays), enquanto os demais serviços só o adicionam quando a resposta é um replay — se o header estiver ausente, a requisição foi processada como nova. O PIX Direct não retorna este header.
ProdutoHeader de requisiçãoAceita X-TTLX-Idempotency-ReplayedEscopoEndpoints cobertos
MidazX-IdempotencySim (padrão 300s)Sempre (false/true)Por organização e ledgerCriação, anotação e reversão de transações (6 endpoints)
MatcherX-Idempotency-Key (também aceita Idempotency-Key)NãoApenas em replayPor tenant, método e rotaTodos os endpoints POST/PUT/PATCH (~33 endpoints via middleware global)
TEDX-Idempotency-KeyNãoApenas em replayPor chave de idempotência (sem scoping por tenant)Envio, devolução e cancelamento de mensagens (3 endpoints)
PIX IndirectX-IdempotencySimApenas em replayPor contaInício de cashout, processamento de cashout e reembolso (3 endpoints)
PIX DirectIdempotency-KeyNãoNãoPor chaveCriação de pagamento e início de devolução (2 endpoints)
ReporterX-IdempotencyNãoApenas em replayPor chaveCriação de relatórios e templates (2 endpoints)
O Midaz sempre inclui o header X-Idempotency-Replayed na resposta (false para requisições novas, true para replays). Os demais serviços (Matcher, TED, PIX Indirect e Reporter) só adicionam este header quando a resposta é um replay — se o header estiver ausente, a requisição foi processada como nova. O PIX Direct não retorna este header; seu middleware de idempotência faz replay da resposta completa de forma transparente, sem um indicador de replay.
Fees Engine, Tracer, Auth e CRM atualmente não suportam headers de idempotência. As validações do Tracer são stateless e naturalmente seguras para retentativa. As operações de tokens do Auth são inerentemente idempotentes. CRM e entidades de onboarding dependem de restrições de unicidade em vez disso.

FAQ


O Midaz gera uma automaticamente calculando um hash SHA-256 do corpo da requisição. Isso significa que corpos de requisição idênticos enviados para a mesma organização e ledger são automaticamente deduplicados. Você só precisa fornecer uma chave personalizada se quiser controlar a deduplicação independentemente do corpo da requisição.
Sim. As chaves de idempotência são escopadas por organização e ledger, então o mesmo valor de chave usado em diferentes organizações ou ledgers não entrará em conflito. Porém, dentro da mesma organização e ledger, cada chave deve ser única por operação.
No Midaz, as chaves de idempotência são escopadas por organização e ledger, não por endpoint. Se você reutilizar a mesma chave em um endpoint diferente dentro da mesma organização e ledger, receberá a resposta em cache do endpoint original. Sempre use chaves únicas para cada operação distinta.
Apenas o TTL da primeira requisição é utilizado. Alterá-lo depois não tem efeito.
Sim. O Midaz repete a resposta completa, incluindo código de status (201 Created), headers e corpo, para requisições concluídas.
A janela padrão é de 300 segundos (5 minutos).
Se a transação falhar por erros de validação ou saldo insuficiente, o Midaz deleta a chave de idempotência do cache. Isso permite que você corrija o problema e retente com a mesma chave.