# Chamadas de voz Ligações usam uma instância de tipo `calls`, com pareamento próprio e áudio nos dois sentidos pelo navegador. O módulo precisa estar habilitado no servidor. ## Capacidade anunciada Consulte [GET /v1/capabilities](https://wpp.atendro.cloud/docs/api/get-capabilities.md) com `admintoken`. Exigir `capabilities.calls=true` e `instance_kinds` contendo `calls`. Este recorte ilustra um servidor habilitado: ```json { "capabilities": {"calls": true}, "instance_kinds": ["whatsapp", "calls"], "calls_max_concurrent": 1 } ``` Com `ATENDROZAP_CALLS_ENABLED=false`, criar ou operar a instância de ligação é recusado. O limite padrão é uma chamada por instância. Conectar uma instância de mensagens não habilita voz nela. ## Primeiro teste pelo painel 1. Abra o servidor no [console](https://wpp.atendro.cloud) e clique em **Nova instância**. 2. Selecione **Tipo → Ligação**, informe um nome e crie. O painel guarda o token no backend. 3. Solicite a conexão e escaneie o QR pelo WhatsApp do número autorizado. Aguarde **connected**. Pode ser outro dispositivo vinculado do mesmo número usado para mensagens ou um número dedicado. 4. Nas **Conversas** da instância de mensagens, abra a conversa autorizada e clique em **Ligar**. O painel escolhe uma instância de ligação conectada do mesmo servidor cujo token conhece. Também é possível usar **Discar** na página da instância de ligação. 5. Permita o microfone, atenda no telefone de destino e confira áudio nos dois sentidos. **Mudo** controla o microfone; **Desligar** encerra a chamada. Mantenha a página aberta durante a conversa. Se o tipo **Ligação** não aparecer, confira a capacidade do servidor. Se o painel não conhecer o token de uma instância criada fora dele, reemita-o pela interface antes do uso. Erros de linha ocupada ou sessão desconectada são mostrados no widget. ## Ruído e eco O painel solicita cancelamento de eco, supressão de ruído e ajuste de ganho ao navegador. Quando o dispositivo oferece o modo de cancelamento de todo o áudio reproduzido, ele é preferido para incluir a voz que sai pelo painel. O widget avisa quando não consegue confirmar o cancelamento de eco. **Reduzir ruído do microfone** vem marcado: acrescenta um filtro de graves e atenua suavemente o fundo entre as falas. Desmarque durante uma chamada para comparar, especialmente se sua voz for muito baixa. Essa opção controla o filtro adicional; o cancelamento de eco do navegador continua solicitado. O tratamento ocorre no computador do atendente antes do envio e não altera o som recebido. Quando a gravação automática está habilitada no servidor, ela captura a voz já tratada do atendente e a voz recebida do contato. O filtro não elimina todas as vozes, teclas ou sons fortes enquanto você fala. Use fone se persistir eco; no teste com dois aparelhos próximos, afaste o telefone do microfone do computador e evite volume alto no viva-voz. A qualidade depende também do navegador, microfone e ambiente. ## Rotas e estados | Operação | Resultado | |---|---| | [POST /call/make](https://wpp.atendro.cloud/docs/api/make-call.md) | Corpo `{number}`; `201` com `callId`; aceita `Idempotency-Key` | | [POST /call/answer](https://wpp.atendro.cloud/docs/api/answer-call.md) | Corpo `{callId}`; atende uma chamada recebida | | [POST /call/reject](https://wpp.atendro.cloud/docs/api/reject-call.md) | Corpo `{callId}`; recusa uma chamada recebida | | [POST /call/hangup](https://wpp.atendro.cloud/docs/api/hangup-call.md) | Corpo `{callId}`; encerra a chamada | | [GET /call/active](https://wpp.atendro.cloud/docs/api/list-active-calls.md) | Lista as chamadas vivas da instância | | [GET /call/{id}](https://wpp.atendro.cloud/docs/api/get-call.md) | Estado da chamada viva ou do histórico persistente | | [GET /call/history](https://wpp.atendro.cloud/docs/api/list-call-history.md) | Histórico paginado, com filtros e situação da gravação | | [GET /call/{id}/recording](https://wpp.atendro.cloud/docs/api/download-call-recording.md) | Reprodução/download autenticado do WAV, com suporte a Range | | [GET /call/{id}/audio](https://wpp.atendro.cloud/docs/api/stream-call-audio.md) | Upgrade WebSocket; PCM s16le mono a 16 kHz | Todas usam o token da instância `calls`. Estados: `ringing`, `connecting`, `active`, `ended`; o encerramento inclui `endReason` e `endedBy`. Uma instância `whatsapp` mantém `501 calls_not_supported` em `/call/make`; outras rotas de ligação recusam o tipo incorreto com `409 wrong_instance_kind`. O áudio passa pelo console, que autentica a sessão do navegador e adiciona o token no pedido à API. Apenas a ponte de áudio aceita `?token=` como alternativa ao header. Prefira o proxy para manter a credencial no backend e não registrar tokens em URLs. Fechar o socket encerra a chamada. ## Registrar o atendimento no sistema parceiro Inscreva `call` no webhook global ou próprio para receber `data` com `callId`, direção, estado e motivo de encerramento. A entrega segue a política de assinatura, retry e deduplicação dos demais eventos. O sinal de atendimento é **`EventType: "call"` e `data.event: "answered"`**. Nesse momento `data.answered` é `true`, `data.answeredAt` traz o horário do aceite e `data.status` é `connecting`. O estado `active` chega depois, quando o motor recebe áudio; não espere por ele para registrar que atendeu. Isso vale para o aceite remoto de uma chamada realizada e para o atendimento local de uma chamada recebida. `ringing` e `preaccept` não são atendimento. ```json { "EventType": "call", "event": "call", "eventId": "ID_DO_EVENTO", "instanceId": "ID_DA_INSTANCIA", "seq": 2, "data": { "callId": "ID_DA_CHAMADA", "event": "answered", "direction": "outbound", "status": "connecting", "answered": true, "startedAt": "2026-09-18T15:00:00Z", "answeredAt": "2026-09-18T15:00:05Z" } } ``` O exemplo é um recorte: o envelope completo inclui as identidades previstas no contrato. No consumidor, valide a assinatura sobre o corpo original, identifique a instância por `instanceId` e faça upsert por `(instanceId, data.callId)`. Deduplicate por `eventId`; retries preservam esse identificador. Use `seq` do envelope para ordenar, pois `data.seq` pertence à sessão de ligações. Responda 2xx após guardar o evento. `data.event: "active"` acrescenta `mediaStartedAt`, mantendo `answeredAt`. `data.event: "ended"` acrescenta `endedAt`, `endReason`, `endedBy` e `durationSeconds`. Os eventos posteriores também preservam `answered=true` e `answeredAt`, permitindo reconciliar o atendimento se o consumidor perdeu uma notificação. Chamadas não atendidas terminam com `answered=false`. `data.event: "recording_ready"` informa `callId` e `recording` com `status`, `bytes` e `durationMs` depois de o arquivo ficar pronto. `recording_failed` informa falha, sem inventar um áudio disponível. Esses dois eventos atualizam a gravação, não o estado da chamada; não dependem de um campo `status` da chamada e podem chegar antes do evento de encerramento. ## Histórico e gravação automática No painel, abra a instância de ligação e a aba **Histórico de chamadas**. É possível filtrar realizadas/recebidas e atendidas/sem atendimento, consultar duração, ouvir e baixar. O histórico permanece após reiniciar a API e após a expiração do áudio; não depende da retenção de `/v1/events`. Na API, `GET /call/history?limit=25&answered=true` lista a primeira página. Envie o `nextCursor` recebido como `before` para buscar chamadas mais antigas. Filtros opcionais: `direction`, `status`, `from` (inclusivo) e `to` (exclusivo), com datas RFC3339. Máximo de 100 itens por página. Na VPS 1 a configuração solicitada é gravar **todas as chamadas atendidas** e reter o áudio por **30 dias**. `capabilities.call_history` e `capabilities.call_recording` anunciam os recursos; a retenção está em `calls_recording_retention_days`. A captura começa no aceite, sem gravar toques, e acompanha substituições da ponte de áudio. O WAV tem PCM 16-bit, 16 kHz, dois canais: atendente à esquerda e contato à direita. O som processado ocupa aproximadamente 3,84 MB por minuto de chamada. Cada item tem `recording.status`: `not_recorded`, `recording` (captura ou finalização), `ready`, `failed` ou `expired`. Quando pronto, `downloadPath` aponta para `GET /call/{id}/recording`. **Use o header `token` no backend**: essa rota não aceita credencial na query. Faça proxy autenticado para o player do Atendro, repassando `Range` para permitir avançar no áudio. O console já faz isso sem expor o token ao navegador. Depois do prazo, o download responde `410 recording_expired`; a limpeza dos arquivos roda de hora em hora, preservando o histórico. Um worker reiniciado durante uma chamada marca o registro como encerrado por `worker_restarted` e a gravação incompleta como falha. Disco indisponível ou fila de gravação esgotada também gera falha explícita, sem bloquear a chamada. Os eventos antigos ainda existentes são importados para o histórico pela migração. Não há áudio recuperável de chamadas anteriores à ativação. ## Limites de validação A bancada validou uma chamada curta de saída com áudio nos dois sentidos, e o responsável confirmou a chamada real pelo painel da VPS em 18/09/2026. Após o ajuste de áudio, repetiu a chamada e confirmou melhora tanto do ruído quanto do eco. Essa confirmação é qualitativa, no ambiente testado. Latência boca-ouvido medida, chamada longa, recebimento e o defeito upstream #25 (recusa por aparelho Web/Desktop do destino) continuam pendentes de homologação. Veja [validação e limites](https://wpp.atendro.cloud/docs/guias/validacao.md).