Implement Embedded Signup
Overview
This guide walks through implementing the full Embedded Signup flow in your frontend — allowing your users to connect their WhatsApp Business numbers to your product without leaving your app.
Prerequisites
- A Muchaw DEV API key
- Your domain must be added to Muchaw DEV’s allowed domains list (contact support)
- Your frontend must be served over HTTPS
React implementation
Here’s a complete, ready-to-use React component:
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. Fetch SDK config on mount 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. Load Facebook SDK 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. Trigger the signup flow 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?.("User closed the popup or denied permission"); 73 return; 74 } 75 76 try { 77 // 4. Complete signup 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 : "Unknown error"); 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" ? "Connecting..." : "Connect WhatsApp"} 111 </button> 112 {status === "pending" && ( 113 <p>Your number is being activated. This takes about 30 seconds.</p> 114 )} 115 {status === "error" && ( 116 <p>Something went wrong. Please try again.</p> 117 )} 118 </div> 119 ); 120 }
Plain HTML/JavaScript implementation
1 <!DOCTYPE html> 2 <html> 3 <head><title>Connect WhatsApp</title></head> 4 <body> 5 <button id="connect-btn">Connect WhatsApp</button> 6 <p id="status"></p> 7 8 <script> 9 const API_KEY = "mk_live_..."; 10 let sdkConfig = null; 11 12 // 1. Fetch SDK config 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. Load Facebook SDK 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. Handle button click 31 document.getElementById("connect-btn").addEventListener("click", () => { 32 if (!sdkConfig || !window.FB) return; 33 document.getElementById("status").textContent = "Connecting..."; 34 35 FB.login( 36 async (response) => { 37 const code = response.authResponse?.code; 38 if (!code) { 39 document.getElementById("status").textContent = "Cancelled."; 40 return; 41 } 42 43 // 4. Complete 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 `Activating number ${number_id}... (~30 seconds)`; 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>
Listening for activation
After /complete, the number enters PENDING status. Set up a webhook for number.activated to know when it’s ready:
1 // Example: update UI when number is activated 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 // Mark the number as active in your database 8 // Notify the user via SSE/WebSocket/email 9 console.log(`Number ${numberId} is now ACTIVE!`); 10 } 11 });
Common issues
| Issue | Solution |
|---|---|
| Popup blocked | Trigger FB.login() directly from a user click event (not in setTimeout/async) |
code is undefined | User cancelled the flow — handle gracefully |
403 from /complete | The code expired (valid for ~5 minutes) — ask the user to try again |
| Domain not allowed | Contact Muchaw DEV support to add your domain to the allowed list |