Skip to main content
Os workspaces do Switchbord não estão mais limitados a uma única WhatsApp Business Account (WABA). Um workspace pode fazer onboarding de WABAs adicionais através do fluxo Embedded Signup da Meta — o próprio popup de login hospedado pela Meta — sem nunca precisar manipular um access token copiado manualmente. Cada WABA recebe seu próprio slot de credencial isolado, de forma que um segundo (ou terceiro) número nunca sobrescreve o primeiro.
O Embedded Signup é aditivo. O wizard original de “traga seu próprio token” em /welcome permanece inalterado e sempre disponível — o Embedded Signup é um segundo caminho, opcional, para workspaces que preferem o onboarding hospedado pela Meta em vez de colar um token de System User.

Três caminhos de onboarding

Quando o Embedded Signup está habilitado, /welcome apresenta um seletor (OnboardingPathChooser) com três cards, em vez de ir direto para o wizard manual: Escolher “Faça onboarding com a gente” ou “Migrar conta de WhatsApp existente” renderiza o mesmo EmbeddedSignupCard — a única diferença é o valor de path (onboard vs migrate) enviado ao endpoint de troca (exchange), e a própria UI de signup da Meta adapta seu texto de acordo. Um checkbox Enable Marketing Messages aparece quando um config_id de Meta com escopo de marketing está configurado, e altera qual config_id de login do Facebook é usado.
Toda tela do seletor tem um botão “Choose a different method” para voltar, de forma que um operador que inicia o Embedded Signup e chega a um beco sem saída (bloqueador de anúncios, popup fechado, erro da Meta) sempre pode retornar ao wizard manual de token sem recarregar a página.

Feature flag e pré-requisitos

O Embedded Signup vem desabilitado por padrão e é controlado por duas condições: uma flag pública de cliente e credenciais de app no lado do servidor: A verificação no lado do servidor é uma defesa em profundidade deliberada: ativar apenas a flag de cliente nunca pode, por si só, expor um fluxo de Embedded Signup funcional sem que as credenciais do app também estejam configuradas.

Como funciona a troca (exchange)

  1. O navegador carrega o SDK JS do Facebook uma vez (connect.facebook.net/en_US/sdk.js) e chama FB.login() com o config_id resolvido, solicitando um code de autorização.
  2. O popup da Meta também posta um evento postMessage WA_EMBEDDED_SIGNUP (validado contra uma origem facebook.com / *.facebook.com) contendo o waba_id e o phone_number_id que o operador selecionou dentro da própria UI da Meta.
  3. Uma vez que tanto o code quanto o par WABA/telefone tenham chegado, o card faz um único POST para /api/onboarding/meta/exchange com { code, wabaId, phoneNumberId, path, includeMarketingMessages }.
  4. A rota (apps/app/app/api/onboarding/meta/exchange/route.ts) executa uma sequência estrita no lado do servidor:
    • troca o code por um access token de negócio (exchangeEmbeddedSignupCode);
    • inspeciona o token com debugToken e exige os escopos whatsapp_business_management e whatsapp_business_messaging;
    • se os granular scopes da Meta enumerarem os WABA ids concedidos, o wabaId fornecido precisa estar nessa lista — um WABA id fornecido pelo cliente nunca é confiado às cegas;
    • confirma que o número de telefone realmente pertence àquela WABA via listWabaPhoneNumbers antes de fazer qualquer outra coisa;
    • gera e armazena um PIN de registro único de 6 dígitos (segredo meta-phone-pin) e chama registerPhoneNumberForCloudApi — uma falha de registro da Meta (já registrado, incompatibilidade de 2FA na migração) é tolerada e reportada de volta como phoneRegistered: false, em vez de falhar a requisição inteira;
    • gera um verify token por workspace e inscreve o app do Switchbord na WABA com um override_callback_uri delimitado por workspace (.../webhooks/meta?w=<workspaceId>);
    • resolve em qual slot de credencial o token dessa WABA pertence (veja abaixo), armazena o token e importa o número de telefone para um channel.
  5. A resposta nunca contém o access token, o PIN, o verify token, o META_APP_SECRET ou qualquer appsecret_proof — apenas channelId, wabaId, phoneNumberId, displayName, phoneRegistered e marketingMessagesEnabled.
A rota de troca (exchange) aplica um invariante estrito contra vazamento de segredos: os campos detail em respostas de erro só podem carregar a mensagem de erro já sanitizada da própria Meta. Tokens, PINs, verify tokens e o app secret nunca são registrados em log, capturados em telemetria de exceção, nem devolvidos ao navegador.

Isolamento de token multi-WABA

Antes deste trabalho, o token da Meta de cada workspace vivia sob um único tipo de segredo do Vault (meta-access-token) — uma segunda WABA conectada via Embedded Signup sobrescreveria silenciosamente o token da primeira WABA e quebraria seus envios. O Switchbord agora resolve o token de cada WABA de forma independente:
  • A conta de provider default (a primeira WABA de um workspace, ou uma já marcada como default) continua usando o tipo de segredo meta-access-token — workspaces com uma única WABA não são afetados de forma alguma.
  • Cada WABA adicional ocupa o primeiro slot livre de meta-access-token-2 até meta-access-token-8 (allocateWabaTokenSlotKind), registrado em whatsapp_provider_accounts.credential_secret_kind. Oito slots excedem confortavelmente qualquer contagem realista de WABAs por workspace.
  • resolveChannelAccessToken(admin, { workspaceId, channelId | channel }) é o único resolvedor usado por todo caminho crítico de envio (despacho de mensagens — que também cobre envios de campanha —, envios de mídia, envios interativos e sincronização de template). Ele resolve channel → conta de provider → credentialSecretKind, lê aquele slot do Vault, e recorre ao meta-access-token padrão do workspace e depois à variável de ambiente WHATSAPP_META_ACCESS_TOKEN se o slot estiver vazio. Nunca lança exceção por falta de token — os chamadores falham o despacho de forma explícita, exatamente como antes.
Isso é transparente para os operadores — não há campo de token por WABA para gerenciar em Settings. O tipo de slot é escolhido automaticamente no momento do onboarding e lido automaticamente no momento do envio. Settings → Provider continua mostrando apenas os tipos de credencial voltados ao operador; os tipos de slot de WABA são internos.

Verificando um workspace multi-WABA

  • Verifique whatsapp_provider_accounts para o workspace: a linha default tem is_default = true e credential_secret_kind = 'meta-access-token'; toda WABA adicional tem sua própria linha com seu slot credential_secret_kind e is_default = false.
  • Um envio para uma WABA não-default que reporta o número de remetente errado quase sempre significa que o credential_secret_kind daquela conta de provider está ausente ou aponta para o slot errado — verifique se setProviderAccountCredentialKind foi chamado durante o onboarding daquela WABA.
  • Se o Embedded Signup foi concluído, mas phoneRegistered retornou false, o número de telefone foi conectado ao channel, mas ainda não está registrado para envios via Cloud API — finalize o registro em Settings antes de esperar que os envios saiam.

Veja também