> For the complete documentation index, see [llms.txt](https://docs.360dialog.com/partner/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.360dialog.com/partner/onboarding/partner-hosted-embedded-signup.md).

# Partner-Hosted Embedded Signup

This page describes how partners can host Embedded Signup

For advanced personalization, approved Meta Tech Providers can host a custom Embedded Signup flow.

## Requirements

#### Tech Provider registration and approved Solution

Enabling this option requires status as a Meta-approved Tech Provider with a live solution integrated with 360dialog. The solution must be in Meta's `ACTIVE` status. [More details](https://docs.360dialog.com/partner/get-started/tech-provider-program#multi-partner-solution).

#### Technical Capacity

Hosting and managing an independent Embedded Signup script requires technical implementation knowledge. Technical support from 360dialog is not available for troubleshooting custom Embedded Signup scripts.

#### Request Advanced Access for public\_profile permission

An additional permission is required for the onboarding process to function correctly. In the Meta for Developers App dashboard > navigate to your **App Review** > **Permissions** > Find the ‘`public_profile`’ permission and request `advanced access`.

<figure><img src="https://2248475362-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FuyAl2S0lSHJaNDXJHo7A%2Fuploads%2FtdpPWJQL5QrIRZo5PLor%2Fpublic_profile.png?alt=media&#x26;token=2404d889-7720-4e42-8b18-a5b01939694d" alt=""><figcaption></figcaption></figure>

Ensure advanced access is granted before configuring the ES.

<figure><img src="https://2248475362-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FuyAl2S0lSHJaNDXJHo7A%2Fuploads%2Fg5uxVcJRIISHDU1Tk9Ns%2Fpublic_profile1.png?alt=media&#x26;token=e800ebbc-5b50-477c-b664-66dc4265a69a" alt=""><figcaption></figcaption></figure>

#### Set Partner Hub Webhook URL and listen to Webhook Events

[See instructions here](https://docs.360dialog.com/partner/partner-api/overview#partner-hub-webhook).

## Build Self-Hosted Embedded Signup

{% hint style="danger" %}
**Important:** The Meta documentation linked below includes steps for **registering a phone number**.

**Do not follow those steps.** Phone number registration is handled entirely by 360Dialog.
{% endhint %}

1. [Implement Embedded Signup](https://developers.facebook.com/documentation/business-messaging/whatsapp/solution-providers/multi-partner-solutions#step-5-configure-embedded-signup).
2. [Check the signup flow for Cloud API](https://developers.facebook.com/docs/whatsapp/embedded-signup/default-flow).\
   Note that if you have information about your customer's business, you can [inject this data](https://developers.facebook.com/docs/whatsapp/embedded-signup/pre-filled-data), which can significantly reduce the number of screens that your customers have to interact with.\
   \
   We recommend using Embedded Signup version 4. In this case you can enable the [Marketing Messages API (MM API)](https://docs.360dialog.com/partner/messaging/marketing-messages) for the client *during* the onboarding process. This allows your clients to skip an additional step of enabling the MM API after they are onboarded. Here is how to enable [Embedded Signup version 4](https://developers.facebook.com/docs/whatsapp/embedded-signup/versions/version-4).

## Embedded Signup versions

{% hint style="warning" %}
**Embedded Signup v2 and v3 are retired on 15 October 2026**, including the `v2-public-preview` and `v3-public-preview` variants. Meta moves most integrations to v4 automatically. Three feature types are not moved and need a manual change: see below.
{% endhint %}

### What happens on 15 October 2026

* **Standard flows upgrade on their own.** If your configuration does not use one of the feature types below, your flow keeps working and starts behaving like v4. Nothing to deploy.
* **Three feature types are not upgraded automatically:** `only_waba_sharing`, `marketing_messages_lite` and `coex`. On v2 and v3 they stop working on that date and the flow falls back to the standard Embedded Signup (a regular new-number signup) until you move to v4. Clients would then not get the WABA-sharing, MM API or Coexistence experience you configured.
* **The phone-number-first screen order** that v4 introduced is being applied by Meta to v2, v3 and v4. Clients see the number step first, which is what makes [pre-verified phone numbers](https://docs.360dialog.com/partner/resources/pre-verified-phone-numbers) effective. No action on your side.

### Move to v4

1. In the Meta App Dashboard, create a new **Facebook Login for Business** configuration with Embedded Signup and the products you need: WhatsApp Cloud API, Marketing Messages API, Ads that click to WhatsApp, Conversions API.
2. Launch the flow with that configuration ID. In v4 the version is **not** a parameter any more: remove `version` and `sessionInfoVersion` from the `extras` object.
3. For Coexistence, use the `whatsapp_business_app_onboarding` feature type, which v4 supports. For WABA sharing and MM API, select the products in the login configuration instead of the retired feature types.
4. Test the full flow with a non-production number, including the redirect to 360dialog and the webhook events, before 15 October.

### Version comparison

|                                                                      | v2                         | v3                  | v4                                                          |
| -------------------------------------------------------------------- | -------------------------- | ------------------- | ----------------------------------------------------------- |
| Status                                                               | Retired 15 Oct 2026        | Retired 15 Oct 2026 | Current                                                     |
| Version selection                                                    | `extras.version`           | `extras.version`    | Login for Business configuration, `extras` left empty       |
| Finish without a verified number                                     | No                         | Yes                 | Yes                                                         |
| Products enabled at signup (MM API, CTWA, Conversions API)           | No                         | No                  | Yes                                                         |
| `only_waba_sharing`, `marketing_messages_lite`, `coex` feature types | Supported                  | Partly              | Replaced by products and `whatsapp_business_app_onboarding` |
| Session info callback                                                | Needs `sessionInfoVersion` | Always              | Always                                                      |

Full details on Meta's [Embedded Signup versions](https://developers.facebook.com/documentation/business-messaging/whatsapp/embedded-signup/versions/) page.

### New WhatsApp account model

Meta's [new WhatsApp account model](/partner/onboarding/new-whatsapp-account-model.md) is live for all accounts since mid-October 2026. The phone number lives in a WhatsApp account (WAAC), and each provider has its own Messaging account (formerly WhatsApp Business Account, WABA) for templates, billing and webhooks. An existing WABA became the Messaging account, with the same ID. \
\
What it means for the flow:

* All Embedded Signup versions return the **Messaging account ID in the WABA ID field**. Pass it to the Partner API as `waba_external_id`, as before. Embedded Signup v5 also returns the Messaging account IDs in a `messaging_account_ids` field. Make sure to submit the Messaging account ID, not the WhatsApp account ID.
* A business can add 360dialog to a phone number that is already in use with another provider or a direct integration: it selects the existing number, the Business Portfolio and WhatsApp account fields are greyed out (pre-selected by Meta) and a new Messaging account is created for the solution. The previous provider is not removed. No 2FA change, number deletion or re-onboarding is needed.
* **After such an onboarding the business must set conversation routing to 360dialog in Meta Business Suite.** Otherwise the channel is Ready but no incoming messages or webhooks reach 360dialog and free-form replies fail with error 131070. Build this into post-onboarding instructions. See [Migrate a number to 360Dialog](/partner/partner-hub/migrating-phone-numbers/migrating-existing-waba.md#after-onboarding-do-this-before-go-live).
* Templates are not carried over to the new Messaging account. 360dialog Support can duplicate them from the source Messaging account on request.

## Connect Self-Hosted Embedded Signup to 360dialog

### Step 1: Create or retrieve a Client Account

In order to later submit the number, either retrieve an existing `client_id` or create a new client instance through our Partner API using the endpoint below. Make sure to store the Client ID of each client within database, since it will be required afterwards. Alternatively, it can also be retrieved with [this endpoint](https://docs.360dialog.com/partner/partner-api/api-reference/client-management#get-api-v2-partners-partner_id-clients).

#### Create client account

This [endpoint](https://docs.360dialog.com/partner/partner-api/api-reference/account-sharing#post-api-v2-partners-partner_id-account_sharing-clients) must be used to create the client account.

### **Step 2: Surface Embedded Signup to client and fetch information**

{% hint style="danger" %}
**Important:** The Meta documentation linked below includes steps for **registering a phone number**.

**Do not follow those steps.** Phone number registration is handled entirely by 360Dialog.
{% endhint %}

Embedded Signup is a Meta-hosted popup that you launch from your own website or portal with the Facebook JavaScript SDK. In the popup, the client logs in with their Meta credentials, accepts the WhatsApp terms, selects or creates a business portfolio and WhatsApp account, adds and verifies a phone number and sets a display name.

When the client finishes, Meta returns two things to your page:

* a **session info event** with the IDs of the client's assets (WABA ID, phone number ID, business portfolio ID)
* an **exchangeable token code** that you can swap for the client's business token

Complete the steps below to launch the flow, capture this data and confirm the shared WABA ID. You submit the IDs to 360dialog in Step 3.

{% hint style="info" %}
**Note:** All requests to the Meta Graph API in this step must be made server-to-server. Never expose your App Secret or System User access token in client-side code.
{% endhint %}

**2.1 Configure your Meta app**

1. In the [App Dashboard](https://developers.facebook.com/apps), open your app and go to **Facebook Login for Business** > **Settings** > **Client OAuth settings**.
2. Set these toggles to **Yes**: Client OAuth login, Web OAuth login, Enforce HTTPS, Embedded Browser OAuth Login, Use Strict Mode for redirect URIs, and Login with the JavaScript SDK.
3. Add every domain that will host the flow, including development and test domains, to **Allowed domains** and **Valid OAuth redirect URIs**. Only HTTPS domains are supported.

{% hint style="info" %}
**Important:** Meta only returns the session info and token code to pages on domains listed in these two fields. If the domain is missing, the flow completes but your page receives no data.
{% endhint %}

Reference: [Meta: Add allowed domains](https://developers.facebook.com/documentation/business-messaging/whatsapp/embedded-signup/implementation#step-1-add-allowed-domains)

**2.2 Create a Facebook Login for Business configuration**

The configuration defines which permissions and assets the flow requests from the client.

1. Go to **Facebook Login for Business** > **Configurations**.
2. Click **Create from template** and select **WhatsApp Embedded Signup Configuration With 60 Expiration Token**. To build a custom configuration instead, click **Create configuration** and select the **WhatsApp Embedded Signup** login variation.
3. Select the products to onboard, for example **WhatsApp Cloud API** and **Marketing Messages API for WhatsApp**.
4. Select only the assets and permissions you need. Extra assets, such as Catalogs, add screens to the flow and increase drop-off.
5. Save the configuration and copy the **configuration ID**.

Reference: [Meta: Create a Facebook Login for Business configuration](https://developers.facebook.com/documentation/business-messaging/whatsapp/embedded-signup/implementation#step-2-create-a-facebook-login-for-business-configuration)

**2.3 Add Embedded Signup to your website**

Add the code below to the page where clients start the onboarding. Replace the placeholders:

| Placeholder           | Description                                              |
| --------------------- | -------------------------------------------------------- |
| `<APP_ID>`            | Your Meta App ID, shown at the top of the App Dashboard. |
| `<GRAPH_API_VERSION>` | The latest Graph API version, for example `v25.0`.       |
| `<CONFIGURATION_ID>`  | The configuration ID from 2.2.                           |

```html
<!-- Load the Facebook JavaScript SDK -->
<script async defer crossorigin="anonymous" src="https://connect.facebook.net/en_US/sdk.js"></script>

<script>
  // Initialize the SDK
  window.fbAsyncInit = function () {
    FB.init({
      appId: '<APP_ID>',
      autoLogAppEvents: true,
      xfbml: true,
      version: '<GRAPH_API_VERSION>'
    });
  };

  // Listen for the session info event (asset IDs, cancel, errors)
  window.addEventListener('message', (event) => {
    if (!event.origin.endsWith('facebook.com')) return;
    try {
      const data = JSON.parse(event.data);
      if (data.type === 'WA_EMBEDDED_SIGNUP') {
        // Send `data` to your server
      }
    } catch {
      // Not a JSON message, ignore or log
    }
  });

  // Receive the exchangeable token code
  const fbLoginCallback = (response) => {
    if (response.authResponse) {
      const code = response.authResponse.code;
      // Send `code` to your server immediately (30-second TTL)
    } else {
      // The flow was closed without completion
    }
  };

  // Launch the flow
  const launchWhatsAppSignup = () => {
    FB.login(fbLoginCallback, {
      config_id: '<CONFIGURATION_ID>',
      response_type: 'code',
      override_default_response_type: true,
      extras: { setup: {} } // v4: do not set version or sessionInfoVersion
    });
  };
</script>

<button onclick="launchWhatsAppSignup()">Connect WhatsApp</button>
```

To shorten the flow, pass business data you already know about the client in `extras.setup`. See [Meta: Pre-filled data](https://developers.facebook.com/documentation/business-messaging/whatsapp/embedded-signup/pre-filled-data).

Reference: [Meta: Add Embedded Signup to your website](https://developers.facebook.com/documentation/business-messaging/whatsapp/embedded-signup/implementation#step-3-add-embedded-signup-to-your-website)

**2.4 Capture the session info**

When the flow ends, Meta sends a `message` event of type `WA_EMBEDDED_SIGNUP` to your page. Send the payload to your server and store it with the `client_id` from Step 1.

The `event` field tells you how the flow ended:

| `event`                                   | Meaning                                                                            |
| ----------------------------------------- | ---------------------------------------------------------------------------------- |
| `FINISH`                                  | The client completed the flow with a phone number.                                 |
| `FINISH_ONLY_WABA`                        | The client completed the flow without adding a phone number.                       |
| `FINISH_WHATSAPP_BUSINESS_APP_ONBOARDING` | The client onboarded a number in use with the WhatsApp Business App (Coexistence). |
| `CANCEL`                                  | The client left the flow early, or reported an error.                              |

Closing the popup on the final screen counts as a successful completion, not as `CANCEL`.

**Completed flow**

```json
{
  "type": "WA_EMBEDDED_SIGNUP",
  "event": "FINISH",
  "data": {
    "phone_number_id": "106540352242922",
    "waba_id": "524126980791429",
    "business_id": "2729063490586005"
  }
}
```

| Field             | Use in Step 3         |
| ----------------- | --------------------- |
| `waba_id`         | `waba_external_id`    |
| `phone_number_id` | `channel_external_id` |
| `business_id`     | Store for reference   |

The payload can also contain `ad_account_ids`, `page_ids`, `dataset_ids`, `catalog_ids` or `instagram_account_ids` if the client selected those assets, and `waba_ids` for multi-WABA flows.

**Abandoned flow**

```json
{
  "type": "WA_EMBEDDED_SIGNUP",
  "event": "CANCEL",
  "data": {
    "current_step": "PHONE_NUMBER_SETUP"
  }
}
```

`current_step` shows the screen where the client left the flow. Use it to follow up with the client. See [Meta: Abandoned flow screens](https://developers.facebook.com/documentation/business-messaging/whatsapp/embedded-signup/errors).

**Error reported by the client**

```json
{
  "type": "WA_EMBEDDED_SIGNUP",
  "event": "CANCEL",
  "data": {
    "error_message": "Your verified name violates WhatsApp guidelines. Please edit your verified name and try again.",
    "error_code": "524126",
    "session_id": "f34b51dab5e0498",
    "timestamp": "1746041036"
  }
}
```

Include `error_code`, `session_id` and `timestamp` when you contact support about a failed signup.

{% hint style="info" %}
**Important:** With Meta's new WhatsApp account model, `waba_id` is the **Messaging account ID**. Submit this value, not the WhatsApp account (WAAC) ID.
{% endhint %}

Reference: [Meta: Session logging message event listener](https://developers.facebook.com/documentation/business-messaging/whatsapp/embedded-signup/implementation#session-logging-message-event-listener)

**2.5 Exchange the token code for a business token**

The `FB.login` callback returns an exchangeable code in `response.authResponse.code`. The code expires after **30 seconds**, so send it to your server and exchange it right away.

Request:

```bash
curl --get 'https://graph.facebook.com/<GRAPH_API_VERSION>/oauth/access_token' \
  -d 'client_id=<APP_ID>' \
  -d 'client_secret=<APP_SECRET>' \
  -d 'code=<CODE>'
```

| Placeholder    | Description                                                             |
| -------------- | ----------------------------------------------------------------------- |
| `<APP_ID>`     | Your Meta App ID.                                                       |
| `<APP_SECRET>` | Your App Secret, from **App Dashboard** > **App settings** > **Basic**. |
| `<CODE>`       | The code from the `FB.login` callback.                                  |

Response:

```json
{
  "access_token": "<BUSINESS_TOKEN>"
}
```

The response contains the client's **business token**. Store it securely. You need it in 2.6 and for any Graph API calls you make for this client.

Reference: [Meta: Response callback](https://developers.facebook.com/documentation/business-messaging/whatsapp/embedded-signup/implementation#response-callback), [Meta: Exchange the token code for a business token](https://developers.facebook.com/documentation/business-messaging/whatsapp/embedded-signup/onboarding-customers-as-a-tech-provider)

**2.6 Confirm the shared WABA ID**

Use the business token to confirm which WABA the client shared with your app. This is a reliable check if the session info event was not received, for example because the client's browser blocked it.

Call the Debug Token endpoint. Pass the business token as `input_token` and authenticate with your **System User access token**.

Request:

```bash
curl 'https://graph.facebook.com/<GRAPH_API_VERSION>/debug_token?input_token=<BUSINESS_TOKEN>' \
  -H 'Authorization: Bearer <SYSTEM_USER_ACCESS_TOKEN>'
```

Response (shortened):

```json
{
  "data": {
    "app_id": "670843887433847",
    "granular_scopes": [
      {
        "scope": "whatsapp_business_management",
        "target_ids": [
          "102289599326934",
          "101569239400667"
        ]
      },
      {
        "scope": "whatsapp_business_messaging",
        "target_ids": [
          "102289599326934",
          "101569239400667"
        ]
      }
    ],
    "is_valid": true,
    "type": "USER"
  }
}
```

In `granular_scopes`, find the `whatsapp_business_management` scope. The **first ID** in its `target_ids` array is the most recently shared WABA. Use it as `waba_external_id` in Step 3.

{% hint style="info" %}
**Note:** If the call returns error code `200`, your app does not have Advanced access for `whatsapp_business_management`. Request it in **App Review** > **Permissions**.
{% endhint %}

As a fallback, list all WABAs shared with your business portfolio:

```bash
curl 'https://graph.facebook.com/<GRAPH_API_VERSION>/<YOUR_BUSINESS_PORTFOLIO_ID>/client_whatsapp_business_accounts' \
  -H 'Authorization: Bearer <SYSTEM_USER_ACCESS_TOKEN>'
```

To get the phone number IDs in the WABA, call:

```bash
curl 'https://graph.facebook.com/<GRAPH_API_VERSION>/<WABA_ID>/phone_numbers' \
  -H 'Authorization: Bearer <BUSINESS_TOKEN>'
```

Reference: [Meta: Get shared WABA ID with access token](https://developers.facebook.com/documentation/business-messaging/whatsapp/solution-providers/manage-accounts#get-shared-waba-id-with-access-token), [Meta: Get list of shared WABAs](https://developers.facebook.com/documentation/business-messaging/whatsapp/solution-providers/manage-accounts#get-list-of-shared-wabas)

**2.7 Steps handled by 360dialog**

Meta's onboarding guide lists further API calls after the token exchange. 360dialog completes these when you submit the number in Step 3:

* **Phone number registration.** We recommend leaving registration to 360dialog. If you have already registered the number, 360dialog can still complete the onboarding.
* **Webhook subscription** on the client's WABA.
* **Credit line sharing** with the client.

{% hint style="info" %}
**Testing:** Claim a sandbox account in the App Dashboard under **WhatsApp** > **Quickstart** > **Testing Integrations** to run the flow without creating real business assets. The sandbox phone number cannot send or receive messages.
{% endhint %}

You now have the `waba_id` and `phone_number_id`. Continue with Step 3 to connect them to the client account.

### Step 3: Connect Client account to the registered Phone Number

Use the endpoint below to submit the phone number/channel to 360Dialog records. If the number was successfully onboarded via self-hosted Embedded Signup and the attached `client_id` matches the user data in 360dialog records, the onboarding flow ends by redirecting the Client to the Partner Redirect URL set.

#### Submit channel/number created via self-hosted Embedded Signup

Please use this [endpoint](https://docs.360dialog.com/partner/partner-api/api-reference/account-sharing#post-api-v2-partners-partner_id-account_sharing-numbers).

{% hint style="info" %}
`channel_external_id` should be filled in with the phone number ID. Once it is filled in, we connect the particular number. If the value is sent as `null` we will connect all numbers associated with the particular waba `waba_external_id`
{% endhint %}

### Step 4: Create API key to start messaging

When the number is fully live, the [Channel Live Webhook Event](https://docs.360dialog.com/partner/onboarding/webhook-events-and-setup/webhook-events-partner-and-messaging-api) will be sent.&#x20;

You should be able to generate an API Key and connect it to your integration to start messaging with this phone number by default.

See [Partner Permissions](https://docs.360dialog.com/partner/partner-hub/api-keys) for details.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.360dialog.com/partner/onboarding/partner-hosted-embedded-signup.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
