> Source: https://wexa.ai/docs/connectors/connect-whatsapp

# connect-whatsapp

Start connecting a WhatsApp account to this project, the same as adding the WhatsApp connector in the console. It creates the connector and returns its `connector_id`, with a QR link to scan when the number is not linked yet. Needs the `fabric:connector.connect` grant.

**Connect a WhatsApp account**

**Wexa MCP server**

```bash
curl -sS -X POST https://fabric.wexa.ai/mcp/$FABRIC_PROJECT_ID \
  -H "authorization: Bearer $FABRIC_API_KEY" \
  -H "Mcp-Session-Id: $MCP_SESSION_ID" \
  -H "content-type: application/json" -H "accept: application/json" \
  -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"connect-whatsapp","arguments":{"name":"Support WhatsApp","phone_number":"<phone-number>","email_id":"<email>","pin":"<pin>"}}}'
```

```json
{
  "content": [
    {
      "type": "text",
      "text": "{\"lifecycle_id\":\"qlc_000003\",\"result\":{\"connector_id\":\"6b0f2c9e4a1d8e7f3c2b1a90\",\"name\":\"Support WhatsApp\",\"status\":\"pending\",\"connected\":false,\"connect_url\":\"https://auth.example/whatsapp/abc123\",\"link_expires_at\":\"2026-10-09T10:20:00Z\"}}"
    }
  ],
  "isError": false
}
```

**REST API**

```bash
curl -sS https://fabric.wexa.ai/v1/connect-whatsapp \
  -H "authorization: Bearer $FABRIC_API_KEY" \
  -H "content-type: application/json" \
  -d '{"name":"Support WhatsApp","phone_number":"<phone-number>","email_id":"<email>","pin":"<pin>"}'
```

```json
{
  "lifecycle_id": "qlc_000003",
  "result": {
    "connector_id": "6b0f2c9e4a1d8e7f3c2b1a90",
    "name": "Support WhatsApp",
    "status": "pending",
    "connected": false,
    "connect_url": "https://auth.example/whatsapp/abc123",
    "link_expires_at": "2026-10-09T10:20:00Z"
  }
}
```

**TypeScript SDK**

```ts
import { Fabric } from '@wexa-fabric/sdk'

const fabric = new Fabric()
const result = await fabric.connectWhatsApp({
  name: 'Support WhatsApp',
  phone_number: '<phone-number>',
  email_id: '<email>',
  pin: '<pin>'
})
```

```ts
// result is the payload itself, with no `.result` to read
{
  connector_id: '6b0f2c9e4a1d8e7f3c2b1a90',
  name: 'Support WhatsApp',
  status: 'pending',
  connected: false,
  connect_url: 'https://auth.example/whatsapp/abc123',
  link_expires_at: '2026-10-09T10:20:00Z'
}
```

**Python SDK**

```python
from wexa import Fabric

fabric = Fabric()
out = fabric.connect_whatsapp(
    name="Support WhatsApp",
    phone_number="<phone-number>",
    email_id="<email>",
    pin="<pin>",
)
```

```python
# out is the result, already unwrapped
{
    "connector_id": "6b0f2c9e4a1d8e7f3c2b1a90",
    "name": "Support WhatsApp",
    "status": "pending",
    "connected": False,
    "connect_url": "https://auth.example/whatsapp/abc123",
    "link_expires_at": "2026-10-09T10:20:00Z"
}
```

## Parameters

| Parameter | Type | Required | Notes |
| --- | --- | --- | --- |
| `name` | string | Required | A name for the connector. A string. |
| `phone_number` | string | Required | The WhatsApp number with its country code and no `+` or spaces, e.g. `919876543210`. A string; a bad format is refused with the platform's message, for example `Invalid phone number format`. |
| `email_id` | string | Required | The email the number is registered to. The PIN is sent here. A string. |
| `pin` | string | Required | A PIN that, with `email_id`, proves ownership of the number. A string. An email and PIN that do not match an earlier registration of the number are refused (400). |
| `description` | string | Optional | What the connector is for. |
| `success_redirect_url` | string | Optional | Where the QR page sends the user after a successful scan. |

**Errors**

- `ForbiddenError` (403): your access does not include the WhatsApp connector (`S8:whatsapp-connect-refused`). The message asks you to have an org admin grant it.
- `ValidationError` (400): the platform refused the connect request (`S8:whatsapp-connect-refused`), with its own message.
- `ValidationError` (422): the connector's configuration is not valid (`S8:whatsapp-connect-refused`).
- `UpstreamError` (502): WhatsApp's provider rejected the link request. The message reads `WhatsApp provider (Unipile) rejected the connect request (status N). Please verify the phone number and try again.`

**Show full response**

An example response, for a number that is not linked yet. The connector is pending and a QR link was issued.

**Result of connect-whatsapp**

**REST API**

```json
{
  "lifecycle_id": "qlc_000003",
  "result": {
    "connector_id": "6b0f2c9e4a1d8e7f3c2b1a90",
    "name": "Support WhatsApp",
    "status": "pending",
    "connected": false,
    "connect_url": "https://auth.example/whatsapp/abc123",
    "link_type": "create",
    "link_expires_at": "2026-10-09T10:20:00Z",
    "next_step": "Open connect_url and scan the QR code with WhatsApp on the phone (Settings > Linked devices > Link a device) within 10 minutes. Then call complete-whatsapp-connection with connector_id 6b0f2c9e4a1d8e7f3c2b1a90; it also issues a new link if this one expired or the scan failed."
  }
}
```

**Wexa MCP server**

```json
{
  "content": [
    {
      "type": "text",
      "text": "{\"lifecycle_id\":\"qlc_000003\",\"result\":{\"connector_id\":\"6b0f2c9e4a1d8e7f3c2b1a90\",\"name\":\"Support WhatsApp\",\"status\":\"pending\",\"connected\":false,\"connect_url\":\"https://auth.example/whatsapp/abc123\",\"link_type\":\"create\",\"link_expires_at\":\"2026-10-09T10:20:00Z\",\"next_step\":\"Open connect_url and scan the QR code with WhatsApp on the phone (Settings > Linked devices > Link a device) within 10 minutes. Then call complete-whatsapp-connection with connector_id 6b0f2c9e4a1d8e7f3c2b1a90; it also issues a new link if this one expired or the scan failed.\"}}"
    }
  ],
  "isError": false
}
```

**TypeScript SDK**

```ts
// the object you get back IS the result — there is no `.result` to read
{
  "connector_id": "6b0f2c9e4a1d8e7f3c2b1a90",
  "name": "Support WhatsApp",
  "status": "pending",
  "connected": false,
  "connect_url": "https://auth.example/whatsapp/abc123",
  "link_type": "create",
  "link_expires_at": "2026-10-09T10:20:00Z",
  "next_step": "Open connect_url and scan the QR code with WhatsApp on the phone (Settings > Linked devices > Link a device) within 10 minutes. Then call complete-whatsapp-connection with connector_id 6b0f2c9e4a1d8e7f3c2b1a90; it also issues a new link if this one expired or the scan failed."
}

// The TS SDK names these camelCase — lifecycleId, traceId — where Python uses
// lifecycle_id and trace_id. Both are non-enumerable: readable, but omitted by
// Object.keys() and JSON.stringify(). `result.lifecycleId` here is undefined.
result.lifecycleId // 'qlc_000003'
```

**Python SDK**

```python
# a dict subclass; `result` is already unwrapped
{
 "connector_id": "6b0f2c9e4a1d8e7f3c2b1a90",
 "name": "Support WhatsApp",
 "status": "pending",
 "connected": False,
 "connect_url": "https://auth.example/whatsapp/abc123",
 "link_type": "create",
 "link_expires_at": "2026-10-09T10:20:00Z",
 "next_step": "Open connect_url and scan the QR code with WhatsApp on the phone (Settings > Linked devices > Link a device) within 10 minutes. Then call complete-whatsapp-connection with connector_id 6b0f2c9e4a1d8e7f3c2b1a90; it also issues a new link if this one expired or the scan failed."
}

out.lifecycle_id  # 'qlc_000003' — an attribute, not a key
```

For a number that is already linked, `status` is `ready`, `connected` is `true`, and there is no `connect_url`,
`link_type` or `link_expires_at`.

Keeping the `lifecycle_id` is what lets you ask later why a call was allowed, refused or held.

**More details**

**Response fields**

- `connector_id`: The connector this call created. Pass it to `complete-whatsapp-connection` and `get-whatsapp-connection`.
- `name`: The connector's name.
- `status`: `pending` while the account is not linked, `ready` once it is.
- `connected`: `true` when the WhatsApp account is linked, whatever `status` says.
- `connect_url`: Present only while a scan is awaited: the page with the QR code.
- `link_type`: Present with `connect_url`: `create` for a new link, `reconnect` for one that re-links the account.
- `link_expires_at`: Present with `connect_url`: when the link stops working, as an RFC 3339 time, 10 minutes after it was issued.
- `next_step`: What to do next, in words.

What comes back depends on whether the number is already linked:

- When it is not linked yet, `status` is `pending` and `connect_url` is a page with a QR code. Open it, and scan the code with WhatsApp on the phone (**Settings > Linked devices > Link a device**) within 10 minutes. Then call [`complete-whatsapp-connection`](/docs/connectors/complete-whatsapp-connection) with the `connector_id`.
- When it is already linked, the connector is `ready` at once, `connected` is `true`, and no link is issued.

The call never waits for the scan. Follow the connector with [`get-whatsapp-connection`](/docs/connectors/get-whatsapp-connection), or let an SDK wait for you.

`email_id` and `pin` together prove that you own the number. The PIN is sent to `email_id`. When the number was registered before, both must match that earlier registration, or the call is refused with the platform's own message, the same one the console shows. Neither the PIN nor the rest of the connector's configuration is ever returned, by this tool or by the other two WhatsApp tools.

A value in angle brackets in the example is one only you can supply, and the platform refuses a literal `<...>`.

**Waiting for the scan.** With `wait`, both SDKs create the connector, then poll `get-whatsapp-connection` every `poll` seconds until `connected` is `true`, and return that status. A number that is already linked is returned at once. When the time limit is reached, the SDK calls `complete-whatsapp-connection` once and returns its answer: the connector is connected when the scan landed, and is otherwise still pending with a new `connect_url`. Nothing is raised at the limit. The SDK never calls `complete-whatsapp-connection` while it polls, because each call on an unscanned connector issues a new link and replaces the one being scanned. With `wait`, the SDK answers only when the wait ends, so the `connect_url` to scan is not in your hands while it waits. To show the QR link first, call without `wait`, open `connect_url`, and then call `complete-whatsapp-connection` with `wait`.

The SDKs also take three options that are not sent to the platform:

- `wait` (TypeScript `wait`): off by default. Poll `get-whatsapp-connection` until the account is connected.
- `wait_timeout` (TypeScript `waitTimeout`): `600` by default. The most seconds to wait, which is the lifetime of the QR link.
- `poll` (TypeScript `poll`): `5` by default. Seconds between two polls.

Every call also writes a `connect-whatsapp.run` audit event, with the outcome: `connected`, `awaiting_scan` or `failed`. A failed call records the error and its code.

Not marked consequential, so it does not wait for approval. Connecting an account gives the project a new connector, which is why it needs its own grant, `fabric:connector.connect`. OWNER, ORG_ADMIN and PROJECT_ADMIN keys carry it by default. An API key minted before the grant existed does not carry it, and must be reissued to use this tool.

Every tool call works the same way: [How every tool call works](/docs/sdks-and-apis/how-every-tool-call-works).
