> ## Documentation Index
> Fetch the complete documentation index at: https://docs.connectadesk.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Idempotência

> Use o header Idempotency-Key para repetir POST e PUT na API do Connecta DESK sem executar a mesma operação duas vezes.

Quando uma requisição dá timeout, você não sabe se ela chegou à API. Se repetir sem cuidado, o
recurso pode ser criado duas vezes. Em `POST /messages`, o cliente final recebe a mesma mensagem
duas vezes.

Com o header `Idempotency-Key`, a primeira chamada é executada e as repetições recebem a mesma
resposta da primeira vez.

<ParamField header="Idempotency-Key" type="string">
  Chave única da operação, com até 200 caracteres. Aceita em `POST` e `PUT`. É opcional: sem ela,
  cada chamada é executada normalmente.
</ParamField>

## Como usar

Gere um identificador único para cada operação de negócio e use esse mesmo identificador em todas
as tentativas daquela operação. Com a mesma chave, a API entende que as tentativas são uma única
operação.

<CodeGroup>
  ```bash cURL theme={null}
  curl --request POST \
    --url "$CONNECTA_URL/messages" \
    --header "Authorization: Bearer $CONNECTA_TOKEN" \
    --header "Content-Type: application/json" \
    --header "Idempotency-Key: pedido-88213-confirmacao" \
    --data '{
      "channelId": 4,
      "number": "5511999999999",
      "body": "Seu pedido #88213 foi confirmado."
    }'
  ```

  ```javascript Node.js theme={null}
  async function enviarComRetry(payload, chave, tentativas = 3) {
    for (let i = 1; i <= tentativas; i++) {
      try {
        const res = await fetch(`${process.env.CONNECTA_URL}/messages`, {
          method: 'POST',
          headers: {
            Authorization: `Bearer ${process.env.CONNECTA_TOKEN}`,
            'Content-Type': 'application/json',
            'Idempotency-Key': chave
          },
          body: JSON.stringify(payload)
        });

        if (res.ok) return res.json();
        if (res.status < 500) throw new Error(`Erro definitivo: ${res.status}`);
      } catch (err) {
        if (i === tentativas) throw err;
      }

      await new Promise((r) => setTimeout(r, 2 ** i * 500));
    }
  }

  // A chave vem do domínio, não de um random por tentativa.
  await enviarComRetry(payload, `pedido-${pedido.id}-confirmacao`);
  ```

  ```python Python theme={null}
  import os, time, requests

  def enviar_com_retry(payload, chave, tentativas=3):
      for i in range(1, tentativas + 1):
          try:
              res = requests.post(
                  f"{os.environ['CONNECTA_URL']}/messages",
                  json=payload,
                  headers={
                      "Authorization": f"Bearer {os.environ['CONNECTA_TOKEN']}",
                      "Idempotency-Key": chave,
                  },
                  timeout=10,
              )
              if res.ok:
                  return res.json()
              if res.status_code < 500:
                  res.raise_for_status()
          except requests.RequestException:
              if i == tentativas:
                  raise

          time.sleep(2**i * 0.5)

  enviar_com_retry(payload, f"pedido-{pedido_id}-confirmacao")
  ```
</CodeGroup>

<Tip>
  As melhores chaves vêm de algo que já é único no seu sistema, como `pedido-88213-confirmacao`,
  `fatura-2026-09-lembrete` ou `crm-card-771-nota`. Um UUID aleatório também serve, desde que você
  o **salve** antes da primeira tentativa. Se um UUID novo for gerado a cada tentativa, a chave
  não protege contra duplicidade.
</Tip>

## O que acontece em cada caso

<AccordionGroup>
  <Accordion title="Repetição com o mesmo corpo" icon="repeat">
    A API devolve a resposta da primeira execução, com o mesmo status, e acrescenta este header:

    ```
    Idempotent-Replay: true
    ```

    Nada é executado de novo. É o que acontece no retry depois de um timeout.
  </Accordion>

  <Accordion title="Mesma chave, corpo diferente" icon="triangle-alert">
    ```json theme={null}
    {
      "error": {
        "code": "ERR_API_IDEMPOTENCY_KEY_REUSED",
        "message": "Idempotency-Key já usada com um corpo diferente."
      }
    }
    ```

    A API recusa a requisição com `409`. Usar a mesma chave em outra operação quase sempre indica
    um erro na forma como a sua integração gera as chaves.
  </Accordion>

  <Accordion title="A primeira ainda está em andamento" icon="hourglass">
    ```json theme={null}
    {
      "error": {
        "code": "ERR_API_IDEMPOTENCY_IN_PROGRESS",
        "message": "Uma requisição com esta Idempotency-Key ainda está em processamento."
      }
    }
    ```

    A resposta também é `409`. Acontece quando duas tentativas rodam ao mesmo tempo. Aguarde e
    consulte o resultado em vez de enviar uma terceira tentativa.
  </Accordion>

  <Accordion title="Chave longa demais" icon="ruler">
    Com mais de 200 caracteres, a requisição é recusada com `400 ERR_API_IDEMPOTENCY_KEY_INVALID`
    antes de qualquer execução.
  </Accordion>
</AccordionGroup>

## Regras da chave

**Erros não ficam guardados.** Só as respostas de sucesso são registradas. Se a chamada falhou
por dado inválido, corrija o corpo e repita com a mesma chave, porque a operação ainda não
aconteceu.

**A chave vale por token, método e rota.** A mesma chave usada em `POST /messages` e em
`POST /contacts` conta como duas operações diferentes, sem conflito. Tokens diferentes também não
compartilham chave, mesmo sendo da mesma empresa.

**Resposta sem corpo também é repetida.** Operações que respondem `204`, como aplicar uma tag no
atendimento, guardam o resultado igual às demais, e a repetição devolve `204` com
`Idempotent-Replay: true`.

**Envio com arquivo não usa a chave.** Em `multipart/form-data`, o arquivo ainda não foi lido quando
a verificação acontece, então não há corpo para comparar e a chave é ignorada. Vale para envio de
mídia, campanha com arquivo e anexo de agendamento: nesses casos, trate a duplicidade do seu lado.

**A chave tem prazo.** As chaves ficam guardadas por 24 horas (esse prazo pode ser configurado na
instalação). Depois disso, a mesma chave faz a operação ser executada de novo. A proteção serve
para os retries feitos logo depois de uma falha. Um reenvio feito semanas depois é tratado como
uma operação nova.

<Warning>
  Se houver uma instabilidade interna, a API processa a requisição normalmente, sem a proteção de
  idempotência, em vez de recusá-la. Por isso, operações críticas também devem conseguir
  identificar duplicidade do seu lado.
</Warning>

## Onde usar

<Columns cols={2}>
  <Card title="POST /messages" icon="send" href="/guides/enviar-mensagens">
    É onde a duplicidade aparece para o cliente final. Use sempre.
  </Card>

  <Card title="POST /campaigns" icon="megaphone">
    Uma campanha criada duas vezes dispara para toda a base duas vezes.
  </Card>

  <Card title="POST /contacts" icon="user-plus">
    Evita cadastro duplicado quando o retry vem de uma rotina automática. Veja também
    `POST /contacts/upsert`.
  </Card>

  <Card title="POST /crm/cards" icon="kanban">
    Cards repetidos poluem o painel do CRM e distorcem os indicadores.
  </Card>
</Columns>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.