WhatsApp Founders

Área de membros

Carregando guias que economizam semanas de tentativa e erro…

Urgente

BSUIDs e Usernames do WhatsApp: guia completo para integrações

BSUIDs já estão em produção. Quando o usuário esconder o número, seu produto aguenta? Guia completo para adaptar antes que quebre.

Tem a senha deste guia ou da comunidade? A da comunidade vale para todos os materiais.

Quero fazer parte e receber esse tipo de conteúdo

BSUIDs e Usernames do WhatsApp: guia completo para integrações

BSUIDs já estão em webhooks de produção desde 31 de março de 2026. Se sua integração identifica contatos por telefone, você precisa agir. Este guia cobre tudo: campos, timeline, migração, Send API e checklist.

Última atualização: 30 de março de 2026

BSUIDs em produção desde
31 de março de 2026

Timeline de rollout

16/fev/2026: BSUIDs de teste Meta App Dashboard permite testar webhooks com BSUIDs simulados
31/mar/2026: BSUIDs em produção ← AGORA Todos os webhooks de produção passam a incluir BSUIDs. Campos de telefone podem ser omitidos quando usuário adota username.
Início de abril/2026: Contact Book Meta lança Contact Book: armazena pares telefone + BSUID de interações futuras (não retroativo)
Maio/2026: Envio por BSUID Send API aceita campo recipient com BSUID. Botão REQUEST_CONTACT_INFO disponível em templates (início de maio).
Mais adiante em 2026: Usernames para usuários Usuários poderão adotar usernames. Data exata pendente. BSUIDs já estarão nos webhooks antes disso.

O que são BSUIDs

Business-Scoped User ID — identificador único para cada par (usuário + portfólio de negócio). Gerado pela Meta, sempre presente nos webhooks a partir de 31 de março.

PropriedadeDetalhe
Formato{ISO 3166-1 alpha-2}.{alfanuméricos} — ex: BR.99887766554433221100
TamanhoCódigo do país + . + até 128 caracteres alfanuméricos
EscopoÚnico por par portfólio de negócio + usuário (não global)
PersistênciaRegenerado quando o usuário troca de número de telefone
Parent BSUIDFormato {CC}.ENT.{alfanuméricos} — para portfólios vinculados (linked portfolios)

Atenção: BSUIDs não são globais. Se você tem múltiplos portfólios, o mesmo usuário terá BSUIDs diferentes em cada um. E se o usuário trocar de número, o BSUID muda — a Meta envia um webhook user_id_update com o antigo e o novo.

Formato: Trate o BSUID como string opaca. Armazene e envie exatamente como recebido — não trunque, não remova o código do país, não altere casing. O tamanho pode variar (até 128 chars após o ponto), então use TEXT no banco, não VARCHAR(n).

Por que BSUIDs existem

O WhatsApp vai lançar usernames mais adiante em 2026. Quando um usuário adotar um username, poderá esconder o telefone de empresas nos webhooks.

Sem BSUIDs, uma empresa que recebe mensagem de um usuário com username não teria como identificá-lo — perderia o contexto, criaria duplicatas e quebraria fluxos.

BSUIDs chegam antes dos usernames. A Meta já envia BSUIDs em todos os webhooks de produção desde 31/março, mesmo antes de usernames estarem disponíveis para usuários. Isso permite que integrações se adaptem antecipadamente.

O que muda nos webhooks

Campos novos (sempre presentes a partir de 31/março)

Mensagens recebidas

  • contacts[].user_id — BSUID
  • contacts[].profile.username — se adotado
  • messages[].from_user_id — BSUID remetente

Status (sent/delivered/read)

  • contacts[]novo em status webhooks
  • contacts[].user_id — BSUID
  • statuses[].recipient_user_id — BSUID destino

Obs: contacts[] é omitido em status failed. username é omitido em status sent.

Campos que podem ser omitidos

Podem desaparecer

  • contacts[].wa_id — telefone
  • messages[].from — telefone remetente
  • statuses[].recipient_id — telefone destino

Quando são omitidos?

  • Usuário adotou username
  • E não houve interação nos últimos 30 dias por número de negócio
  • E usuário não está no Contact Book

Regra dos 30 dias: A visibilidade do telefone é avaliada por número de negócio. Se você mandou mensagem do número A há 15 dias, o telefone aparece nos webhooks do número A — mas NÃO nos do número B do mesmo portfólio, a menos que B também tenha interagido.

Comparação de payload: antes vs depois

Antes (só telefone — sem campos BSUID)
{
  "contacts": [{
    "wa_id": "5511999887766",
    "profile": { "name": "João" }
  }],
  "messages": [{
    "from": "5511999887766",
    "type": "text",
    "text": { "body": "Olá" }
    // Sem user_id, from_user_id ou username
  }]
}
Depois — BSUID + telefone (interação recente)
{
  "contacts": [{
    "user_id": "BR.99887766554433221100",    // ← NOVO: BSUID
    "wa_id": "5511999887766",                // presente (interação < 30d)
    "profile": {
      "name": "João",
      "username": "joao.silva"               // ← NOVO: se adotou username
    }
  }],
  "messages": [{
    "from": "5511999887766",                 // presente
    "from_user_id": "BR.99887766554433221100", // ← NOVO: BSUID
    "type": "text",
    "text": { "body": "Olá" }
  }]
}
Depois — BSUID-only (telefone omitido)
{
  "contacts": [{
    "user_id": "BR.99887766554433221100",    // ← BSUID: sempre presente
    // wa_id: OMITIDO (username + sem interação 30d)
    "profile": {
      "name": "João",
      "username": "joao.silva"
    }
  }],
  "messages": [{
    // from: OMITIDO
    "from_user_id": "BR.99887766554433221100", // ← único identificador
    "type": "text",
    "text": { "body": "Olá" }
  }]
}

Send API: to vs recipient

A Meta adiciona o campo recipient para enviar mensagens por BSUID. O campo to (telefone) continua funcionando.

CenárioCampoDisponível
Tem telefone"to": "5511999..."Sempre
Só tem BSUID"recipient": "BR.998..."Maio/2026 (data exata TBD)
Tem ambos"to"Phone tem precedência
BSUID antes de maioError 131062

Error 131062: BSUID recipients not supported for this message type. Retornado se você tentar enviar por BSUID antes de maio/2026. Classifique como erro de usuário — não faça retry.

Auth templates: Templates de autenticação (one-tap, zero-tap, copy code) não suportam envio por BSUID — exigem número de telefone. Isso vale mesmo após maio/2026.

Resposta da Send API

Quando você envia para telefone, a resposta inclui wa_id (telefone) mas não inclui user_id. Quando envia para BSUID, inclui user_id mas não inclui wa_id (a menos que o telefone esteja disponível via Contact Book).

Guard temporal recomendado
function buildSendPayload(phone, bsuid) {
  if (phone) {
    return { to: phone };            // Sempre funciona
  } else if (bsuid && isAfterMay2026()) {
    return { recipient: bsuid };     // Só a partir de maio/2026
  } else {
    logWarning("Sem identificador válido para envio");
    return null;
  }
}

Webhook user_id_update

Quando um usuário troca de número de telefone, o BSUID é regenerado. A Meta envia um webhook dedicado com o BSUID anterior e o atual.

Payload user_id_update
{
  "field": "user_id_update",
  "value": {
    "contacts": [{
      "profile": { "name": "João" },
      "wa_id": "5511999887766",        // se disponível
      "user_id": "BR.NOVO_BSUID..."    // BSUID atual
    }],
    "user_id_update": [{
      "wa_id": "5511999887766",
      "detail": "User id for João has been updated.",
      "user_id": {
        "previous": "BR.ANTIGO_BSUID...",
        "current": "BR.NOVO_BSUID..."
      },
      "timestamp": "1711756800"
    }]
  }
}

Crítico: Se você não tratar user_id_update, contatos que trocam de número "desaparecem" — o BSUID antigo não encontra mais ninguém. Inscreva seu app no campo user_id_update no App Dashboard.

Além do webhook dedicado, a Meta também envia uma system message de tipo user_changed_user_id com o texto User <NAME> changed from <OLD_BSUID> to <NEW_BSUID>.

Contact Book (início de abril/2026)

PropriedadeDetalhe
HospedagemMeta-hosted — sem integração necessária
GatilhoEnviar ou receber mensagem/ligação após o lançamento
RetroatividadeNÃO retroativo — só captura interações pós-lançamento
EscopoNível de portfólio de negócio (não individual por número)
DesabilitarDisponível desde 16/março/2026 em Meta Business Suite > Business settings > Business info
Ao desabilitarPara de armazenar e deleta dados existentes. Reabilitar começa do zero.
Portfólios vinculadosDados não são sincronizados entre portfólios — cada um é independente
Local storageModo opcional em que o Contact Book se comporta diferente com REQUEST_CONTACT_INFO (ver callout abaixo)

REQUEST_CONTACT_INFO e Contact Book: Por padrão, quando o usuário compartilha o telefone via este botão, o telefone é adicionado automaticamente ao Contact Book. Exceção: se você habilitou local storage no Contact Book, o telefone não é adicionado automaticamente — nesse caso, envie uma mensagem para o telefone do usuário para capturá-lo.

REQUEST_CONTACT_INFO (início de maio/2026)

Botão para templates de utility e marketing que solicita o telefone do usuário. Quando o usuário toca, a Meta dispara um webhook de contatos com telefone e vCard.

Template com botão REQUEST_CONTACT_INFO
{
  "type": "buttons",
  "buttons": [{ "type": "REQUEST_CONTACT_INFO" }]
}
// Botão não é customizável e não requer parâmetros no envio

Parent BSUIDs (portfólios vinculados)

Se a sua empresa tem portfólios vinculados (linked portfolios), a Meta pode fornecer um parent BSUID que funciona em todos os portfólios vinculados.

PropriedadeDetalhe
Formato{CC}.ENT.{alfanuméricos} — ex: US.ENT.11815799212886844830
Webhookcontacts[].parent_user_id, messages[].from_parent_user_id
UsoQualquer número de negócio nos portfólios vinculados pode usar o parent BSUID
AtivaçãoRequer contato com o representante Meta (POC)

Para tech providers e solution partners

Regra crítica para providers: O BSUID do cliente deve ser usado com os números de telefone do portfólio do cliente. Usar o BSUID do cliente com números do seu portfólio vai falhar.

Se você é tech provider ou solution partner, garanta que:

  • Cada cliente tem seu próprio conjunto de BSUIDs (escopo por portfólio)
  • Seu sistema associa BSUIDs ao portfólio correto
  • O envio por BSUID usa sempre o número de telefone do portfólio do cliente

O que pode quebrar

RiscoSeveridadeCausa
Contatos perdidosAltoSistema cria novo contato em vez de associar ao existente (sem lookup por BSUID)
Contatos duplicadosAltoMesmo usuário com dois registros: um pelo phone, outro pelo BSUID
Envio falhaAltoContato BSUID-only + envio por phone = mensagem não vai
UI crashesMédiophone.replace() ou wa.me/phone quando phone é null
Histórico perdidoMédiouser_id_update não tratado → contato "desaparece" ao trocar número
Campanhas falhamMédioAutomações que dependem de phone como destinatário

Migração: roteiro completo

flowchart TD A["1 · Auditar dependências
de phone_id"] --> B["2 · Schema: colunas bsuid
e username, phone nullable"] B --> C["3 · Indexes únicos
(bsuid, instance_id)"] C --> D["4 · Parser webhook:
user_id, from_user_id,
recipient_user_id, username"] D --> E["5 · Resolução dual:
phone-first, BSUID-fallback"] E --> F["6 · Backfill automático
(cruzado bidirecional)"] F --> G["7 · Handler
user_id_update"] G --> H["8 · Send API:
to vs recipient +
guard temporal"] H --> I["9 · UI null-safe
+ @username fallback"] I --> J["10 · Testar no Meta
App Dashboard"] J --> K(["Deploy + Monitorar"])

1. Auditar código

Busque todas as referências que assumem que from/wa_id são sempre números E.164. Inclua lookups por telefone, validações, links wa.me/, CRM e relatórios.

2. Adaptar banco de dados

PostgreSQL — schema mínimo
-- 1. Colunas BSUID e username
ALTER TABLE contacts ADD COLUMN IF NOT EXISTS bsuid TEXT;
ALTER TABLE contacts ADD COLUMN IF NOT EXISTS username TEXT;
ALTER TABLE chats ADD COLUMN IF NOT EXISTS bsuid TEXT;

-- 2. phone_id aceita NULL (CRÍTICO)
ALTER TABLE contacts ALTER COLUMN phone_id DROP NOT NULL;

-- 3. Tabela de mapeamento (auditoria)
CREATE TABLE IF NOT EXISTS bsuid_phone_mappings (
  id BIGSERIAL PRIMARY KEY,
  bsuid TEXT NOT NULL,
  phone_id TEXT,
  instance_id UUID NOT NULL,
  first_seen TIMESTAMPTZ DEFAULT NOW(),
  last_seen TIMESTAMPTZ DEFAULT NOW()
);

-- 4. Indexes únicos
CREATE UNIQUE INDEX IF NOT EXISTS idx_contacts_bsuid_instance
  ON contacts (bsuid, instance_id) WHERE bsuid IS NOT NULL;
CREATE UNIQUE INDEX IF NOT EXISTS idx_chats_bsuid_instance
  ON chats (bsuid, instance_id) WHERE bsuid IS NOT NULL;

3. Parsear novos campos do webhook

Pseudocódigo — extração de campos (mensagens recebidas)
// Webhook de MENSAGEM (payload.messages existe)
function parseIncomingMessage(payload) {
  const contact = payload.contacts[0];
  const message = payload.messages[0];

  // Campos NOVOS (sempre presentes a partir de 31/março)
  const bsuid    = contact.user_id;           // ← BSUID: sempre
  const username = contact.profile?.username;  // ← se adotou
  const fromBsuid = message.from_user_id;     // ← BSUID: sempre

  // Campos que PODEM ser omitidos (username + sem interação 30d)
  const phone = contact.wa_id || null;         // ← pode ser undefined!
  const from  = message.from || null;          // ← pode ser undefined!

  return { bsuid, username, phone, from, fromBsuid };
}

// Webhook de STATUS (payload.statuses existe — nunca junto com messages)
function parseStatus(payload) {
  // contacts[] é NOVO em status webhooks, omitido em status "failed"
  const contact = payload.contacts?.[0];
  const status  = payload.statuses[0];

  const bsuid = contact?.user_id || null;
  const recipientBsuid = status.recipient_user_id;  // ← BSUID destino

  return { bsuid, recipientBsuid };
}

4. Resolução dual-identifier

A estratégia recomendada é phone-first, BSUID-fallback:

Pseudocódigo — resolução dual
function resolveContact(phone, bsuid, username) {
  let contact = null;

  // 1. Tentar por phone (backward compatible)
  if (phone) {
    contact = findByPhone(phone);
    if (contact && bsuid && !contact.bsuid) {
      contact.bsuid = bsuid;          // Backfill BSUID
      contact.username = username;
      save(contact);
      logMapping(bsuid, phone);        // Auditoria
    }
  }

  // 2. Fallback: tentar por BSUID
  if (!contact && bsuid) {
    contact = findByBsuid(bsuid);
    if (contact && phone && !contact.phone) {
      contact.phone = phone;           // Backfill phone
      save(contact);
      logMapping(bsuid, phone);
    }
  }

  // 3. Nenhum encontrado: criar novo
  if (!contact) {
    contact = createContact({ phone, bsuid, username });
    if (phone && bsuid) logMapping(bsuid, phone);
  }

  return contact;
}

Por que phone-first? O campo to (phone) tem precedência no Send API e sempre funciona. Começando pelo phone, você mantém compatibilidade total com contatos existentes e enriquece com BSUID automaticamente.

5. Handler user_id_update

Inscreva seu app no campo user_id_update no Meta App Dashboard. Quando receber o webhook, atualize o BSUID no registro do contato:

Pseudocódigo
function handleUserIdUpdate(payload) {
  for (const update of payload.user_id_update) {
    const oldBsuid = update.user_id.previous;
    const newBsuid = update.user_id.current;
    const phone    = update.wa_id || null;

    const contact = findByBsuid(oldBsuid);
    if (contact) {
      contact.bsuid = newBsuid;
      save(contact);
      logMapping(newBsuid, phone);
    }
  }
}

6. Testar no App Dashboard

Desde 16/fev/2026, o Meta App Dashboard permite enviar webhooks de teste com BSUIDs. Teste estes cenários:

  • Cenário 1: Usuário SEM username → BSUID + phone presentes
  • Cenário 2: Usuário COM username, phone indisponível → BSUID + username, sem phone
  • Cenário 3: Usuário COM username, phone disponível → todos os campos
  • Cenário 4: user_id_update → BSUID antigo → BSUID novo

Checklist de migração

ItemPrioridadePrazo
Parsear contacts[].user_id e messages[].from_user_id dos webhooksCríticaAgora
Adicionar colunas bsuid e username no bancoCríticaAgora
Tornar phone_id nullableCríticaAgora
Implementar resolução dual (phone-first, BSUID-fallback)CríticaPrimeira semana de abril
Backfill automático cruzadoCríticaPrimeira semana de abril
Handler user_id_updateAltaAbril
UI null-safe (phone_id pode ser null)AltaAbril
Display @username como fallbackAltaAbril
Adaptar Send API (to vs recipient + guard temporal)AltaAntes de maio
Tratar error 131062 (user error, não retry)NormalAntes de maio
Configurar monitoring para BSUIDsNormalAbril
Implementar REQUEST_CONTACT_INFO em templatesNormalMaio+

Referências

Fonte: Meta Developer Documentation — Business-scoped user IDs. Última atualização do documento fonte: 23 de março de 2026. Qualquer mudança descrita pela Meta está sujeita a alteração.

Botões +/− ou roda do mouse: zoom · arrastar: mover · teclas + e − também ajustam o zoom · no telefone, use Compartilhar para enviar o link do material