No manual tokens
Users never see or paste access tokens — the exchange happens server-side.
Embedded Signup is the self-serve way to connect a WhatsApp Business Account (WABA) to Whatomate. Instead of manually copying a permanent access token, phone ID, and WABA ID out of the Meta dashboard, the user clicks a button, authenticates with Facebook in a popup, and Whatomate does the token exchange, discovery, subscription, and registration for them.
Embedded Signup wraps Meta's official onboarding flow (the Facebook JS SDK launching Meta's Embedded Signup dialog). The user grants your Meta app access to their WhatsApp Business Account and phone number; the SDK hands back a short-lived authorization code; Whatomate exchanges it for a permanent access token, discovers the WABA and phone number behind it, subscribes your app to the account's webhooks, and (for most numbers) registers the phone — all in one round trip.
No manual tokens
Users never see or paste access tokens — the exchange happens server-side.
Auto-discovery
WABA ID and phone number are discovered from the token if the SDK didn't supply them.
Encrypted at rest
The permanent token, app secret, and PIN are AES-encrypted before being saved.
Coexistence
SMB numbers still running on the WhatsApp Business mobile app connect without registration.
Embedded Signup needs Meta app credentials configured in the [whatsapp] section of config.toml:
[whatsapp]webhook_verify_token = "random-string-change-this"app_id = "" # Meta App ID for Embedded Signupapp_secret = "" # Meta App Secretconfig_id = "" # WhatsApp Config ID for frontend login| Setting | Purpose |
|---|---|
app_id | Your Meta App ID. Sent to the frontend so the Facebook JS SDK can launch the dialog. |
config_id | The Embedded Signup configuration ID from your Meta app. Selects which onboarding flow the SDK shows. |
app_secret | Your Meta App Secret. Used server-side to exchange the code for a token and to debug the token during discovery. Never sent to the frontend. |
webhook_verify_token | Default verify token for the /api/webhook endpoint; a per-account token is generated if you don't pass one. |
See Configuration for the full [whatsapp] block and environment-variable overrides.
The frontend fetches the resolved (non-secret) values before launching the dialog:
GET /api/embedded-signup/config→ { "whatsapp_app_id": "…", "whatsapp_config_id": "…", "whatsapp_api_version": "v21.0" }The app secret is deliberately not included in this response.
Launch the dialog. The frontend loads the Facebook JS SDK with the app_id and config_id from /api/embedded-signup/config and opens Meta's Embedded Signup dialog. The user selects (or creates) their WhatsApp Business Account and phone number and grants your app permission.
SDK returns a code. On success the SDK returns a short-lived authorization code (and, usually, the phone_id and waba_id).
Exchange the code. The frontend posts it to the backend:
POST /api/accounts/exchange-token{ "code": "…", "phone_id": "…optional…", "waba_id": "…optional…", "name": "…optional…", "webhook_verify_token": "…optional…"}The server then:
whatsapp_business_management granular scopes for the WABA ID (falling back to shared-WABA lookup), then lists the WABA's phone numbers and picks the first one.Response. On success the account is returned; if it went active via registration the generated pin is included, and if registration failed a warning is returned so the user can register manually.
Both GET /api/embedded-signup/config and POST /api/accounts/exchange-token require an authenticated session; the exchange additionally requires accounts:write.
Cloud API phone numbers must be registered with a 6-digit two-step-verification PIN before they can send. Exchange-token attempts this automatically, but if it failed (the account comes back with a warning and a pending_registration status) you can register it explicitly:
POST /api/accounts/{id}/register{ "pin": "…optional 6-digit PIN…" }If you omit the PIN, the server generates a secure random one. On success the account status flips to active and the PIN is returned so you can store it. This endpoint also requires accounts:write.
Coexistence lets a number that's still being used in the WhatsApp Business mobile app connect to the Cloud API at the same time — the small-business owner keeps chatting from their phone while Whatomate mirrors those conversations.
During exchange-token, Whatomate inspects the phone number info from Meta and flags the account IsSMB when the number is on the Business App (is_on_biz_app) or its platform type is SMB / SMB_CLOUD_API. For these numbers:
POST /api/accounts/{id}/register set the account straight to active with no PIN.[whatsapp] config block and env overrides