Implementando o Embedded Signup
Visão geral
Este guia mostra como implementar o fluxo completo de Embedded Signup no seu frontend — permitindo que seus usuários conectem seus números de WhatsApp Business ao seu produto sem sair do seu app.
Pré-requisitos
- Uma chave de API do Muchaw DEV
- Seu domínio deve ser adicionado à lista de domínios permitidos do Muchaw DEV (entre em contato com o suporte)
- Seu frontend deve ser servido via HTTPS
Implementação com React
Aqui está um componente React completo e pronto para usar:
1 import { useEffect, useState } from "react"; 2 3 declare global { 4 interface Window { 5 FB: { 6 init: (config: object) => void; 7 login: (callback: (response: { authResponse?: { code?: string } }) => void, options: object) => void; 8 }; 9 fbAsyncInit?: () => void; 10 } 11 } 12 13 interface EmbeddedSignupButtonProps { 14 apiKey: string; 15 onSuccess?: (numberId: string) => void; 16 onError?: (error: string) => void; 17 } 18 19 export function EmbeddedSignupButton({ 20 apiKey, 21 onSuccess, 22 onError, 23 }: EmbeddedSignupButtonProps) { 24 const [sdkConfig, setSdkConfig] = useState<{ 25 app_id: string; 26 config_id: string; 27 sdk_version: string; 28 } | null>(null); 29 const [status, setStatus] = useState<"idle" | "loading" | "pending" | "error">("idle"); 30 31 // 1. Buscar configuração do SDK ao montar 32 useEffect(() => { 33 fetch("https://dev.muchau.com.br/api/embedded-signup/init", { 34 headers: { Authorization: `Bearer ${apiKey}` }, 35 }) 36 .then((r) => r.json()) 37 .then(setSdkConfig) 38 .catch(() => setStatus("error")); 39 }, [apiKey]); 40 41 // 2. Carregar SDK do Facebook 42 useEffect(() => { 43 if (!sdkConfig) return; 44 45 window.fbAsyncInit = () => { 46 window.FB.init({ 47 appId: sdkConfig.app_id, 48 xfbml: true, 49 version: sdkConfig.sdk_version, 50 }); 51 }; 52 53 if (!document.getElementById("facebook-jssdk")) { 54 const script = document.createElement("script"); 55 script.id = "facebook-jssdk"; 56 script.src = "https://connect.facebook.net/en_US/sdk.js"; 57 script.async = true; 58 document.body.appendChild(script); 59 } 60 }, [sdkConfig]); 61 62 // 3. Acionar o fluxo de cadastro 63 const handleConnect = () => { 64 if (!sdkConfig || !window.FB) return; 65 setStatus("loading"); 66 67 window.FB.login( 68 async (response) => { 69 const code = response.authResponse?.code; 70 if (!code) { 71 setStatus("error"); 72 onError?.("Usuário fechou o popup ou negou a permissão"); 73 return; 74 } 75 76 try { 77 // 4. Completar cadastro via Muchaw DEV 78 const res = await fetch("https://dev.muchau.com.br/api/embedded-signup/complete", { 79 method: "POST", 80 headers: { 81 Authorization: `Bearer ${apiKey}`, 82 "Content-Type": "application/json", 83 }, 84 body: JSON.stringify({ code }), 85 }); 86 87 if (!res.ok) throw new Error(await res.text()); 88 89 const { number_id } = await res.json(); 90 setStatus("pending"); 91 onSuccess?.(number_id); 92 } catch (err) { 93 setStatus("error"); 94 onError?.(err instanceof Error ? err.message : "Erro desconhecido"); 95 } 96 }, 97 { 98 config_id: sdkConfig.config_id, 99 response_type: "code", 100 override_default_response_type: true, 101 } 102 ); 103 }; 104 105 if (!sdkConfig) return null; 106 107 return ( 108 <div> 109 <button onClick={handleConnect} disabled={status === "loading"}> 110 {status === "loading" ? "Conectando..." : "Conectar WhatsApp"} 111 </button> 112 {status === "pending" && ( 113 <p>Seu número está sendo ativado. Isso leva cerca de 30 segundos.</p> 114 )} 115 {status === "error" && ( 116 <p>Algo deu errado. Por favor, tente novamente.</p> 117 )} 118 </div> 119 ); 120 }
Implementação com HTML/JavaScript puro
1 <!DOCTYPE html> 2 <html> 3 <head><title>Conectar WhatsApp</title></head> 4 <body> 5 <button id="connect-btn">Conectar WhatsApp</button> 6 <p id="status"></p> 7 8 <script> 9 const API_KEY = "mk_live_..."; 10 let sdkConfig = null; 11 12 // 1. Buscar configuração do SDK 13 fetch("https://dev.muchau.com.br/api/embedded-signup/init", { 14 headers: { Authorization: `Bearer ${API_KEY}` }, 15 }) 16 .then((r) => r.json()) 17 .then((config) => { 18 sdkConfig = config; 19 20 // 2. Carregar SDK do Facebook 21 window.fbAsyncInit = () => { 22 FB.init({ appId: config.app_id, version: config.sdk_version }); 23 }; 24 const s = document.createElement("script"); 25 s.src = "https://connect.facebook.net/en_US/sdk.js"; 26 s.async = true; 27 document.head.appendChild(s); 28 }); 29 30 // 3. Gerenciar clique no botão 31 document.getElementById("connect-btn").addEventListener("click", () => { 32 if (!sdkConfig || !window.FB) return; 33 document.getElementById("status").textContent = "Conectando..."; 34 35 FB.login( 36 async (response) => { 37 const code = response.authResponse?.code; 38 if (!code) { 39 document.getElementById("status").textContent = "Cancelado."; 40 return; 41 } 42 43 // 4. Completar via Muchaw DEV 44 const res = await fetch( 45 "https://dev.muchau.com.br/api/embedded-signup/complete", 46 { 47 method: "POST", 48 headers: { 49 Authorization: `Bearer ${API_KEY}`, 50 "Content-Type": "application/json", 51 }, 52 body: JSON.stringify({ code }), 53 } 54 ); 55 const { number_id } = await res.json(); 56 document.getElementById("status").textContent = 57 `Ativando número ${number_id}... (~30 segundos)`; 58 }, 59 { 60 config_id: sdkConfig.config_id, 61 response_type: "code", 62 override_default_response_type: true, 63 } 64 ); 65 }); 66 </script> 67 </body> 68 </html>
Aguardando a ativação
Após /complete, o número entra no status PENDING. Configure um webhook para number.activated para saber quando estiver pronto:
1 // Exemplo: atualizar UI quando o número for ativado 2 app.post("/webhooks/whatsapp", express.raw({ type: "application/json" }), (req, res) => { 3 res.sendStatus(200); 4 const event = JSON.parse(req.body.toString()); 5 if (event.event === "number.activated") { 6 const numberId = event.data.id; 7 // Marcar o número como ativo no seu banco de dados 8 // Notificar o usuário via SSE/WebSocket/e-mail 9 console.log(`Número ${numberId} agora está ATIVO!`); 10 } 11 });
Problemas comuns
| Problema | Solução |
|---|---|
| Popup bloqueado | Acione FB.login() diretamente de um evento de clique do usuário (não em setTimeout/async) |
code é undefined | O usuário cancelou o fluxo — trate isso graciosamente |
403 de /complete | O code expirou (válido por ~5 minutos) — peça ao usuário para tentar novamente |
| Domínio não permitido | Entre em contato com o suporte do Muchaw DEV para adicionar seu domínio à lista de permitidos |