Skip to main content
Se você tem um SaaS e quer que seus clientes conectem o WhatsApp API Oficial (Cloud API) sem sair do seu produto, a D-API funciona como provedor: você embute um fluxo de conexão, cada número conectado vira uma conexão na sua conta D-API, e você é cobrado por conexão. Você repassa como quiser para o seu cliente.
  • Você é um usuário normal da D-API (sua API key secreta fica no seu backend).
  • Seu cliente conecta o número dele; a conexão fica sob a sua conta, identificada por um connectionId.
  • Cobrança da Meta é do seu cliente (ele usa o método de pagamento dele na WABA). A D-API só cobra a taxa de plataforma por conexão de você.

Como funciona

O Embedded Signup da Meta não roda no domínio do seu SaaS (a Meta exige domínios cadastrados). Por isso o fluxo roda numa página hospedada pela D-API (connect.d-api.cloud), que você abre como popup. O resultado volta pro seu app por postMessage. Seu domínio não precisa ser cadastrado na Meta.
1

Crie uma publishable key

Uma publishable key (pk_live_…) é pública de propósito: só inicia o onboarding — não envia mensagens nem lê dados. Crie no painel em Integrações → Publishable Keys, ou via API com a sua API key secreta:
A resposta traz o key uma única vez — guarde.
2

Abra o connect no seu frontend

Use o pacote d-api-sdk (entry d-api-sdk/connect):
Isso abre o popup hospedado, roda o Embedded Signup e resolve com o connectionId (e o access token da Meta). Também dá para fazer o handshake “na mão”, em HTML puro — veja o exemplo completo.
3

Associe o connectionId ao seu cliente

Guarde o connectionId retornado no seu banco, ligado ao cliente correspondente. A partir daí, esse número é uma conexão normal da D-API.
4

Envie mensagens pelo seu backend

Com a sua API key secreta (nunca no navegador), o connectionId é o sessionId nas rotas normais de envio:

Coexistência (manter o app WhatsApp Business)

Por padrão o fluxo cria/onboarda um número novo na API Oficial. Se o seu cliente quer manter o app WhatsApp Business no mesmo número (coexistência), passe mode: "coexistence":
O fluxo é o mesmo do padrão — a janela vai direto para a Meta e volta com o connectionId. A diferença é o que a Meta pede ao cliente: escanear um QR no app WhatsApp Business. A sincronização do histórico começa automaticamente e pode levar alguns minutos; oriente o cliente a manter o app aberto.

Webhooks

Você define o webhook da conexão no connect.start({ webhookUrl }), e pode alterar depois pela rota de atualização de sessão. Os eventos chegam com o id da conexão/sessão no payload — então você pode apontar todas as conexões para um único endpoint e distribuir pelo connectionId.

O resultado chega por dois caminhos

Toda conexão criada pelo connect hospedado é anunciada duas vezes, sem opção a configurar:
  1. o connect.start() resolve no navegador com o connectionId e o access token;
  2. um webhook session.created vai para o webhookUrl daquela conexão, com todos os dados — incluindo o access token e o seu metadata.
O segundo existe por causa do mobile. Em navegador de celular o popup abre como uma aba, sem window.opener utilizável, então o postMessage que o start() espera nunca chega: a promise pode rejeitar com “Conexão cancelada” enquanto a conexão foi criada normalmente. Em webview de app nativo vale o mesmo.
Em fluxo mobile, não trate a rejeição do start() como falha — confirme pelo session.created (ou pela rota de listagem de conexões) antes de mostrar erro para o seu cliente.

Correlacionar com o seu cliente (metadata)

metadata é um JSON livre seu, guardado com a conexão e devolvido intacto em data.metadata do session.created. É o que permite ligar a conexão ao tenant sem depender do retorno síncrono:
Limite: 512 bytes de JSON serializado. O valor viaja na URL do diálogo da Meta, e acima disso o start() lança erro antes de abrir a janela. Guarde ali identificadores, não objetos de negócio inteiros.
metadata é opcional e novo na versão 1.3.0 do SDK. Integrações em 1.2.0 ou anterior seguem funcionando sem alteração — apenas recebem metadata: {} no evento.

Formato dos eventos (webhookMode)

Você escolhe em que formato os eventos chegam:
Dá para trocar depois em Atualizar conexão (webhookMode).

Access token da Meta

O resultado do connect.start() traz também o access token da Meta daquela conexão, já descriptografado — útil se você quer chamar a Graph API direto (por exemplo, para gerenciar templates ou o catálogo por fora da D-API):
No Embedded Signup a Meta emite um token permanente (accessTokenKind: "permanent", accessTokenExpiresAt: null) — é o caso normal aqui. Os outros tipos aparecem quando o token foi trocado manualmente: long_lived (~60 dias) e short_lived (~1 hora).
O accessToken é segredo: com ele dá para enviar mensagens e administrar a WABA do seu cliente. Encaminhe para o seu backend e pronto — não registre em log, não salve no localStorage, não exponha em URL.
Se preferir que o token não trafegue pelo navegador, ignore o campo e busque no seu backend quando precisar, com a sua API key secreta:
A resposta traz o token e a mesma classificação — veja Obter access token da Meta.

Quando a conexão falha

Se o onboarding não conclui, a janela hospedada mostra o motivo em português, com o código embaixo — um print dela já serve para o suporte. O mesmo motivo volta para o seu app:
Com o SDK, o connect.start() rejeita com essa mensagem. Se você fez o handshake na mão, cheque o ok antes de ler o data — numa falha não existe data, e ler data.connectionId direto faz você perder o motivo real:
trial_required, plan_not_ready e billing_not_ready são sobre a sua conta D-API, não a do seu cliente — é a taxa de plataforma por conexão. A cobrança das conversas continua sendo da conta Meta do cliente.

Cobrança (pass-through)

A cobrança das conversas pela Meta é do seu cliente: durante o Embedded Signup ele usa o método de pagamento da conta Meta dele na WABA. A D-API não cobra as conversas — só a taxa de plataforma por conexão ativa, na sua conta. Lembre o seu cliente de finalizar o método de pagamento no WhatsApp Manager, se a Meta pedir.

Segurança

  • A publishable key é pública por design: escopo onboard apenas, com rate limit. O pior caso de vazamento é alguém iniciar um popup de Embedded Signup — sem acesso a dados nem envio.
  • A sua API key secreta nunca vai para o navegador — só no seu backend.
  • O resultado do onboarding só é entregue para a janela que abriu o popup, e o SDK valida que a mensagem veio do domínio hospedado da D-API.
  • O access token da Meta volta pela página hospedada no fragmento da URL (#…), que o navegador nunca envia ao servidor — ele não aparece em log de acesso nem em Referer, e a página o apaga da barra de endereço depois de repassar. Daí em diante a responsabilidade é sua: mande para o backend e não persista no browser.

Exemplo completo (HTML puro)

Um único arquivo, sem framework, mostrando o fluxo popup + postMessage passo a passo.