> For the complete documentation index, see [llms.txt](https://docs.appmixer.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.appmixer.com/connector-configuration/whatsapp.md).

# WhatsApp

## WhatsApp

The Appmixer WhatsApp connector talks to the **WhatsApp Business Cloud API** hosted by Meta. This page has two distinct parts:

| Part                                   | Audience                        | What it covers                                                                                                                                              |
| -------------------------------------- | ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Part 1 — Configuring the connector** | Appmixer **administrator**      | One-time tenant setup: Meta App, WhatsApp product, Facebook Login for Business, WhatsApp Embedded Signup, Appmixer Backoffice, webhook endpoint, App Review |
| **Part 2 — Using the connector**       | **End customer** / flow builder | What every customer must bring (WABA, phone, registration), how to connect their account, how Sender vs Recipient works, the 24-hour window, going Live     |

If you're setting WhatsApp up on a fresh Appmixer tenant for the first time — start with **Part 1**. If you're a customer building flows on an Appmixer where WhatsApp is already configured — skip to **Part 2**.

***

## Part 1 — Configuring the WhatsApp connector

A one-time setup performed by an Appmixer **administrator**. End customers don't see any of these steps; once the Meta App is wired up they simply click "Connect WhatsApp" in the Designer.

### 1.0 Admin prerequisites

* A **Meta Business Account** at [business.facebook.com](https://business.facebook.com). A personal Facebook account can create one for free.
* **Admin / Backoffice access** to your Appmixer tenant.
* (Recommended for testing) a phone number you can use as a WhatsApp sender. Meta provides a free **test phone number** during App development.

### 1.1 Create the Meta App

1. Open <https://developers.facebook.com/> and choose **My Apps → Create app**.
2. **Use case:** select **Other**, then on the next screen choose **Business** as the app type.
3. Give the app a descriptive name (e.g. `Appmixer – WhatsApp`) and link it to your Business Account.

### 1.2 Add the WhatsApp product

1. In the new app dashboard, scroll to **Add products to your app**.
2. Click **Set up** on the **WhatsApp** card. This attaches a WhatsApp Business Account (WABA) to the app — Meta offers to create a brand-new test WABA if you don't already own one.
3. After setup, you'll land on the **API Setup** page. Note the following — you'll need them for testing:
   * **Phone number ID** (the long numeric ID Appmixer's `phoneNumberId` input expects)
   * **WhatsApp Business Account ID** (WABA ID — used by the `ListPhoneNumbers` component, templates, etc.)
   * **Temporary access token** (24h lifetime; fine for smoke tests, not for production)
   * The pre-supplied **test phone number** Meta gives you

### 1.3 Add Facebook Login for Business

The end-user OAuth flow goes through **Facebook Login for Business**.

1. In the app sidebar choose **Add products → Facebook Login for Business → Set up**.
2. Under **Facebook Login for Business → Settings**, set the **Valid OAuth Redirect URIs** to your tenant's WhatsApp callback URL:

   ```
   https://api.YOUR_TENANT.appmixer.cloud/auth/whatsapp/callback
   ```

   Replace `YOUR_TENANT` with the subdomain of your Appmixer tenant. Self-Managed customers can use any domain configured for the Appmixer API; append `/auth/whatsapp/callback`.
3. Under **App settings → Basic → App Domains**, add your tenant domain(s) — at minimum the API host above. Without this Meta will reject the redirect at runtime.

### 1.3.1 Choose the OAuth flow: Embedded Signup vs plain OAuth

The connector supports two OAuth flows:

| Flow                                       | Backoffice config                        | End-customer UX                                                                                                                            | WABA auto-discovery                                                                                                                     |
| ------------------------------------------ | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |
| **WhatsApp Embedded Signup** (recommended) | `clientId`, `clientSecret`, `esConfigId` | Meta's guided signup wizard — the customer selects (or even creates from scratch) a WABA and phone number during login. Same UX as Zapier. | ✅ Automatic — the `WhatsApp Business Account ID` dropdowns in components are pre-populated.                                             |
| **Plain OAuth** (fallback)                 | `clientId`, `clientSecret` only          | Standard Meta consent screen incl. the WABA asset picker (Meta shows it automatically for the whatsapp scopes).                            | ❌ Not possible — Meta does not expose the picked WABA to the token in this flow. Customers type their WABA ID into components manually. |

If `esConfigId` is not set in Backoffice, the connector automatically uses plain OAuth. Plain OAuth is fully functional — the only difference is the manual WABA ID entry.

#### Setting up WhatsApp Embedded Signup

**Prerequisites on the Meta side** (without these the signup wizard blocks with *"… can't onboard customers right now"*):

* **Verified business** — the business portfolio that owns the Meta App must pass **Business Verification** (Meta Business Manager → Security Centre).
* **Advanced Access** for `whatsapp_business_messaging` and `whatsapp_business_management` (App Review, section 1.7).

Setup steps:

1. Meta App → **Facebook Login for Business → Configurations → Create from template** → pick **"WhatsApp Embedded Signup Configuration"** (the *With 60 Expiration Token* variant is fine). Don't use the manual *Create configuration* wizard — the WhatsApp Embedded Signup login variation is only offered through the template.
2. Copy the resulting **Configuration ID** → Backoffice `esConfigId` (section 1.4).
3. In **Facebook Login for Business → Settings**:
   * **Login with the JavaScript SDK** → **Yes**
   * **Allowed Domains for the JavaScript SDK** → add your Appmixer API domain (e.g. `api.YOUR_TENANT.appmixer.cloud`). The signup page is served by the connector plugin at `…/plugins/appmixer/whatsapp/signup` on this domain.
4. Reconnect a test account: the login now opens an Appmixer-served page with a **Continue with Facebook** button that launches Meta's signup wizard.

> **Note:** the template issues system-user tokens with a 60-day expiration. The connector refreshes tokens automatically; if a customer's account nevertheless stops authenticating after \~60 days, ask them to reconnect.

### 1.4 Configure Appmixer Backoffice

1. From the app dashboard, copy the **App ID** and **App Secret** (under **App settings → Basic**).
2. Open your Appmixer **Backoffice → Connector Configuration**.
3. Create (or edit) the entry with configuration ID **`appmixer:whatsapp`** and add:
   * `clientId` = Meta **App ID**
   * `clientSecret` = Meta **App Secret** — used both for the OAuth token exchange **and** for HMAC verification of incoming webhooks (`X-Hub-Signature-256`)
   * `esConfigId` = **WhatsApp Embedded Signup Configuration ID** from section 1.3.1. (Optional — without it the connector uses plain OAuth and customers enter their WABA ID manually.)
   * `verifyToken` = any string you choose. You'll enter the same value into Meta App Dashboard when configuring webhook callback URL (section 1.6). Treat it as a shared secret.
4. Save.

End customers on your tenant can now click **Connect WhatsApp** in the Designer.

> **Auto-discovery of WABA ID (Embedded Signup only):** Tokens issued through Embedded Signup carry the selected WABA in `granular_scopes[].target_ids`; the connector reads them via Meta's `/debug_token` endpoint during OAuth and stores them on the account profile (`profileInfo.wabaIds`, `profileInfo.businessAccountId`). The `WhatsApp Business Account ID` dropdowns in components are populated from this list. With plain OAuth the token does not carry the selection — the dropdowns stay empty and customers type the WABA ID in (the field is a text input with a dropdown attached, so manual entry always works).
>
> In **both** flows the connector verifies during OAuth that the issued token actually carries the whatsapp scopes — Meta drops scopes silently in several scenarios (stale grants, standard access without an app role). A token without them would be useless, so authentication fails fast with a descriptive error instead.

### 1.5 Required permissions (scopes)

The connector requests these scopes during OAuth:

| Scope                          | Why                                                         |
| ------------------------------ | ----------------------------------------------------------- |
| `whatsapp_business_messaging`  | Send/receive messages, mark as read, upload media           |
| `whatsapp_business_management` | Manage the WABA, phone numbers, templates, business profile |

Both are part of Meta's standard WhatsApp product and do **not** require Advanced Access for development testing. They **do** require **App Review** before going Live for users outside your test list (see section 1.7).

### 1.6 Webhook setup for triggers (one-time admin step)

The Appmixer WhatsApp `NewMessage` and `MessageStatusUpdated` triggers receive events from Meta over HTTPS webhooks. Meta allows **one webhook callback URL per Meta App**, so Appmixer uses a connector-level **plugin endpoint** that all customers' WABAs share. The admin configures this once per tenant; per-customer WABA subscription happens automatically when a trigger flow starts.

#### One-time admin steps

1. **Get the plugin endpoint URL** for your tenant:

   ```
   https://api.YOUR_TENANT.appmixer.cloud/plugins/appmixer/whatsapp/events
   ```

   (Self-Managed customers: substitute your Appmixer API base URL for `https://api.YOUR_TENANT.appmixer.cloud`.)
2. In the Meta App Dashboard go to **WhatsApp → Configuration → Webhooks**.
3. Click **Edit** on **Callback URL**:
   * **Callback URL** = the plugin endpoint URL from step 1
   * **Verify token** = the `verifyToken` value you set in Backoffice → `appmixer:whatsapp` (section 1.4)
4. Click **Verify and save**. Meta sends a `GET` to the endpoint with `hub.mode=subscribe&hub.challenge=…&hub.verify_token=…`. The plugin echoes back `hub.challenge` when the verify token matches.
5. On the same page, find the **`messages` field** in the webhook fields table and click **Subscribe**. This single field covers:
   * **Inbound messages** (`value.messages[]`) — used by `NewMessage` trigger
   * **Outbound status updates** (`value.statuses[]`) — used by `MessageStatusUpdated` trigger
   * Reactions, button clicks, system messages, etc.

That's the entire admin setup. From here, every customer whose flow includes a WhatsApp trigger gets webhook events automatically (Part 2, section 2.5).

#### How the routing works

```
External user sends WhatsApp message
            │
            ▼
Meta servers detect message → fires `messages` field webhook
            │
            ▼
HTTP POST to <plugin endpoint>/events                ← one URL for all tenants' customers
            │
            ▼
Plugin verifies HMAC (X-Hub-Signature-256 vs clientSecret)
Plugin parses entry[].id (= WABA ID), value.messages[] or value.statuses[]
            │
            ▼
context.triggerListeners({ eventName: 'messages:{wabaId}', payload, … })
            │
            ▼
Only listeners subscribed to this specific WABA fire   ← customer isolation
            │
            ▼
Trigger component's receive() fires → flow continues
```

This means:

* ✅ One Meta App serves unlimited customers on the same Appmixer tenant
* ✅ Customer A's messages never leak to customer B's flows (eventName includes wabaId)
* ✅ HMAC signature verification is centralized (uses the Meta App Secret stored in `appmixer:whatsapp.clientSecret`)
* ❌ But: still only **one Meta App per Appmixer tenant**. Multiple tenants need a Meta App each.

### 1.7 App Review for production

Until your Meta App is reviewed and switched to **Live** mode, only verified test recipients and limited features are available. To onboard real customers you must submit for App Review:

1. **App settings → Basic** — fill in app icon, category, privacy policy URL, terms of service URL.
2. **App Review → Permissions and Features** — request advanced access for `whatsapp_business_messaging` and `whatsapp_business_management`.
3. **Business Verification** — verify your business entity in Meta Business Manager. Requires a business document (commercial register entry, articles of incorporation, …) and may take several days.
4. **Tech Provider designation** — required if you plan to onboard other businesses' WABAs via Embedded Signup. Appmixer hosted plans typically already operate under a Tech Provider Meta App; Self-Managed customers will need to apply separately.

***

## Part 2 — Using the WhatsApp connector

This part is for the **end customer / flow builder** on an Appmixer tenant where the WhatsApp connector is already configured (Part 1 complete).

### 2.0 What you need on Meta's side

Before you can use the connector in your flows, you need an active WhatsApp Business presence on Meta. **Appmixer does not provision this for you** — each customer brings their own.

#### Must have

1. **Active Meta Business Account** — at [business.facebook.com](https://business.facebook.com), free. A personal Facebook account can create one.
2. **Active WhatsApp Business Account (WABA)** — created under your Business Account, either:
   * Manually via Meta Business Suite → Settings → Business Settings → Accounts → **WhatsApp Accounts → Add**, OR
   * Automatically when you sign up via a Business Solution Provider (BSP) or template setup.
3. **At least one phone number added to the WABA** — added via WhatsApp Manager, verified by Meta with an SMS / voice OTP code. During verification you also set a **6-digit two-step verification PIN** for the number — **write it down**, you'll need it for Cloud API registration in section 2.2.
4. **Phone number registered for Cloud API** — one-time activation. Easiest via the `Ensure Sender Phone Number Registered` component (section 2.2 below). Required before sending/receiving any message; without it Meta returns `133010 — Account not registered`.
5. **Business Verification** in Meta Business Manager — strictly required only for **going Live** (section 2.6), but recommended even in Development mode for better sender quality rating.

#### Hierarchy of Meta entities

```
Meta Business Account                        ← your company
   │     ID: 1234567890123456
   │
   └── WhatsApp Business Account (WABA)      ← container for WhatsApp business activity
        │     ID: 2430596730775767           ← this is `businessAccountId` in Appmixer
        │
        └── Phone Numbers (1 or more)        ← actual numbers under that WABA
             │
             ├── Phone Number A
             │     E.164: +1 (555) 635-4389
             │     Phone Number ID: 1044539225419737      ← auto-assigned by Meta
             │
             └── Phone Number B (optional)
                   E.164: +420 800 123 456
                   Phone Number ID: 9876543210987654      ← different ID per number
```

**Phone Number ID** is auto-assigned by Meta when you add a phone number into a WABA. It's stable for the lifetime of the number on that WABA — but if you migrate the number to a different WABA, it gets a new Phone Number ID.

#### Where to find your IDs

| What                              | Where in Meta UI                                                                                                                 |
| --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| **WABA ID** (`businessAccountId`) | business.facebook.com → Settings → Business Settings → Accounts → WhatsApp Accounts → click WABA → ID at top                     |
| **Phone Number ID**               | Same path → click the phone number in the **Phone Numbers** tab → ID in the details panel                                        |
| **PIN** (for register)            | Set during phone verification. Reset via Meta Business Manager → WhatsApp Manager → phone number → **Two-step verification PIN** |

With Embedded Signup (section 2.1) you rarely need to look these up — Appmixer auto-discovers the WABA after OAuth. With plain OAuth you'll need the **WABA ID** once: type it into the `WhatsApp Business Account ID` field of the components you use; the phone-number dropdowns then load from it automatically.

### 2.1 Connect your WhatsApp account in Appmixer

How the connection looks depends on which flow your Appmixer admin configured (Part 1, section 1.3.1):

**With Embedded Signup configured:**

1. In the Appmixer Designer, drop any WhatsApp component (e.g. `Send Text Message`) onto a flow.
2. Click **Connect new account** → a page with a **Continue with Facebook** button opens.
3. Meta's signup wizard walks you through logging in, picking your business portfolio and selecting — or creating from scratch — a **WhatsApp Business Account and phone number**.
4. Back in Appmixer, your account is connected. The WABA is auto-discovered and the `WhatsApp Business Account ID` dropdowns in components offer it automatically.

**With plain OAuth:**

1. Same start — **Connect new account** opens a Meta consent screen.
2. **Approve the requested permissions** (`whatsapp_business_messaging`, `whatsapp_business_management`) and select your WABA when the asset picker appears.
3. Back in Appmixer, your account is connected. The WABA ID is **not** auto-discovered in this flow — type it into the `WhatsApp Business Account ID` field of the components you use (where to find it: section 2.0). You only need to look it up once; the phone-number dropdowns then load automatically from it.

> **Already connected before?** Meta caches the previous authorization (a *Business Integration*) and may silently reuse its old — possibly outdated — permissions on reconnect, even though the consent screens look normal. If a reconnect fails with a permissions error: open [facebook.com → Settings & privacy → Settings → **Business integrations**](https://www.facebook.com/settings?tab=business_tools), **remove** the Appmixer integration, then reconnect for a completely fresh grant.

#### When authentication deliberately fails

If the issued token carries no WhatsApp permissions at all, Appmixer **fails the authentication** with a descriptive error instead of connecting a non-functional account (every component call would otherwise fail with a permission error later). Typical causes and fixes:

1. The permissions were declined during login → reconnect and approve them.
2. A stale Business Integration grant was silently reused → remove the integration (see the box above) and reconnect.
3. The Meta App is in Live mode with standard access only and your Facebook account has no role on the app → coordinate with the Appmixer admin (App Review / app roles, Part 1 section 1.7).
4. Your Meta account has no WABA: create one in Meta Business Manager → Settings → Accounts → **WhatsApp Accounts → Add**, add and verify a phone number, then reconnect.

#### Sender vs recipient terminology

Two distinct concepts often confused:

|               | What it is                                               | Where it lives       | Identifier                           |
| ------------- | -------------------------------------------------------- | -------------------- | ------------------------------------ |
| **Sender**    | YOUR business phone number — the number you message FROM | Inside your WABA     | Phone Number ID (`1044539225419737`) |
| **Recipient** | An end user you message TO                               | Anywhere on WhatsApp | E.164 phone number (`+420725657976`) |

Appmixer components named `*PhoneNumber*` (List/Get/Register/Deregister/EnsureRegistered/GetRegistrationStatus) always operate on **YOUR sender numbers**, never on recipients. Recipients need no registration — they're just E.164 phone numbers in the `to` field of Send components.

### 2.2 Register your sender phone number for Cloud API

**One-time step per sender phone number.** Without it the Cloud API returns `133010 — Account not registered`.

Two components:

* **`Ensure Sender Phone Number Registered`** (recommended for onboarding) — idempotent: checks status first, only calls register if not already registered. Returns `wasAlreadyRegistered` so you can branch on first-time setup vs resume.
* **`Register Sender Phone Number`** (explicit) — always calls register. Useful when you want a hard failure on PIN mismatch.

Both take:

* **Phone Number ID** — your sender number's ID. Pick from the dropdown (loaded from your WABA) or paste manually.
* **PIN** — the 6-digit two-step verification PIN you set during phone verification (section 2.0).
  * For Meta test numbers it's typically `000000`.
  * For owned numbers, the one you wrote down. Forgot? Reset via Meta Business Manager → WhatsApp Manager → phone number → Two-step verification PIN.
* **Data Localization Region** — leave empty unless your WABA is in a Meta data-localization program (AU/BR/DE/IN/ID/GB).

Run the component once per phone number. `registered: true` (Ensure) or `success: true` (Register) confirms.

For diagnostics there's also **`Get Sender Registration Status`** — read-only, no side effects. Returns `{ registered, platformType, codeVerified, qualityRating, … }`.

#### Alternative: register via curl

```bash
curl -X POST 'https://graph.facebook.com/v25.0/PHONE_NUMBER_ID/register' \
  -H 'Authorization: Bearer ACCESS_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{ "messaging_product": "whatsapp", "pin": "000000" }'
```

### 2.3 Verified recipients (Development mode only)

While the Appmixer admin's Meta App is in **Development** mode, Meta only delivers to phone numbers explicitly added as test recipients on the App.

If you can't deliver to a phone:

1. Open Meta App Dashboard → WhatsApp → **API Setup**. (Requires Meta App access — coordinate with your Appmixer admin if you don't have it.)
2. In the **To** dropdown, click **Manage phone number list** and add the recipient.
3. WhatsApp will send a verification code via WhatsApp; enter it back in Meta Console.

This restriction goes away once the Meta App is **Live** (App Review approved — Part 1, section 1.7).

### 2.4 Understanding message delivery — the 24-hour customer service window

**This explains 90 % of "my Appmixer flow succeeded but the message never arrived" tickets.** Read it carefully.

**You can send free-form `text` / `image` / `video` / `audio` / `document` / `location` messages only during a 24-hour&#x20;*****customer service window*****, which opens when the end user sends a message to your WhatsApp Business number.** Outside that window, the only message type Meta will actually deliver is a **pre-approved template message**.

What makes this insidious:

* Meta does **not** reject out-of-window free-form sends with an HTTP error. The API returns **HTTP 200 with a valid `messageId`** — your Appmixer flow shows green — but the message is silently dropped on Meta's side.
* The Meta App Dashboard's built-in "Send Message" button uses `hello_world` (a template) by default, so a manual test there appears to work even when your text-based Appmixer flow does not.
* The same applies to Meta-supplied test phone numbers — verified recipients still need to write to the test number first to open the 24-hour window.

#### How to verify delivery in practice

1. **First contact must be a template.** Use `Send Template Message` with `templateName: hello_world`, `languageCode: en_US`.
2. **Add a `Message Status Updated` trigger** to the same flow. Meta sends `status` webhook events through it:

   * `sent` — accepted by Meta's servers
   * `delivered` — reached the recipient's device
   * `read` — recipient opened it
   * `failed` — not delivered; the payload includes a `errors[]` array with the reason code

   If you receive `delivered` but never `read`, the message reached the phone. If you never receive `delivered` within \~30 seconds, the message was dropped — typically because the 24-hour window was closed or the recipient isn't on the verified list.

#### Switching to free-form text

You only get to use `Send Text Message` after the user replies. Two ways:

* **Manual:** open WhatsApp on the recipient device, send any message ("hi") to your test number. The 24-hour window now starts ticking; your `Send Text Message` flow will deliver until 24 hours after that message.
* **Programmatic:** start every conversation with a template, then react to the `New Message` trigger when the user replies — only then send text.

### 2.5 Triggers — how inbound messages reach your flow

When you drop a `New Message` or `Message Status Updated` trigger into a flow and **start the flow**, the trigger automatically:

1. Calls `POST /{wabaId}/subscribed_apps` on Meta — tells Meta to start delivering webhook events for your WABA to the Appmixer plugin endpoint.
2. Registers a listener so the plugin can route incoming events to this specific trigger instance.

No webhook URL or token entry on your side — the Appmixer admin configured the global endpoint once (Part 1, section 1.6).

#### What each trigger sees

| Trigger                  | Fires on                                                                                                        | Payload                                                                                                                 |
| ------------------------ | --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `New Message`            | Inbound from a user to your sender number (text, media, location, reaction, interactive response, system event) | `{ id, from, timestamp, type, text/image/…, phoneNumberId, wabaId }`                                                    |
| `Message Status Updated` | Status change of an outbound message you previously sent                                                        | `{ id, recipientId, status (sent\|delivered\|read\|failed), timestamp, errors[], conversation, phoneNumberId, wabaId }` |

#### The WABA field

Both triggers require a **`WhatsApp Business Account ID`**. With Embedded Signup the field offers a dropdown of the WABAs you granted; with plain OAuth type the ID in manually (section 2.0).

#### Important constraint

Only **one Meta App per Appmixer tenant** is configured. If your tenant has many customers, they all share the same plugin endpoint — Appmixer routes events by WABA so isolation works fine. But if you operate multiple Appmixer tenants you need a Meta App per tenant.

### 2.6 Going Live — what changes and what does not

Switching the Meta App from **Development** to **Live** mode (after App Review approval) lifts a few restrictions but **does not change the fundamental WhatsApp Business messaging policy**.

#### What changes when you go Live

| Restriction                                           | Development                                | Live                                            |
| ----------------------------------------------------- | ------------------------------------------ | ----------------------------------------------- |
| Recipient must be on the **Verified Recipients** list | Required                                   | Removed — message anyone                        |
| Available templates                                   | Only Meta-provided (e.g. `hello_world`)    | All approved templates in your WABA             |
| Daily messaging cap                                   | 250 business-initiated conversations / 24h | Quality-tier based: 1K → 10K → 100K → unlimited |
| Geographic reach                                      | Limited to Meta-approved regions           | Worldwide                                       |

#### What does NOT change

These constraints apply to **every** WhatsApp Business app, forever:

1. **The 24-hour customer service window.** Free-form messages allowed only within 24h of the user's last message. Outside → templates only.
2. **Opt-in requirement for business-initiated messages.** Sending unsolicited templates puts your number's quality rating in the red zone and risks WABA suspension.
3. **Templates require pre-approval.** Submit via Meta Business Manager → WhatsApp → Message Templates, or programmatically via `POST /{waba-id}/message_templates`. Approval typically takes hours to a day.
4. **Silent-drop behaviour for out-of-window sends.** HTTP 200 + `messageId` on accept, no delivery, no error. Detect via `MessageStatusUpdated` (you'll get `sent` but never `delivered` / `failed`).

#### Common production patterns

**A) User-initiated conversation** (chatbot, support inbox)

```
[User clicks wa.me link or scans QR] → User writes first message
                                            ↓
                          [NewMessage trigger fires in Appmixer]
                                            ↓
                  [SendTextMessage / SendImageMessage / …] freely for 24h
                                            ↓
            (24h ticks; either user replies — window resets — or window closes)
```

Free-form messages are **service conversations** — typically free or at the lowest rate.

**B) Business-initiated outreach** (notifications, reminders, marketing)

```
[External trigger: order placed / appointment reminder / promo]
                                ↓
                    [SendTemplateMessage with approved template]
                                ↓
                      (delivered as billable conversation)
                                ↓
              (if user replies → NewMessage trigger → 24h window opens → free text)
```

Templates are billed per conversation by category and country:

| Category           | Typical use                   | Cost (EU, indicative) |
| ------------------ | ----------------------------- | --------------------- |
| **Service**        | Reply within 24h window       | Free (or very low)    |
| **Authentication** | OTPs, login codes             | \~$0.005–0.015 / conv |
| **Utility**        | Order status, account updates | \~$0.015–0.04 / conv  |
| **Marketing**      | Promotions, newsletters       | \~$0.04–0.10 / conv   |

Exact rates depend on country and change periodically — see [Meta's conversation-based pricing](https://developers.facebook.com/docs/whatsapp/pricing).

#### Designing a customer's flow — checklist

When asked "how do I broadcast to all my users":

1. ☐ Did the recipient explicitly opt in? (Required; no opt-in = ToS violation.)
2. ☐ Is the message intent **Marketing**, **Utility**, **Authentication**, or **Service**? Each has its own template category and pricing tier.
3. ☐ Is there an approved template for this message? If not, submit one and wait for approval.
4. ☐ Does the flow gracefully handle the `failed` status webhook (number blocked, opted out, invalid)?
5. ☐ Is the recipient potentially outside the 24-hour window? If unknown → use a template.

### 2.7 Test the connection

The quickest end-to-end smoke test from inside Appmixer:

1. In the Designer, click **Connect WhatsApp** on any WhatsApp component → complete OAuth (section 2.1).
2. Add an **Ensure Sender Phone Number Registered** component, fill `phoneNumberId` and `pin`, run it once. (Idempotent — safe to re-run.)
3. Drop a **Send Template Message** component (the safest first message — see section 2.4 above for why). Use:
   * **WhatsApp Business Account ID** — pick from the dropdown (Embedded Signup) or type your WABA ID (plain OAuth)
   * **Sender Phone Number** — the dropdown loads from the WABA above
   * `to` = a verified recipient in E.164 format (e.g. `+420777123456`)
   * `templateName` = `hello_world` (Meta's always-approved default template)
   * `languageCode` = `en_US`
4. Run the flow. A message should arrive on the recipient's WhatsApp within seconds.
5. **Only after** the recipient writes back from WhatsApp do you have a 24-hour window in which `Send Text Message` will actually deliver.
6. (Optional) Add a `New Message` trigger to a separate flow, run it, then send a reply from your phone to the test number — the trigger should fire within seconds.

***

### Troubleshooting

| Symptom                                                                                  | Cause / Fix                                                                                                                                                                                                                                                                                                                                         |
| ---------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Auth fails with "The connected Facebook account did not grant the WhatsApp permissions…" | The issued token carries no whatsapp scopes. Most common cause: Meta silently reused a stale **Business Integration** grant — remove it at facebook.com → Settings → **Business integrations** and reconnect. Other causes: permissions declined during login; Live app with standard access and no app role for the user. See Part 2, section 2.1. |
| Embedded Signup wizard shows "… can't onboard customers right now"                       | The business portfolio owning the Meta App hasn't passed **Business Verification** (or advanced access for the whatsapp scopes is missing). Complete Part 1, section 1.7 / the prerequisites in section 1.3.1.                                                                                                                                      |
| Embedded Signup page says "WhatsApp Embedded Signup is not configured"                   | `esConfigId` (or `clientId`) missing in Backoffice → `appmixer:whatsapp`. See Part 1, section 1.4.                                                                                                                                                                                                                                                  |
| Embedded Signup button stuck on "Loading Facebook SDK…" / popup blocked                  | The Appmixer API domain is not in **Allowed Domains for the JavaScript SDK**, or **Login with the JavaScript SDK** is off (Part 1, section 1.3.1, step 3).                                                                                                                                                                                          |
| `Invalid Scopes: business_management` during OAuth                                       | The Meta App doesn't have `business_management` whitelisted (WhatsApp-use-case apps may only request `whatsapp_*` permissions). The connector only requires the two `whatsapp_*` scopes — make sure your published connector matches and re-run OAuth.                                                                                              |
| The `WhatsApp Business Account ID` dropdown is empty                                     | Expected with plain OAuth (no `esConfigId`) — Meta doesn't expose the picked WABA to the token in that flow. Type the WABA ID in manually (Part 2, section 2.0). With Embedded Signup configured, reconnect the account so a fresh token with WABA `target_ids` is issued.                                                                          |
| Asset picker says "No WhatsApp Business Accounts available"                              | The customer's logged-in Facebook account doesn't own / co-manage any WABA. They must create one in Meta Business Manager first (see Part 2, section 2.0).                                                                                                                                                                                          |
| `133010 — Account not registered`                                                        | The phone number was not registered on the Cloud API. Run **Ensure Sender Phone Number Registered** once.                                                                                                                                                                                                                                           |
| `Security PIN Mismatch: Wrong PIN used` (during register)                                | The PIN you supplied does not match the phone number's two-step verification PIN. Reset it: Meta Business Manager → WhatsApp Manager → phone number → Two-step verification PIN. Then re-run Register with the new PIN.                                                                                                                             |
| **Flow succeeds with valid `messageId` but recipient never receives the message**        | You sent a free-form (text / media / location) message outside the 24-hour customer service window. Meta accepts the request and returns HTTP 200 but silently drops delivery. **Fix:** use `Send Template Message` with `hello_world` for the first contact, then wait for the user to reply before sending text. See section 2.4.                 |
| `131030 — Recipient phone number not in allowed list`                                    | Meta App is in Development mode and the recipient isn't in the verified list. Add the recipient under **WhatsApp → API Setup → Manage phone number list**, or move to Live mode (Part 1, section 1.7).                                                                                                                                              |
| Test works in Meta App Dashboard "Send Message" but not in Appmixer                      | The dashboard's built-in send button uses `hello_world` (a template) by default. Your Appmixer flow is probably sending `text` outside the 24-hour window — switch to **Send Template Message** for the first contact.                                                                                                                              |
| `132000 — Number of parameters does not match` (templates)                               | Template `components` array doesn't match the template's required parameters. Inspect the template structure in **WhatsApp → Message Templates** and adjust the JSON.                                                                                                                                                                               |
| `NewMessage` trigger never fires (but `MessageStatusUpdated` works)                      | Most often: no inbound message has been sent to your business number yet. Outbound sends generate `statuses[]` but not `messages[]`. From a verified recipient phone, write a message TO your test number — then the trigger fires.                                                                                                                 |
| Both triggers silent                                                                     | `messages` field is not subscribed in Meta App webhook configuration (Part 1, section 1.6), or the per-WABA subscription failed. Check Meta App Dashboard → WhatsApp → Configuration → Webhooks → `messages` shows "Subscribed". The customer's flow must be in **Running** state — `start()` calls `POST /{wabaId}/subscribed_apps`.               |
| Webhook verify fails (Meta returns "Couldn't validate the callback URL")                 | The verify token in Meta App Dashboard must match `verifyToken` configured in Backoffice → `appmixer:whatsapp` (Part 1, section 1.4). Re-check both and re-save. The plugin endpoint must also be reachable (HTTPS, 200 on `GET /plugins/appmixer/whatsapp/events` handshake).                                                                      |
| Token expires after \~60 days                                                            | Long-lived tokens are issued via `fb_exchange_token` and need periodic refresh. Appmixer refreshes them automatically; if a customer's account stops working, ask them to reconnect via the Designer.                                                                                                                                               |

### References

* WhatsApp Business Cloud API docs: <https://developers.facebook.com/docs/whatsapp/cloud-api>
* Webhook setup: <https://developers.facebook.com/docs/whatsapp/cloud-api/guides/set-up-webhooks>
* Register phone number: <https://developers.facebook.com/docs/whatsapp/cloud-api/reference/registration>
* Access tokens & System Users: <https://developers.facebook.com/documentation/business-messaging/whatsapp/access-tokens/>
* Conversation-based pricing: <https://developers.facebook.com/docs/whatsapp/pricing>


---

# 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 dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.appmixer.com/connector-configuration/whatsapp.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
