Pular para o conteúdo principal
Um número conectado pode fazer e receber chamadas de voz e vídeo do WhatsApp. Você adiciona chamadas ao seu produto com os SDKs da Polymorfa:
  • No navegador, @polymorfa/browser conecta microfones, câmeras e alto-falantes a uma chamada, e @polymorfa/react e @polymorfa/elements renderizam a interface da chamada.
  • No código do servidor, @polymorfa/sdk/calls permite que a sua aplicação fale e ouça em uma chamada, por exemplo para executar um agente de voz.
  • No seu servidor, @polymorfa/sdk faz, atende e encerra chamadas e gerencia as configurações de chamadas.
Navegadores e código do servidor podem entrar na mesma chamada. Cada participante ouve os demais e recebe o vídeo deles. Os SDKs cuidam das conexões de mídia, das reconexões e da renovação de tokens; a sua aplicação lida apenas com chamadas e participantes. Os pacotes de chamadas são distribuídos no repositório de SDKs da Polymorfa. Consulte SDK TypeScript para a instalação.

Como as chamadas funcionam

  • A chamada. Ela toca, é atendida ou recusada e termina. Encerrá-la desconecta todos.
  • Participantes. Um participante é quem age na chamada. A Polymorfa o deriva da credencial:
    • Um token de cliente age como client:<ephemeralId>, usando o ephemeralId com que foi emitido. Tokens de cliente não podem indicar outro participante.
    • Uma chave de equipe ou um token de projeto age como server:<participant>. Informe o nome opcional participant (de 1 a 128 caracteres entre A-Z, a-z, 0-9, ., _, :, @ e -). O padrão é server:default.
  • Conexões. Cada aba do navegador ou cliente de servidor que transporta o áudio e o vídeo de um participante é uma conexão. Um participante pode ter várias conexões. Sair fecha uma conexão e nunca encerra a chamada.
Toda chamada recebida toca até que um participante a atenda ou recuse, ou até que a janela de toque termine. Nada atende uma chamada automaticamente. A sua aplicação decide quem é convidado, quem atende e se outros participantes podem entrar.

Autentique clientes de navegador

Navegadores e aplicativos móveis usam um token de cliente. Emita o token no seu servidor com POST /platform/client-tokens e envie-o ao cliente. Mantenha as chaves de equipe e os tokens de projeto no seu servidor. Consulte Tokens de cliente. Ative as ações de chamada de que o cliente precisa nas regras de cliente da sessão: O SDK de navegador precisa das três para fazer e atender chamadas. Um token de cliente age apenas em chamadas da sessão à qual está vinculado, e essa sessão ainda precisa pertencer ao projeto do token. O ephemeralId dele precisa usar os caracteres de participante listados acima; caso contrário, as requisições de chamada retornam 403. Tokens de cliente expiram. Passe ao SDK uma função que busca um token novo no seu servidor; o SDK renova o token nas conexões abertas antes que ele expire. Quando um token é revogado ou deixa de autorizar a sessão, o SDK informa um erro unauthorized e pede um novo token à sua função. Ele faz o mesmo quando a Polymorfa não consegue confirmar o token por 3 minutos porque as verificações estão com limite de taxa ou temporariamente indisponíveis.

Chamadas no navegador

createClientTokenProvider() solicita tokens a /api/polymorfa/token na sua própria origem. Implemente essa rota no seu servidor e retorne um token de cliente para o usuário conectado. CallSurface mostra as chamadas que estão tocando, o palco da chamada, o vídeo dos participantes, a lista de participantes e os controles de microfone, câmera, dispositivos, saída e encerramento da chamada. IncomingCallCard, CallStage, ParticipantVideoGrid, ParticipantList, CallControls e DialPad estão disponíveis individualmente. Em HTML puro, atribua o mesmo controlador ao elemento <pmfa-call> de @polymorfa/elements. Para construir (build) a sua própria interface, leia calls.controller.getSnapshot() e chame place, answer, join, reject, leave, end, setMuted e switchDevice no controlador. Várias chamadas podem tocar ao mesmo tempo; o controlador as lista em snapshot.invitations e nunca recusa uma chamada por você. O vídeo de cada participante remoto é um stream separado em controller.remoteVideos, identificado pelo participante. Chame await calls.dispose() quando a sua aplicação liberar a interface de chamadas.

Chamadas a partir do código do servidor

  • call.audio transporta o áudio combinado da chamada como PCM mono de 16 bits com sinal, na taxa call.audio.sampleRate, nos dois sentidos. Escreva o áudio em tempo real.
  • call.video recebe o vídeo de cada um dos outros participantes como um stream separado de quadros H.264 e envia um stream H.264 seu. call.video.sources indica o participante por trás de cada stream. Envie um keyframe (uma unidade de acesso com uma fatia IDR, com SPS e PPS nela ou antes dela) quando o evento keyframeRequest disparar. Os outros participantes começam a receber o seu vídeo a partir do seu primeiro IDR.
  • Quando a conexão cai, o cliente a reconecta e mantém a chamada.
@polymorfa/sdk/calls roda no Node.js 22 ou posterior, ou no Node.js 20 com uma implementação de WebSocket passada nas opções.

Atender, entrar ou recusar

Toda chamada recebida gera call.received. Os SDKs a expõem como uma chamada que está tocando. Escolha exclusive em cada atendimento:
  • exclusive: true faz o claim da chamada. Os outros participantes param de tocar, não podem atender nem se conectar, e as conexões abertas deles são fechadas. Use quando uma pessoa cuida da chamada, por exemplo quando o primeiro agente a atender fica com ela.
  • exclusive: false (o padrão) mantém a chamada compartilhada. Os outros participantes continuam tocando e podem entrar.
Um atendimento posterior em uma chamada compartilhada entra nela. Repetir um atendimento como o mesmo participante é seguro. Somente o participante que atendeu pode fazer o claim de uma chamada compartilhada depois; um claim de qualquer outro participante falha com call_claimed, e assim os participantes que já entraram continuam conectados. Em uma chamada que você fez, o participante que fez a chamada é o participante que atendeu. Quando outro participante faz o claim de uma chamada, o SDK indica que o claim foi feito em outro lugar. Pare de tocar e não recuse a chamada: recusar encerra a chamada para o participante que atendeu. Uma chamada que ninguém atende nem recusa dentro da janela de toque termina com call.missed e o motivo ring_timeout. Depois de atender, conecte a mídia logo; uma chamada sem mídia conectada termina com o motivo setup_timeout.

Fazer uma chamada

No navegador, chame calls.controller.place("+15550100", { video: true }). No código do servidor, chame client.place("+15550100"). No seu servidor:
A resposta traz o callId enquanto o dispositivo da pessoa chamada toca. call.accepted vem em seguida, quando a pessoa atende, e call.ended quando a chamada termina. to é um número de telefone E.164 ou um ID de usuário. Um token de cliente faz chamadas pela sessão à qual está vinculado; uma chave de equipe ou um token de projeto precisa indicar session.

Chamadas para pessoas que nunca conversaram com o número

O WhatsApp às vezes restringe um número a iniciar conversas e chamadas apenas com pessoas com quem ele já conversou. Enquanto essa restrição está ativa, a Polymorfa recusa uma chamada para qualquer outra pessoa com 403 number_restricted antes que algo chegue ao WhatsApp, e retorna Retry-After quando o WhatsApp informou um horário de término. Chamadas para pessoas com quem o número já conversou continuam funcionando, assim como as chamadas recebidas. A mesma verificação vale para convites. session.restriction_updated avisa quando a restrição começa, muda e termina, para que você possa pausar a prospecção a frio e retomá-la automaticamente. Se uma chamada chegar ao WhatsApp enquanto o número está restrito, ela termina com reason: "call_restricted". Consulte Boas práticas de chamadas para saber como escolher para quem ligar e como aumentar o volume de um número novo. Os inícios de chamadas realizadas compartilham um limite por minuto para cada sessão de origem da sua equipe. Mudar o destino ou usar outra chave ou outro token de cliente não reinicia esse limite. Uma chamada acima do limite falha com 429 sem tocar no destino. Espere o próximo minuto antes de tentar novamente. O WhatsApp pode restringir um número de dispositivo vinculado cujas chamadas recebem denúncias. O risco é maior em chamadas para pessoas que nunca interagiram com o número. Consulte Boas práticas de chamadas antes de fazer chamadas em volume.

Controle de chamadas pelo servidor

messaging.voip também atende, entra, recusa e encerra chamadas a partir do seu servidor, e convida mais pessoas: accept retorna answered (true quando esta requisição atendeu a chamada, false quando ela entrou em uma chamada já atendida), answeredBy e exclusive. Consulte a referência da API para os campos de requisição e resposta.

Convidar mais pessoas

addParticipant faz tocar o telefone de outro usuário do WhatsApp para que ele entre em uma chamada ao vivo, transformando uma chamada individual em uma chamada em grupo. Os SDKs informam quando participantes entram, mudam de estado e saem; os webhooks informam as mesmas mudanças como call.participant_joined, call.participant_state e call.participant_left. Os participantes usam o mesmo id de usuário da Polymorfa em todos os lugares. Aliases conhecidos aparecem como phoneNumber, bsuid ou username. Os campos audioMuted e video são reservados e continuam false porque o WhatsApp não informa nenhum dos dois estados por participante. Para adicionar pessoas pela sua própria aplicação, dê um token de cliente a cada pessoa e peça que ela entre na chamada compartilhada.

Áudio, vídeo e configurações de chamadas

Cada participante recebe um único stream de áudio combinado. As pessoas no WhatsApp ouvem todos os participantes que você conecta à chamada. O que os seus próprios participantes ouvem depende do modo conferência.

Modo conferência

Os seus participantes são todos que você conecta a uma chamada: pessoas em um navegador, os seus servidores e bots e o seu PBX por meio de um tronco SIP. O modo conferência decide se eles ouvem uns aos outros. Ninguém ouve a própria voz em nenhum dos modos. Um participante com mais de uma conexão com a mesma chamada, por exemplo durante uma reconexão, não ouve a si mesmo pela outra conexão. Desative o modo conferência quando cada participante fala com o lado do WhatsApp de forma independente, por exemplo um bot que transcreve a chamada ao lado de um agente humano que não deve ouvir o bot. Altere o modo por sessão:
Uma atualização altera apenas as configurações que você envia; as demais mantêm os valores. revision aumenta a cada alteração. Para aplicar uma alteração somente se ninguém tiver alterado as configurações desde a sua leitura, envie a revision que você leu como expectedRevision; a atualização então falha com 409 state_conflict se elas tiverem mudado. Leia as configurações de novo e tente novamente. Uma sessão sem configurações salvas retorna callsEnabled: true, conferenceMode: true, inboundRoute: "clients", sipTrunkId: null, sipClaim: true, hostCloudApiCalls: false, revision: 0 e updatedAt: null. Ler exige sessions:read e salvar exige sessions:manage, com uma chave de equipe ou um token de projeto. Tokens de cliente não podem ler nem alterar as configurações de chamadas. Uma configuração salva vale para uma chamada na próxima vez que um participante a atender ou se conectar a ela, inclusive em chamadas em andamento. Quando não é possível ler a configuração, atender e conectar falham com 503 em vez de usar um valor que você não escolheu. Você também pode alterá-la no Console, nos detalhes do número. Consulte Get call settings e Update call settings.

Desativar chamadas em um número

Defina callsEnabled como false para interromper as chamadas em uma sessão sem desconectá-la:
Enquanto as chamadas estão desativadas:
  • fazer uma chamada, atender ou entrar em uma, convidar um participante e conectar mídia falham com 403 calls_disabled. Iniciar ou atender uma chamada pelo endpoint /calls da Graph API falha com um erro de permissão;
  • as chamadas recebidas são recusadas. Você ainda recebe call.received, seguido de call.rejected e call.ended; e
  • um tronco SIP não pode fazer chamadas pela sessão.
As chamadas em andamento continuam: o participante que atendeu ou fez uma chamada ainda pode reconectar a mídia dele a ela, e sair, encerrar e recusar chamadas continuam funcionando. Outros participantes não podem entrar em uma chamada em andamento. Defina callsEnabled de volta como true para permitir chamadas novamente. Uma alteração chega às chamadas recebidas e aos troncos SIP em cerca de um minuto. A Polymorfa encaminha o vídeo de cada participante como um stream separado e não os combina em uma grade. O lado do WhatsApp da chamada recebe um único stream de vídeo: a câmera do primeiro participante que envia vídeo, enquanto esse participante continuar conectado. Cada chamada informa as suas capabilities: video e invite. Os componentes do SDK ocultam os controles que uma chamada não suporta.

Números da Cloud API

Um número conectado pela WhatsApp Business Cloud API continua atendendo as chamadas recebidas pela sua integração com a Graph API até que você ative hostCloudApiCalls nas configurações de chamadas dele:
Com hostCloudApiCalls: true, os seus apps de chamadas recebem e atendem as chamadas recebidas do número, e o endpoint /calls da Graph API se recusa a atendê-las. Com false (o padrão), o Polymorfa Calls não hospeda chamadas recebidas no número, e a sua integração com a Graph API as atende. Enquanto as chamadas estão desativadas, a Polymorfa recusa as chamadas recebidas do número, seja qual for essa configuração. A configuração vale para chamadas que chegam depois da alteração. As chamadas que você faz com os SDKs sempre usam o Polymorfa Calls. As chamadas em um número da Cloud API funcionam da mesma forma nos SDKs, com estes limites:
  • As chamadas são individuais e somente de áudio. As capabilities delas informam video: false e invite: false. Fazer uma chamada de vídeo ou convidar um participante falha com unsupported_for_connection. Atender com vídeo atende apenas com áudio.
  • Antes de você fazer uma chamada, o destinatário precisa conceder à sua empresa permissão para ligar para ele. Sem isso, fazer a chamada falha com call_permission_required.
  • O WhatsApp permite de 30 a 60 segundos para atender uma chamada recebida da Cloud API. Atenda em até 30 segundos para evitar uma chamada perdida.

Webhooks

Histórico de chamadas

O Console lista as suas chamadas com estado, direção e duração, e mostra os participantes, as conexões e as medições de qualidade de cada chamada, os diagnósticos que o seu app informou e os resultados das entregas de webhook. Proprietários e administradores podem encerrar uma chamada ao vivo ou remover uma conexão dela ali.

Análises e registros de chamadas

Três endpoints da Platform API leem o seu histórico de chamadas. Eles aceitam uma chave de equipe ou um token de projeto com sessions:read. Um token de projeto lê apenas o próprio projeto; uma chave de equipe lê a equipe inteira, a menos que você informe projectId. O resumo das chamadas do Console usa o mesmo endpoint de estatísticas. Uma chamada mantém o projeto original depois que o número dela é excluído. Reutilizar o nome do número em outro projeto não transfere o histórico, as estatísticas nem o uso dele. Registros cujo projeto original é desconhecido têm projectId: null e aparecem apenas em leituras de toda a equipe. Os três aceitam os mesmos filtros: Cada chamada tem um único resultado:
  • answered: a mídia se conectou. Chamadas atendidas ainda em andamento contam aqui.
  • declined: um participante ou a outra parte recusou, ou a linha estava ocupada.
  • missed: ninguém atendeu antes de a chamada parar de tocar, ou quem ligou desligou primeiro.
  • failed: a chamada terminou antes de se conectar por qualquer outro motivo, como uma falha de conexão ou de capacidade.
  • in_progress: a chamada ainda está tocando.

Estatísticas

Sem since e until, o intervalo são os últimos 7 dias. groupBy seleciona os grupos:
  • day (o padrão) e hour retornam um grupo por dia ou por hora em timezone, incluindo os vazios. Um intervalo com day cobre no máximo 366 dias, e um intervalo com hour, no máximo 31 dias.
  • session retorna um grupo por número, começando pelos que têm mais chamadas, até 500 números. groupsTruncated é true quando mais números tiveram chamadas.
  • outcome retorna um grupo por resultado.
timezone aceita um nome IANA como UTC, CET ou Europe/Lisbon, em maiúsculas ou minúsculas; o timezone da resposta é o nome canônico. Deslocamentos UTC e strings POSIX como UTC+3 são recusados. Os grupos por hora são horas do relógio local: no dia em que um fuso muda o relógio, a hora pulada não tem grupo e a hora repetida forma um único grupo. Cada grupo e os totals informam calls, a contagem de cada resultado, answerRate, totalDurationSeconds e averageDurationSeconds. answerRate é o número de chamadas atendidas dividido pelo número de chamadas que não estão mais tocando. As durações contam apenas o tempo conectado. heatmap sempre tem 168 células, uma por dia da semana (1 é segunda-feira) e hora, em timezone.

Registros detalhados de chamadas

Cada registro tem callId, projectId, sessionId, direction, upstream, outcome, state, hasVideo, peerRef, startedAt, connectedAt, endedAt, durationSeconds e endReason. peerRef é o pseudônimo da outra parte, específico da equipe: a mesma pessoa tem o mesmo peerRef em todas as chamadas da sua equipe, mas ele não é um número de telefone e a Polymorfa não consegue convertê-lo de volta em um. GET /platform/calls retorna os registros do mais novo para o mais antigo. Passe page.nextCursor como cursor, com os mesmos filtros, para ler a próxima página. GET /platform/calls/export retorna os mesmos registros em CSV (format=csv, o padrão) ou em JSON delimitado por quebras de linha (format=ndjson), até 1.000 por requisição. Cada página CSV começa com uma linha de cabeçalho. Quando mais registros correspondem aos filtros, o cabeçalho de resposta Polymorfa-Next-Cursor contém o cursor da próxima página:
Em CSV, um valor de texto que começa com =, +, -, @, uma tabulação ou um retorno de carro recebe um apóstrofo como prefixo, para que planilhas não o executem como fórmula. Use os endpoints HTTP autenticados acima para análises, registros e exportações de chamadas. O SDK TypeScript e a CLI não expõem essas operações de análise. O histórico de chamadas pode ficar atrasado em relação aos eventos ao vivo durante uma falha temporária de registro. As escritas que falharam são tentadas novamente por até 24 horas. Um evento atrasado não faz uma chamada aceita ou finalizada voltar a tocar.

Retenção de dados de chamadas

A exclusão começa em uma data anunciada com antecedência no changelog. Até lá, escolher um período registra a sua escolha e não exclui nada.
A sua equipe escolhe por quanto tempo a Polymorfa mantém os dados de chamadas dela. Quando a exclusão começar, a Polymorfa excluirá os dados de chamadas mais antigos que esse período. O período vale para:
  • registros de chamadas: o histórico de chamadas que o Console e a API listam;
  • eventos de chamadas: o histórico de participantes e conexões de cada chamada;
  • os diagnósticos que os seus apps informam sobre as conexões deles nas chamadas.
A Polymorfa não grava o áudio nem o vídeo das chamadas e não armazena o número de telefone nem o endereço do WhatsApp da outra parte. Escolha uma política: Depois que a exclusão estiver em funcionamento, a Polymorfa exclui os dados de chamadas em até 24 horas depois que eles ficam mais antigos que o período. Um acúmulo grande, como os dados de chamadas já armazenados quando a exclusão começa ou quando você encurta o período, pode levar mais tempo para ser excluído. Uma chamada é medida a partir do momento em que começou; uma chamada que ainda está tocando ou em andamento é mantida até terminar. O período cobre todos os projetos da equipe.
Depois que a exclusão estiver em funcionamento, um período mais curto também vale para os dados de chamadas já armazenados: os dados mais antigos que o novo período são excluídos em até 24 horas e não podem ser recuperados. Um período mais longo não restaura dados que já foram excluídos.
Leia a configuração com qualquer chave de equipe ou token de projeto que tenha sessions:read:
Altere a configuração com uma chave de equipe que tenha sessions:manage. Envie retentionDays apenas com a política custom:
  • Tokens de projeto podem ler a configuração, mas não alterá-la; uma alteração falha com 403. Tokens de cliente não podem fazer nenhuma das duas coisas.
  • Uma equipe sem configuração salva retorna revision: 0 e updatedAt: null. revision aumenta a cada alteração. Envie a revision que você leu como expectedRevision para recusar a atualização com 409 state_conflict se alguém tiver alterado a configuração depois da sua leitura.
  • Uma política nomeada com um retentionDays diferente, ou custom sem um, falha com 400 invalid_parameter.
  • appliesTo lista os tipos de dados de chamadas que o período cobre. Quando a Polymorfa passar a armazenar um novo tipo de dado de chamada, ele será adicionado a essa lista e seguirá o mesmo período.
Proprietários e administradores da equipe também podem alterar o período no Console, na página Chamadas. Consulte Get call retention e Update call retention.

Informar diagnósticos de chamadas pelo seu app

O seu app pode enviar as medições de qualidade e os erros que mede em cada uma das conexões dele. O Console os mostra na página de detalhes da chamada, ao lado das medições do serviço de mídia da Polymorfa. Os relatórios são opcionais; uma chamada sem eles funciona da mesma forma. Envie os relatórios com POST /messaging/voip/calls/{id}/reports. Os SDKs da Polymorfa não os enviam por você; chame o endpoint pelo seu app. Use a credencial que transporta a chamada: um token de cliente precisa da ação voip_signal, e uma chave de equipe ou um token de projeto informa como server:<participant>.
Um relatório bem-sucedido retorna 202 com { "success": true }. As medições de qualidade são números inteiros ou nomes curtos: Códigos de erro: Os relatórios aceitam apenas esses campos. A Polymorfa não aceita mensagens de erro, nomes de dispositivos, endereços IP, SDP nem user agents em um relatório; uma requisição que os contenha falha com 400. Limites:
  • Cada conexão pode enviar um relatório de qualidade a cada 5 segundos e 20 relatórios de erro por minuto. Os excedentes falham com 429. Os relatórios também contam para a regra rateLimit de um token de cliente.
  • A Polymorfa aceita relatórios enquanto a chamada está ao vivo e por 10 minutos depois que ela termina. Relatórios posteriores falham com 409, ou com 410 quando a chamada terminou porque o host de mídia dela foi perdido.
  • A Polymorfa mantém até 200 relatórios por chamada. Nesse limite, um relatório de qualidade substitui o relatório de qualidade mais antigo da mesma conexão. Um relatório de qualidade de uma conexão sem nenhum relatório de qualidade armazenado, e todo relatório de erro, retornam 202, mas não são mantidos.
  • A Polymorfa autoriza a chamada, não a conexão: qualquer participante como o qual a sua credencial pode agir pode enviar relatórios de qualquer connectionId em uma chamada que essa credencial alcança.
Os relatórios são excluídos junto com o histórico da chamada quando ultrapassam o período de retenção de dados de chamadas da sua equipe. Excluir uma equipe remove o acesso ao histórico dela; isso não garante a eliminação imediata dos registros retidos. Uma cadência que mantém o Console atualizado: um relatório de qualidade a cada 15 segundos durante a chamada e um quando a conexão fecha, além de um relatório de erro sempre que ocorrer um erro.

Limites de acesso

Toda operação de chamada fica dentro do limite de recursos da credencial. Chaves de equipe podem controlar chamadas em toda a equipe. Tokens de projeto podem controlar chamadas em qualquer sessão desse projeto. Tokens de cliente podem controlar chamadas apenas na sessão à qual estão vinculados. Uma chamada fora desse limite falha com 409 antes que a operação altere o estado da chamada. As regras de cliente valem para estabelecimentos de chamada, chamadas feitas e convites:
  • maxSetupsPerMinute limita os estabelecimentos de chamada por usuário de token de cliente (padrão 10). Cada chamada feita e cada convite contam como um estabelecimento. Em uma chamada existente, o primeiro atendimento ou a primeira conexão bem-sucedida conta como um estabelecimento; os seguintes na mesma chamada não contam.
  • allowedNumber é uma lista separada por vírgulas de números E.164 para os quais um token de cliente pode ligar ou que ele pode convidar.
  • maxConcurrency limita as chamadas que um usuário de token de cliente mantém ao mesmo tempo. Uma chamada ocupa a vaga dela até terminar.
Exceder um limite falha com 429. Uma chamada libera a vaga de simultaneidade quando termina, mesmo que o seu cliente se desconecte sem encerrá-la. Se uma chamada feita ou um estabelecimento falhar sem um resultado confirmado, a vaga fica reservada por até quatro horas, porque a chamada ainda pode estar ativa caso a resposta tenha se perdido.

Erros

Os SDKs geram esses erros como erros tipados; call_claimed é um CallClaimedError. Consulte Erros para o objeto de erro.

Controles da tabela no Console

A tabela Chamadas abre primeiro. Use os filtros dela para selecionar atividade, estado, direção, número e datas. Gerenciar troncos SIP, Política de chamadas, Atualizar chamadas e o botão API ficam ao lado dos filtros. A análise de chamadas aparece abaixo da tabela.