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:

1import { useEffect, useState } from "react";
2
3declare 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
13interface EmbeddedSignupButtonProps {
14 apiKey: string;
15 onSuccess?: (numberId: string) => void;
16 onError?: (error: string) => void;
17}
18
19export 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
2app.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

IssueSolution
Popup blockedTrigger FB.login() directly from a user click event (not in setTimeout/async)
code is undefinedUser cancelled the flow — handle gracefully
403 from /completeThe code expired (valid for ~5 minutes) — ask the user to try again
Domain not allowedContact Muchaw DEV support to add your domain to the allowed list