Idempotencia

Chaves de idempotencia garantem que operacoes criticas sejam executadas apenas uma vez, mesmo em caso de retries ou falhas de rede.

O que e idempotencia?

Uma operacao e idempotente quando executa-la multiplas vezes produz o mesmo resultado que executa-la uma vez. Isso e crucial para operacoes financeiras onde duplicacoes podem causar prejuizos.

Importante

Sempre use chaves de idempotencia em operacoes que criam ou modificam recursos, especialmente pagamentos e transferencias.

Como usar

Adicione o header Idempotency-Key com um valor unico para cada operacao:

POST /v1/payments HTTP/1.1
Host: api.axon.com
Authorization: Bearer axon_sk_...
Content-Type: application/json
Idempotency-Key: pay_order123_attempt1

{
  "token_id": "tok_abc123",
  "amount": 150.00
}

Gerando chaves de idempotencia

idempotency.jsjavascript
// Opcao 1: UUID v4 (simples)
function generateIdempotencyKey() {
  return crypto.randomUUID();
}

// Opcao 2: Baseado no contexto (recomendado)
function generateContextualKey(operation, resourceId, attempt = 1) {
  // Permite retry com mesma chave
  return `${operation}_${resourceId}_${attempt}`;
}

// Opcao 3: Hash de parametros
function generateDeterministicKey(params) {
  const sorted = JSON.stringify(params, Object.keys(params).sort());
  return crypto.createHash('sha256').update(sorted).digest('hex');
}

// Exemplos de uso
const key1 = generateIdempotencyKey();
// "f47ac10b-58cc-4372-a567-0e02b2c3d479"

const key2 = generateContextualKey('payment', 'order_123', 1);
// "payment_order_123_1"

const key3 = generateDeterministicKey({
  token_id: 'tok_abc',
  amount: 150.00,
  order_id: 'order_123',
});
// "a1b2c3d4e5f6..."

Comportamento da API

Primeira requisicao

A operacao e executada normalmente e a resposta e armazenada junto com a chave.

Requisicao duplicada (mesma chave, mesmos parametros)

Retorna a resposta armazenada sem executar novamente. Status 200.

Conflito (mesma chave, parametros diferentes)

Retorna erro 409 Conflict. Gere uma nova chave para a operacao diferente.

Tratando respostas

handle-idempotency.jsjavascript
async function createPaymentSafely(tokenId, amount, orderId) {
  const idempotencyKey = `payment_${orderId}`;

  try {
    const response = await fetch('https://api.axon.com/v1/payments', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${apiKey}`,
        'Content-Type': 'application/json',
        'Idempotency-Key': idempotencyKey,
      },
      body: JSON.stringify({
        token_id: tokenId,
        amount,
        metadata: { order_id: orderId },
      }),
    });

    const data = await response.json();

    if (response.ok) {
      // Checar se foi idempotente
      if (response.headers.get('Idempotent-Replayed') === 'true') {
        console.log('Resposta recuperada de requisicao anterior');
      }
      return data;
    }

    if (response.status === 409) {
      // Conflito - parametros diferentes para mesma chave
      throw new Error(`Idempotency conflict: ${data.error.message}`);
    }

    throw new Error(data.error.message);

  } catch (error) {
    // Em caso de timeout ou erro de rede, pode tentar novamente
    // com a MESMA chave de idempotencia
    if (error.name === 'TypeError' || error.code === 'ETIMEDOUT') {
      console.log('Erro de rede, retentando com mesma chave...');
      return createPaymentSafely(tokenId, amount, orderId);
    }
    throw error;
  }
}

Validade das chaves

Chaves de idempotencia sao armazenadas por 24 horas. Apos esse periodo, a mesma chave pode ser reutilizada para uma nova operacao.

ServicoValidade
Vault24 horas
Payments24 horas
Chain7 dias

Boas praticas

  • Use chaves baseadas no contexto do negocio (order_id, transaction_id)
  • Armazene a chave usada junto com o resultado da operacao
  • Use a mesma chave ao retentar apos erros de rede
  • Gere nova chave apenas para operacoes genuinamente diferentes
  • Limite o tamanho da chave a 255 caracteres