Listar e inspecionar números
Liste todos os números de WhatsApp da sua conta ou obtenha o detalhe completo de um número — incluindo a saúde e, para números Meta, dados em tempo real do Meta Graph.Use uma chave de API com escopo de tenant para gerenciar números em toda a sua conta. Uma chave com escopo de número também pode chamar esses endpoints. Autentique-se com o cabeçalho
x-api-key: ps_....GET /v1/numbers — Listar todos os números
Lista todas as instâncias de WhatsApp do tenant da chave de API como um array JSON.- Não retorna credenciais de sessão.
- Cada número expõe seu
statede conexão plano e uma flagisFullyConnected. - A listagem não força uma atualização em massa do estado de conexão — use
GET /v1/numbers/{id}/statuspor número quando precisar de uma verificação em tempo real. - As entradas
apiKeysde cada item incluem apenasname,keyPrefixekeyLast4(sem oidda chave de API). - Itens Meta (Cloud API) também trazem um bloco
coexistence— veja a seção de Coexistência abaixo. - Todo item traz
extraChargeUnpaidSinceeextraChargeDisconnectAt— veja Cobrança de número extra sem pagamento abaixo.
GET /v1/numbers/ — Detalhe completo de um número
Retorna ostate/isFullyConnected plano, um bloco health (veja O bloco health) e — para números Meta — um bloco aninhado em camelCase meta com informações de phone, profile e waba obtidas do Meta Graph. Para números não-Meta, meta é null.
string
Adicione
?refresh=1 para forçar uma busca em tempo real no Meta Graph e persistir o snapshot. Por padrão, a resposta é armazenada em cache (último snapshot meta).404 se o id não pertencer ao tenant do chamador.
"provider": "PILOT_STATUS", "meta": null e "coexistence": null.
O bloco historyImport
O que aconteceu com o histórico do aparelho na conexão atual. Os dois campos vêm null quando nada aconteceu.
Os dois são definitivos. A Meta entrega o histórico de um número uma vez só, e apagar e reconectar o número não faz ela enviar de novo. Uma nova conexão do mesmo número começa com os dois
null.
O bloco health
health é o único lugar que responde este número consegue enviar agora, e se não, por quê. Ele é derivado dos sinais da Meta por um avaliador compartilhado, então a lista, o detalhe e o painel nunca discordam.
Um bloqueio de envio fica fora de health: a cobrança de número extra sem pagamento. Ela é informada por extraChargeUnpaidSince, no nível de cima do número — veja Cobrança de número extra sem pagamento.
boolean
É o nosso veredito, não o da Meta. O
state / isFullyConnected de um número Meta são derivados dela (sendable → "OPEN", caso contrário "DISCONNECTED").Leia como “a Pilot Status acredita, agora, que este número consegue enviar” — que é a soma dos campos abaixo, e não a mesma pergunta que “a Meta vai aceitar o próximo envio”. A segunda só a Meta responde, e responde por mensagem, na resposta àquele envio.string | null
A nota de qualidade da Meta para o número, em maiúsculas e repassada:
GREEN, YELLOW, RED, UNKNOWN. null quando a Meta não informou nenhuma. RED interrompe o envio do nosso lado (sendable: false).string | null
O limite de mensagens do próprio número (
messaging_limit_tier), por exemplo TIER_250, TIER_1K, TIER_2K, TIER_10K, TIER_100K, TIER_UNLIMITED. null quando a Meta não reporta nenhum para ele — o que já é informação: um número sem tier próprio não é um número Cloud API plenamente registrado, e chamadas não podem ser habilitadas nele.string | null
O limite do Business Portfolio (
whatsapp_business_manager_messaging_limit), mantido como campo próprio. A Meta o devolve mesmo quando o tier por número está ausente.Ele já substituiu o messagingLimitTier sempre que a Meta omitia o do número, e a substituição era invisível: o painel mostrava “2K/24h” para um número em TIER_250, e o portão de habilitar chamadas abria para 17 números que não tinham tier nenhum. Qual dos dois governa um envio é decisão da Meta, não nossa — leia os dois, e trate messagingLimitTier: null como “este número não tem limite próprio”, nunca como “ele tem o do portfólio”.string | null
O
status do número de telefone na Meta, em maiúsculas e repassado verbatim — não o enumeramos, porque a Meta acrescenta valores sem aviso. O que fixamos é a classificação de cada um:Um valor fora dos dois conjuntos não contribui para o veredito; a qualidade e a regra do número de teste abaixo ainda podem bloquear.
string | null
Causa legível por máquina,
null quando saudável — com uma exceção, meta_phone_not_registered, que vem numa linha HEALTHY com sendable: true. Ramifique por aqui, não pelo reason.string | null
A mensagem legível por humano da mesma causa, em português. String de diagnóstico, não contrato — o texto muda entre releases. Exiba; não faça parse.
As transições de saúde também são empurráveis.
number.health_degraded, number.health_blocked, number.health_shadowban, number.recovered, number.inbound_stalled e number.inbound_recovered disparam na transição e estão no seletor de eventos — assine cada uma pelo nome, sem precisar do curinga "*".⚠️ Elas chegam na forma canónica { event, data }, não no envelope nativo da Meta. Se assinar saúde e conversa no mesmo webhook, o seu endpoint recebe dois formatos na mesma URL. Veja saúde do número na referência de eventos.Cobrança de número extra sem pagamento
Um número extra — um número acima da capacidade que o seu workspace já pagou — é cobrado quando conecta pela primeira vez (Números extras). Se essa cobrança é recusada, o número continua conectado, mas o envio por ele fica bloqueado até o pagamento. Dois campos no nível de cima informam isso, em todo item deGET /v1/numbers (não oficiais e Meta) e em GET /v1/numbers/{id}:
string | null
Instante ISO 8601 em que a cobrança foi recusada pela primeira vez. O envio pelo número está bloqueado desde então:
POST /v1/messages/send responde 409 NUMBER_BLOCKED com reason: "extra_charge_unpaid". null quando o número não está bloqueado.string | null
Instante ISO 8601 em que o número será desconectado se continuar sem pagamento — 7 dias depois de
extraChargeUnpaidSince. null quando o número não está bloqueado, e sempre null em número da Meta Cloud API: ele nunca é desconectado, fica bloqueado para envio até o pagamento.POST /v1/numbers/{id}/pay, recarregue a carteira ou salve um cartão. Depois do pagamento, os dois campos voltam a null.
Atualizando a partir do Meta Graph
?refresh=1 é a única coisa que lê a Meta. Nada atualiza o meta por agendamento para você: sem ele, meta.fetchedAt fica preso a quando o snapshot foi gravado pela última vez — tipicamente o momento do pareamento — não importa quanto tráfego o número tenha tratado desde então.
O que custa um refresh: quatro leituras sequenciais na Graph (o nó do telefone, o perfil comercial, a WABA e as configurações de chamada), cada uma com try/catch independente, mais uma escrita para persistir o snapshot. Não há limite de taxa nosso na chamada; o teto que você vai encontrar é o throttling da própria Graph, compartilhado com toda outra chamada feita com o token daquele número.
Como o refresh persiste, a atualidade não é propriedade do endpoint: um GET /v1/numbers posterior lê o mesmo snapshot que o refresh acabou de gravar. A lista não é permanentemente “mais fraca” que o detalhe — é o mesmo cache.
Por que
coexistence.evidence pode diferir entre duas chamadas no mesmo instante. As duas rotas rodam o mesmo predicado, e ele prefere a evidência mais forte presente no snapshot:meta.phone.isOnBizApp→meta_is_on_biz_app- senão
metaIsCoexistence(gravado do que a Meta respondeu no onboarding) →history_sync - senão a impressão digital →
phone_fields(só aparece comLIKELY) - senão
UNKNOWN
is_on_biz_app é um campo não documentado da Graph, então ele viaja na lista rica de campos; se essa requisição falha, caímos para um conjunto mínimo que não o inclui. Um snapshot sem ele responde então por history_sync — mesmo status, evidência mais fraca. Um ?refresh=1 bem-sucedido recoloca o isOnBizApp no snapshot, e a partir daí as duas rotas reportam meta_is_on_biz_app.Coexistência — e por que o platformType não responde isso
Coexistência significa que o número continua ativo no app WhatsApp Business de um aparelho e, ao mesmo tempo, está conectado à Cloud API.
Leia o bloco coexistence. Ele vem nos números Meta tanto em GET /v1/numbers quanto em GET /v1/numbers/{id}, e é null para números não oficiais (pareados por QR).
string
CONFIRMED — o número está em coexistência.
NO — não está; é um número Cloud API puro (indisponível no app do celular).
LIKELY — inferido, não respondido: a Meta deixa marcas num número em coexistência (ela recusa o /register, então ele fica NOT_VERIFIED, com nameStatus NON_EXISTS e sem PIN).
UNKNOWN — não é possível responder com o que temos.string
De onde veio a resposta, para você separar resposta de palpite:
meta_is_on_biz_app (campo da própria Meta, também espelhado em meta.phone.isOnBizApp), history_sync (o que a Meta respondeu quando pedimos o histórico do aparelho) ou phone_fields (a inferência acima — só aparece com LIKELY). É null quando o status é UNKNOWN.O que a coexistência muda na prática
- A Meta recusa o
/registerdo número (“not available for SMB businesses”), então ele nunca vira um número Cloud API plenamente registrado. - Chamadas não podem ser habilitadas enquanto o número seguir em coexistência.
- Mensagens funcionam normalmente — envio e recebimento não são afetados.
- Para usar chamadas, o número precisa ser migrado para fora do app WhatsApp Business. Essa decisão é de quem é dono do número.