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.
call.offer.
Passo 1 — Inicie a chamada
ChamePOST /calls/stream com a sessão e o número de destino (com DDI, apenas
dígitos).
Identificador da chamada. Use-o para consultar a gravação depois.
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 de acesso àquela chamada (a sua API Key). Já está dentro da
wsUrl.Passo 2 — Conecte ao WebSocket
Abra awsUrl e configure binaryType para receber áudio como ArrayBuffer.
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.
Crie o worklet voip-worklet.js (implementação de referência, adaptada da extensão
oficial da D-API):
Passo 4 — Acompanhe o ciclo de vida
Os frames de texto do WebSocket são eventos JSON no formato{ "type": ... }.
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
Mutar / desmutar
Mutar / desmutar
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 })).Desligar
Desligar
Fechar o WebSocket já desliga a chamada — o servidor interpreta o
fechamento como um
hangup.Encerrar e liberar recursos
Encerrar e liberar recursos
Ao terminar, pare o microfone e feche o
AudioContext:Formato de áudio
Todo o áudio, nos dois sentidos, segue exatamente este formato:Inteiros de 16 bits com sinal, little-endian. Frames binários (não base64).
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: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.
O stream de voz está indisponível no momento. Tente novamente mais tarde.
Ao atingir o limite, a chamada encerra com
ended e reason: "terminate".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.
