v4 Configuration Requirements
Dualhook uses a custom Facebook Login for Business v4 configuration with the WhatsApp Embedded Signup variation. The configuration must be created and reviewed in Meta's Embedded Signup Builder with:
- the Cloud API product selected in the v4 configuration
- WhatsApp Business Accounts and WhatsApp phone numbers as the only selected assets
- a Business Integration System User business token with never-expiring access
- only
whatsapp_business_managementandwhatsapp_business_messaging - Advanced Access for
public_profile,whatsapp_business_management, andwhatsapp_business_messaging - no
business_management, ad account, Page, Instagram, dataset, catalog, or Marketing Messages Lite selection account_updatesubscribed on Dualhook's app-level WhatsApp webhook configuration- Client OAuth Login, Web OAuth Login, Enforce HTTPS, Embedded Browser OAuth Login, Strict Mode for redirect URIs, and Login with the JavaScript SDK enabled
- only approved HTTPS hostnames in Allowed Domains and exact HTTPS callback locations in Valid OAuth Redirect URIs
NEXT_PUBLIC_META_CONFIG_ID must remain on the current accepted configuration until the replacement configuration passes both a sandbox Cloud API onboarding and a sandbox Coexistence onboarding. For Coexistence, confirm that the ordinary WABA selection screen is replaced by the screen offering connection of an existing WhatsApp Business app account. Also test the chat-history opt-in branch before switching production.
How Dualhook Uses Embedded Signup
Dualhook uses Meta's OAuth popup flow to create connections and obtain a short-lived exchangeable authorization code. The code is sent to Dualhook's server immediately and is never written to browser logs.
The client-side flow calls FB.login(...) with:
config_id— your Login for Business configurationresponse_type: "code"— returns an authorization code instead of a tokenoverride_default_response_type: trueextras: { setup: {}, featureType: "whatsapp_business_app_onboarding" }— v4 uses the Builder configuration for product assets and permissions, while Meta still requires this launch selector to offer WhatsApp Business app user onboarding
Dualhook does not send the legacy sessionInfoVersion or generic feature: "whatsapp_embedded_signup" launch overrides. The Coexistence completion event itself still reports session payload version: 3 and uses FINISH_WHATSAPP_BUSINESS_APP_ONBOARDING.
Dualhook listens for the popup's postMessage session info and captures:
waba_id— the WhatsApp Business Account IDphone_number_id— the specific phone number ID when Meta includes it; the Coexistence completion payload can omit it, so Dualhook uses server-side discovery
Server-Side Completion
After receiving the authorization code, Dualhook:
- Exchanges the code for a customer-scoped Business Integration System User access token using Dualhook's app credentials. No app-secret proof applies to this exchange because an access token does not exist yet. The returned token is stored encrypted on the server and is never returned to the customer (see WhatsApp Business API Permissions).
- Calls
debug_tokento capture the system user ID and the granular OAuth scopes attached to the token (which WABAtarget_idsit haswhatsapp_business_managementandwhatsapp_business_messagingaccess to). This request is proof-aware using the authorizing app access token, not the customer token being inspected. - Stores token lifecycle metadata (
tokenIssuedAt,tokenExpiresAt) so Dualhook can warn before expiry. Existing expiring BISU tokens require customer reauthorization; Dualhook does not apply the ordinary System User refresh flow to BISU tokens. - Creates a connection draft or full connection.
- Subscribes Dualhook's app to the WABA and configures Webhook Override (best effort).
All subsequent native Graph reads and mutations use Dualhook's server-only
proof transport. The browser SDK, customer, and webhook receiver never receive
or construct appsecret_proof.
After setup, customers can use the selected connection's dh_live_... key for
the allowlisted Graph-compatible Runtime API.
The runtime always derives phone and WABA scope from this stored Embedded
Signup selection. A caller cannot replace those IDs, submit a different Meta
token, or change webhook subscriptions/callbacks through the runtime.
Fallback Discovery
If the popup session info is incomplete (for example, the postMessage did not arrive), Dualhook falls back to Graph API discovery using the debug_token granular scopes captured above:
- For each WABA
target_idreturned bydebug_token, fetch WABA name andowner_business_info. - If granular scopes are empty, fall back to
/me/businessesand enumerate owned WABAs. - Enumerate phone numbers under each candidate WABA.
If multiple WABAs or numbers are discovered, Dualhook presents the options and finalizes setup with your selection.
Common Failure Modes
- Meta finished but no Dualhook connection appears — follow Connection Not Appearing After Embedded Signup for the clean-browser retry and recovery-banner behavior.
- Popup blocked by browser — allow popups for Dualhook and retry.
- User cancels before code return — restart the connection flow.
- Token exchange failure — verify your app credentials and
redirect_uri. - No discoverable WABA/phone under granted access — confirm the correct Meta Business Portfolio was selected during the popup.
If Meta displays a numbered or textual error inside the popup, search the Embedded Signup Errors index before deleting or recreating any asset.