Skip to main content
As Ligações por Stream deixam o seu aplicativo transmitir o áudio de uma chamada de voz do WhatsApp em tempo real: você inicia a ligação por uma chamada HTTP, abre um WebSocket e troca áudio nos dois sentidos — microfone do seu usuário para o outro lado, e a voz do outro lado para o alto-falante.
Você precisa de uma conexão WhatsApp já conectada (provider whatsmeow) e de uma API Key. Gere a sua chave no painel.

Como funciona

O fluxo é sempre de saída (você liga para um número) e roda no navegador, onde estão o microfone e o alto-falante:
1

Inicie a chamada

POST /calls/stream retorna um callId e uma wsUrl pronta para abrir.
2

Abra o WebSocket

A wsUrl já carrega a autenticação. Frames de texto são eventos do ciclo de vida; frames binários são áudio.
3

Troque áudio

Envie o microfone como PCM binário e reproduza o áudio binário recebido.
4

Finalize

Feche o WebSocket para desligar. A gravação fica disponível ao final.
Por baixo, o áudio trafega entre o navegador e o bridge do WhatsApp; a D-API é um cano bidirecional. Chamadas recebidas não entram por aqui — elas chegam pelo webhook call.offer.

Passo 1 — Inicie a chamada

Chame POST /calls/stream com a sessão e o número de destino (com DDI, apenas dígitos).
A resposta traz o identificador da chamada e a URL do stream:
callId
string
Identificador da chamada. Use-o para consultar a gravação depois.
wsUrl
string
URL opaca e de uso único do WebSocket, com callId e token já embutidos. Abra-a exatamente como veio — não monte a URL você mesmo.
token
string
Token de acesso àquela chamada (a sua API Key). Já está dentro da wsUrl.
A wsUrl embute a sua API Key no parâmetro token. Inicie a chamada pelo seu backend e entregue ao navegador apenas a wsUrl; trate-a como um segredo de curta duração (não registre em logs). Prefira uma API Key com escopo de sessão para reduzir o impacto caso ela vaze.
Um exemplo de início pelo backend, que mantém a chave fora do navegador:

Passo 2 — Conecte ao WebSocket

Abra a wsUrl e configure binaryType para receber áudio como ArrayBuffer.
Não há handshake pós-conexão: a autenticação está na URL. Se o servidor recusar, ele envia um evento error e fecha a conexão.

Passo 3 — Capture e reproduza o áudio

O áudio na rede é PCM cru (s16le, 16 kHz, mono), em frames de 20 ms = 320 amostras = 640 bytes. A forma mais simples de acertar o formato é rodar o AudioContext a 16 kHz — o navegador reamostra o microfone para você — e converter Float32 ⇄ Int16 dentro de um AudioWorklet.
Rode o AudioContext a sampleRate: 16000. Assim você evita reamostrar o microfone na mão, e cada frame do worklet já sai no formato exato do stream.
Crie o worklet voip-worklet.js (implementação de referência, adaptada da extensão oficial da D-API):
Ligue o microfone, o worklet e o WebSocket:
Não envie áudio do microfone antes do evento accepted. Antes disso o outro lado ainda não está pronto. O flag canSendUplink acima cuida disso.

Passo 4 — Acompanhe o ciclo de vida

Os frames de texto do WebSocket são eventos JSON no formato { "type": ... }.
O evento ended traz um reason: hangup, rejected, timeout, accepted_elsewhere, terminate (duração máxima atingida), ws_closed, entre outros. Se o WebSocket fechar sem um ended, trate como encerramento.

Passo 5 — Controle a chamada

Basta parar de enviar o microfone. O jeito mais simples é desabilitar a faixa de áudio:
Como alternativa, o servidor também aceita um controle por texto: ws.send(JSON.stringify({ type: "mute", muted: true })).
Fechar o WebSocket já desliga a chamada — o servidor interpreta o fechamento como um hangup.
Ao terminar, pare o microfone e feche o AudioContext:

Formato de áudio

Todo o áudio, nos dois sentidos, segue exatamente este formato:
Codec
PCM s16le
Inteiros de 16 bits com sinal, little-endian. Frames binários (não base64).
Taxa de amostragem
16000 Hz
Canais
1 (mono)
Tamanho do frame
320 amostras = 640 bytes = 20 ms
Envie em cadência de tempo real (um frame a cada ~20 ms), sem acumular e despejar em lote.

Gravação

Toda chamada por stream é gravada. Perto do fim, o servidor envia:
Os arquivos são WAV mono de 16 kHz (full = mixagem, sender/recipient = lados separados). A mesma gravação também fica disponível depois em GET /api/v1/calls/:callId.

Erros e limites

429 Too Many Requests
Limite de novas chamadas por usuário (padrão: 10 a cada 60 s). Evita bloqueios do WhatsApp por excesso de tentativas. Aguarde antes de tentar de novo.
503 Service Unavailable
O stream de voz está indisponível no momento. Tente novamente mais tarde.
Duração máxima
3600 s
Ao atingir o limite, a chamada encerra com ended e reason: "terminate".
Os eventos error trazem um code: unavailable, not_found, unauthorized ou forbidden.

Exemplo completo

Um cliente mínimo que inicia (via seu backend), conecta, transmite áudio e oferece mutar/desligar:

Próximos passos

Webhooks de chamadas

Receba chamadas de entrada (call.offer) e o ciclo de vida por webhook.

Referência da API

Autenticação, sessões e todos os endpoints da D-API.