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

# Reconexão

> O zapo não reconecta automaticamente por design — siga este padrão para detectar sessões caídas, recriar o client e retomar sem conexões duplicadas.

<Warning>
  O `WaClient` **não** reconecta automaticamente. Esta é uma escolha de design deliberada: a política de reconexão (backoff, máximo de tentativas, alertas) pertence à sua aplicação. Você escuta o `connection: close` e decide o que fazer.
</Warning>

<h2 id="internal-recovery-layers">
  Camadas internas de recuperação
</h2>

A regra "sem auto-reconnect" vale para o **ciclo de vida da sessão**: assim que um `connection: close` é emitido, o client não reabre sozinho. Mas dois retries de baixo nível existem dentro da stack – você os verá em log e não precisa tratá-los.

* **Transport WebSocket.** Se o socket cair *antes* de um handshake noise bem-sucedido, o `WaComms` faz retry interno a cada `reconnectIntervalMs` (default `2000`) até `maxReconnectAttempts`. Quando o handshake completa, o contador zera e qualquer queda posterior vira um evento `connection` pra sua app tratar.
* **Transição de pairing.** Logo após um pair via QR/código, o client reinicia o socket como sessão já registrada. Nenhum `connection: close` é emitido – é invisível de fora.

A recuperação `client_too_old` (HTTP 405) coberta abaixo é uma terceira camada, opt-in.

<h2 id="connection-lifecycle">
  Ciclo de vida da conexão
</h2>

```mermaid theme={null}
stateDiagram-v2
  [*] --> Connecting: connect()
  Connecting --> Open: opened
  Connecting --> Closed: failed
  Open --> Closed: connection close
  Closed --> Connecting: reconnect (isLogout = false)
  Open --> [*]: disconnect()
  Closed --> [*]: isLogout = true (re-pair)
```

<h2 id="the-connection-event">
  O evento connection
</h2>

`connection` é uma union discriminada por `status`:

```ts theme={null}
client.on('connection', (event) => {
  if (event.status === 'open') {
    console.log('connected', { isNewLogin: event.isNewLogin })
    return
  }

  // status === 'close'
  console.log('disconnected', {
    reason: event.reason,
    code: event.code,
    isLogout: event.isLogout
  })
})
```

Em `close`:

* **`isLogout: true`** — o dispositivo foi desvinculado (logout no servidor). **Não** reconecte; as credenciais se foram e você precisa parear novamente.
* **`isLogout: false`** — uma queda transitória. É seguro reconectar com as credenciais armazenadas.

<h2 id="a-reconnection-loop-with-backoff">
  Um loop de reconexão com backoff
</h2>

```ts theme={null}
const MAX_ATTEMPTS = 10

async function connectWithRetry(client: WaClient) {
  let attempt = 0

  client.on('connection', (event) => {
    if (event.status === 'open') {
      attempt = 0 // reseta o backoff em uma conexão saudável
      return
    }
    if (event.isLogout) {
      console.error('logged out — re-pairing required')
      return
    }
    void reconnect()
  })

  async function reconnect() {
    if (attempt >= MAX_ATTEMPTS) {
      console.error('giving up after', attempt, 'attempts')
      return
    }
    const delayMs = Math.min(30_000, 1_000 * 2 ** attempt)
    attempt += 1
    console.log(`reconnecting in ${delayMs}ms (attempt ${attempt})`)
    await new Promise((r) => setTimeout(r, delayMs))
    try {
      await client.connect()
    } catch (err) {
      console.error('reconnect failed', err)
      void reconnect()
    }
  }

  await client.connect()
}
```

<h2 id="recovering-from-client-too-old">
  Recuperando de `client_too_old` (HTTP 405)
</h2>

Se o servidor começar a rejeitar o handshake noise com `failure_client_too_old`, a versão embarcada do WA Web está desatualizada. Duas opções:

* Ative [`recoverFromClientTooOld: true`](/pt-br/concepts/configuration#whatsapp-web-version) no `WaClient` — a cada 405 o client busca a versão atual em `web.whatsapp.com`, troca em memória e reconecta.
* Passe um [resolver `version`](/pt-br/concepts/configuration#whatsapp-web-version) que retorne uma string fresca por conexão.

Ambos são paliativos — atualize o zapo quando uma release trouxer um default mais novo.

<h2 id="after-reconnecting">
  Depois de reconectar
</h2>

Parte do estado é **escopado à conexão** e precisa ser reestabelecido após uma reconexão bem-sucedida:

* **Assinaturas de presença** — faça `subscribe()` novamente em qualquer contato que você estava observando ([Presença](/pt-br/guides/presence-status#subscribing-to-a-contact)).
* **Atualizações ao vivo de newsletter** — faça `subscribeLiveUpdates()` novamente se você depende delas.

O estado persistido (credenciais, sessões do Signal, [app-state](/pt-br/reference/glossary#app-state)) é restaurado da [store](/pt-br/concepts/stores) automaticamente — você **não** pareia novamente em uma reconexão normal.

<h2 id="graceful-shutdown">
  Encerramento gracioso
</h2>

Chame `disconnect()` para um encerramento limpo que mantém as credenciais, para que você possa retomar mais tarde:

```ts theme={null}
process.on('SIGINT', async () => {
  await client.disconnect()
  process.exit(0)
})
```

Isso descarrega os dados pendentes de write-behind e fecha o socket sem desvincular o dispositivo.
