> ## Documentation Index
> Fetch the complete documentation index at: https://docs.switchbord.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Meta Embedded Signup e Multi-WABA

> Como os workspaces fazem onboarding de WhatsApp Business Accounts adicionais por meio do Meta Embedded Signup, e como o Switchbord mantém o access token de cada WABA isolado no momento do envio.

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.

<Info>
  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.
</Info>

## 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:

| Caminho                                | O que faz                                                                                                                                                   | Componente                                     |
| -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- |
| **Traga seu próprio token**            | O wizard manual original — cole você mesmo um token de System User, o Phone Number ID e o WABA ID. Sempre disponível, incluindo em deployments self-hosted. | `WelcomeWizard`                                |
| **Faça onboarding com a gente**        | Faça login com a Meta e registre um número totalmente novo no WhatsApp Business. Sem copiar/colar token.                                                    | `EmbeddedSignupCard` (`defaultPath="onboard"`) |
| **Migrar conta de WhatsApp existente** | Faça login com a Meta e mova um número já registrado no WhatsApp Business para o Switchbord.                                                                | `EmbeddedSignupCard` (`defaultPath="migrate"`) |

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.

<Tip>
  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.
</Tip>

## 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:

| Requisito                                                                | Onde                                      | Efeito quando ausente                                                                                                                                 |
| ------------------------------------------------------------------------ | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `NEXT_PUBLIC_EMBEDDED_SIGNUP_ENABLED=1` (ou `true`/`on`/`enabled`/`yes`) | Ambiente Vercel de `apps/app`             | `/welcome` renderiza apenas o wizard manual — o seletor nunca aparece                                                                                 |
| `NEXT_PUBLIC_META_APP_ID` + `NEXT_PUBLIC_META_CONFIG_ID`                 | Ambiente Vercel de `apps/app`             | A flag de cliente resolve como desabilitada mesmo se a variável de ambiente acima estiver definida (o SDK JS do Facebook não consegue rodar sem elas) |
| `NEXT_PUBLIC_META_CONFIG_ID_MM` (opcional)                               | Ambiente Vercel de `apps/app`             | O checkbox "Enable Marketing Messages" fica oculto; todo signup usa a configuração padrão                                                             |
| `META_APP_ID` + `META_APP_SECRET`                                        | Ambiente de servidor Vercel de `apps/app` | A rota de API de troca (`/api/onboarding/meta/exchange`) responde `404 embedded_signup_disabled` mesmo que a UI esteja visível                        |

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`.

<Warning>
  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.
</Warning>

## 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.

```text theme={null}
resolveChannelAccessToken
  1. channel → provider account (whatsapp_provider_accounts)
  2. provider account → credential_secret_kind ("meta-access-token" | "meta-access-token-2".."-8")
  3. readWorkspaceSecret({ workspaceId, kind: credential_secret_kind })
       ↳ if empty and kind ≠ default → retry with "meta-access-token"
       ↳ if still empty → env WHATSAPP_META_ACCESS_TOKEN
```

<Info>
  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.
</Info>

## 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

* [Onboarding do Operador](/pt-BR/platform/onboarding) — o fluxo de primeiro acesso `/setup` e o checklist de prontidão
* [Credenciais da Meta — configuração passo a passo](/pt-BR/getting-started/meta-credentials) — o caminho manual de traga seu próprio token
* [Conectar WhatsApp](/pt-BR/platform/connect-whatsapp) — o walkthrough completo do Meta Business Suite
* [Arquitetura do Vault](/pt-BR/security/vault-architecture) — como os segredos do workspace (incluindo os slots de token de WABA) são armazenados e lidos
