Docs

Meta WhatsApp SaaS setup

Operator notes for connecting Meta Embedded Signup, webhook subscriptions, and hosted setup flow.

This app supports multi-tenant onboarding: each customer org connects its own WhatsApp Business Account (WABA) via Embedded Signup (Facebook Login for Business). Operator login stays Supabase; Meta is only used to link customer WhatsApp assets.

1. Meta Business and app

  1. Create a Meta Business for your company and complete Business Verification when Meta requires it (required before App Review / Advanced Access for customer-facing onboarding).
  2. In Meta for Developers, create a Business app (or use an existing one) and add the WhatsApp product.
  3. Under WhatsApp → Getting started, note the App ID and App Secret (same secret used for webhook signature verification: WHATSAPP_APP_SECRET).

2. Tech Provider onboarding (dashboard)

  1. Open App Dashboard → Use cases → WhatsApp → Customize and follow Tech Provider onboarding (see Become a Tech Provider).
  2. You must complete business verification before App Review for Tech Provider permissions.
  3. Request Advanced Access for at least:
  1. Prepare separate screen recordings per permission (Meta rejects one video for multiple permissions).

3. Embedded Signup + Login for Business (OAuth)

The in-app flow uses the Facebook JS SDK (FB.login with config_id and response_type: code on the onboarding page). The server exchanges that code in exchangeEmbeddedSignupCode and must use the same redirect_uri Meta used for the dialog.

3a. Facebook Login for Business configuration

  1. In the Meta app, open Facebook Login for Business (under Use cases or Products) and create a configuration for WhatsApp Embedded Signup (per Meta’s Tech Provider / Embedded Signup docs).
  2. Copy the Configuration ID into NEXT_PUBLIC_META_EMBEDDED_SIGNUP_CONFIG_ID* (and use the same value only in public env; it is not secret).*

3b. Client OAuth settings (Facebook Login → Settings)

Match the Client OAuth screen to this app’s behavior:

SettingRecommended for this codebase
Client OAuth loginYes
Web OAuth loginYes
Enforce HTTPSYes (production)
Use Strict Mode for redirect URIsYes — then URIs must match exactly
Login with the JavaScript SDKYes — required because MetaEmbeddedSignupButton calls FB.login

Under Valid OAuth Redirect URIs, add every URL where users can finish the Embedded Signup dialog. In this repo the connect button is available on onboarding and Settings → Integrations, so include at least:

  • https://<your-production-domain>/onboarding
  • https://<your-production-domain>/app/settings/whatsapp
  • http://localhost:3000/onboarding (local dev; ngrok URL if you test through a tunnel, e.g. https://<subdomain>.ngrok-free.app/onboarding)

Strict mode means a bare origin like https://yourdomain.com will not match /onboarding.

Under Allowed Domains for the JavaScript SDK, add your site hostnames (e.g. yourdomain.com, localhost for dev).

3c. Server env: META_OAUTH_REDIRECT_URI

Set META_OAUTH_REDIRECT_URI to the same redirect URI Meta uses when exchanging the code — typically the full URL of the onboarding page (scheme + host + path, no trailing slash mismatch). It must appear in Valid OAuth Redirect URIs. If token exchange fails with a redirect mismatch, compare this value character-for-character to the URI in the Meta dashboard.

3d. Deauthorize / data deletion URLs

The Basic app settings may ask for a Deauthorize callback URL and Data Deletion Request URL. This repository does not ship dedicated routes for those yet; for App Review and compliance you will need HTTPS endpoints that accept Meta’s callbacks and document the behavior in your privacy policy.

4. Post–Embedded Signup (server-side)

After a customer completes Embedded Signup, your backend must:

  1. Exchange the returned code for a business integration system user access token (Onboarding customers as a Tech Provider).
  2. Call **POST /{waba-id}/subscribed_apps*** so your app receives webhooks for that WABA.*
  3. Register the business phone number for Cloud API where required (*POST /{phone-number-id}/register).*

This codebase performs these steps in lib/whatsapp/meta-onboarding.ts when the client posts the completion code to /api/integrations/meta/whatsapp/complete.

5. Webhooks

  • Configure the Callback URL in the Meta app to https://<your-domain>/api/webhooks/whatsapp.
  • Use a single Verify token (WHATSAPP_VERIFY_TOKEN) for the app.
  • Webhook verification uses WHATSAPP_APP_SECRET for X-Hub-Signature-256.

For multi-tenant inbound, org routing uses the phone number id in each webhook (metadata.phone_number_id) matched against rows in whatsapp_sessions / channel_connections.

6. Environment variables (summary)

VariablePurpose
NEXT_PUBLIC_META_APP_IDMeta app ID (used by FB JS SDK + server token exchange)
NEXT_PUBLIC_META_EMBEDDED_SIGNUP_CONFIG_IDLogin for Business configuration ID
META_OAUTH_REDIRECT_URIMust match Valid OAuth Redirect URIs (e.g. onboarding page URL)
WHATSAPP_APP_SECRETWebhook signature + server calls
WHATSAPP_VERIFY_TOKENWebhook GET verification
WHATSAPP_TOKEN_ENCRYPTION_KEY32-byte key (base64) for encrypting per-org tokens at rest (required)

See .env.local.example.

7. Policies and UX

  • Publish a Privacy Policy and Terms URL in the Meta app settings when required.
  • In-product: show connection status, reconnect, and disconnect; do not expose access tokens in the UI or client bundles.

References