> ## Documentation Index
> Fetch the complete documentation index at: https://docs.crmspark.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# Conectar WhatsApp Business pela API

> Guia para integradores iniciarem o Embedded Signup da Meta via API, acompanhar a sessão e receber o número conectado por webhook ou consulta.

Use este fluxo quando sua aplicação precisa **conectar um número da API oficial do WhatsApp** à organização Spark **sem** que a pessoa passe pelo painel do CRM. O Spark hospeda a etapa com a Meta; sua integração só cria a sessão, abre a URL para o usuário final e reage ao resultado.

Para conectar manualmente pelo dashboard, veja [Conectar WhatsApp Business (API oficial)](/guia/conectar-whatsapp-business). Para autenticação, chaves e base URL, veja [Introdução à API](/api-reference/introduction).

## Pré-requisitos

| Requisito                  | Detalhe                                                                                                                                                       |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Chave secreta**          | As rotas desta seção exigem `sk_` no cabeçalho `X-API-Key`.                                                                                                   |
| **Ambiente ativo**         | Habilite desenvolvedores em [Configurações → Desenvolvedores](https://crmspark.com.br/dash/settings/developers).                                              |
| **Plano ativo**            | Assinatura ativa na organização (`SUBSCRIPTION_INACTIVE` → 403).                                                                                              |
| **Conta Meta**             | Quem abre a URL precisa concluir o fluxo oficial da Meta (WhatsApp Business / Embedded Signup).                                                               |
| **Webhooks (recomendado)** | Para reagir em tempo real, cadastre os eventos `entrypoints.whatsapp.*` no [Consumer App Portal](/api-reference/webhooks#como-configurar-endpoints-no-spark). |

```http theme={null}
X-API-Key: sk_sua_chave_secreta
Content-Type: application/json
```

Base URL: [gateway.crmspark.com.br](https://gateway.crmspark.com.br) (prefixo `/v1`).

## O que acontece, em resumo

1. Seu **backend** chama `POST /v1/entrypoints/whatsapp/connection-sessions` e recebe `sessionId`, `url` e `expiresAt`.
2. Você direciona a pessoa para **`url`** (página do Spark). Ela faz login na Meta e autoriza o número.
3. O Spark finaliza a conexão e cria o **entrypoint** (canal WhatsApp oficial) na organização.
4. Você descobre o resultado por **webhook** (`entrypoints.whatsapp.connected` ou `entrypoints.whatsapp.connection_failed`) ou por **polling** em `GET …/connection-sessions/{sessionId}`.

```mermaid theme={null}
sequenceDiagram
  participant App as Sua aplicação
  participant GW as Gateway Spark
  participant User as Usuário final
  participant Page as Página Spark (url)
  participant Meta as Meta / WhatsApp

  App->>GW: POST connection-sessions
  GW-->>App: 202 sessionId, url, expiresAt
  App->>User: Abre url (janela de topo)
  User->>Page: Conclui Embedded Signup
  Page->>Meta: Fluxo oficial
  Meta-->>Page: Autorização
  Page-->>User: Sucesso (e returnUrl, se informado)
  GW-->>App: Webhook connected OU GET status completed
```

<Warning>
  A API **não** devolve códigos OAuth da Meta nem tokens de longa duração para sua aplicação. Credenciais e vínculo do número ficam no Spark; você recebe o **entrypoint** criado (`id`, `phoneNumberId`, `wabaId`, etc.) quando a conexão conclui.
</Warning>

## Endpoints

| Método | Rota                                                       | Descrição                                               |
| ------ | ---------------------------------------------------------- | ------------------------------------------------------- |
| `POST` | `/v1/entrypoints/whatsapp/connection-sessions`             | Inicia uma sessão (**202**).                            |
| `GET`  | `/v1/entrypoints/whatsapp/connection-sessions/{sessionId}` | Consulta status e dados do entrypoint, se já conectado. |

A referência OpenAPI ao lado documenta cada campo, exemplo e código de erro.

## Criar uma sessão

**Corpo (`application/json`):**

| Campo          | Obrigatório | Descrição                                                                                                                                                          |
| -------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `funnelStepId` | Não         | Etapa do funil em que **novos contatos** desse número entram. Omita para não vincular funil.                                                                       |
| `funnelId`     | Condicional | Se informar `funnelStepId`, pode enviar `funnelId` para validar que a etapa pertence a esse funil. **Não** envie só `funnelId` sem `funnelStepId` — a API rejeita. |
| `coexistence`  | Não         | `true` para o fluxo de **coexistência** com o app WhatsApp Business no celular; padrão `false` (Embedded Signup da API oficial).                                   |
| `returnUrl`    | Não         | URL **https** (sem usuário/senha na URL) para redirecionar a pessoa após conectar com sucesso.                                                                     |

**Resposta 202:**

| Campo       | Significado                                                                           |
| ----------- | ------------------------------------------------------------------------------------- |
| `sessionId` | Identificador estável da sessão — use em GET e correlacione com webhooks.             |
| `url`       | Link único para a pessoa abrir no navegador. **Não** é o mesmo valor que `sessionId`. |
| `expiresAt` | Prazo em ISO 8601. A sessão vale **20 minutos** a partir da criação.                  |
| `status`    | Sempre `pending` na criação.                                                          |

```bash theme={null}
curl -s -X POST https://gateway.crmspark.com.br/v1/entrypoints/whatsapp/connection-sessions \
  -H "X-API-Key: sk_…" \
  -H "Content-Type: application/json" \
  -d '{
    "funnelStepId": "funnel_step_abc",
    "funnelId": "funnel_xyz",
    "coexistence": false,
    "returnUrl": "https://seuapp.com/whatsapp/conectado"
  }'
```

```json theme={null}
{
  "sessionId": "wa_connect_…",
  "status": "pending",
  "url": "https://crmspark.com.br/connect/whatsapp/…",
  "expiresAt": "2026-05-08T12:20:00.000Z"
}
```

### Como abrir a `url`

* Abra em **janela de topo** ou nova aba (`window.open` com `_blank` ou redirecionamento). A resposta 202 da API descreve explicitamente “janela de topo” — popups bloqueados ou iframes costumam quebrar o fluxo da Meta.
* Guarde `sessionId` no seu backend **antes** de enviar o usuário à `url`.
* A `url` é de uso único e sensível: trate como link de convite (não logue em analytics públicos, não compartilhe em canais inseguros).

## Consultar a sessão

`GET /v1/entrypoints/whatsapp/connection-sessions/{sessionId}` com a mesma chave `sk_`.

**Status possíveis:**

| `status`    | Significado                                                          |
| ----------- | -------------------------------------------------------------------- |
| `pending`   | Ainda aguardando a pessoa concluir na Meta ou o processamento final. |
| `completed` | Número conectado; `entrypoint` traz o canal criado.                  |
| `failed`    | Falha definitiva; veja `reason` e `message`.                         |
| `expired`   | Prazo esgotado sem conclusão.                                        |

Enquanto `pending`, `entrypoint` é `null`. Em `completed`, você recebe, entre outros:

* `entrypoint.id` — use em envios e listagens (`GET /v1/entrypoints`, mensageria, etc.).
* `phoneNumberId`, `wabaId`, `displayPhone`, `name`
* `funnelId`, `funnelStepId`, `isCoexistence` — espelham o que foi configurado na sessão.

**Motivos de falha (`reason`):**

| `reason`                | Quando ocorre                                                                 |
| ----------------------- | ----------------------------------------------------------------------------- |
| `expired`               | Sessão passou do prazo sem conclusão.                                         |
| `token_exchange_failed` | A Meta não concluiu a troca de credenciais (erro temporário ou cancelamento). |
| `phone_in_use`          | Número já vinculado a outra conta ou canal incompatível.                      |
| `funnel_not_found`      | Funil ou etapa inválida para a organização no momento da conclusão.           |

O campo `message` pode trazer texto legível para exibir ao usuário; para lógica no código, prefira `status` e `reason`.

<Tip title="Webhook + polling">
  Em produção, trate o **webhook** como fonte principal e use **GET** como fallback (tela de “aguardando conexão”, suporte ou reconciliação). Faça polling com intervalo razoável (ex.: 2–5 s) só enquanto `pending`, e pare ao receber evento final ou ao passar `expiresAt`.
</Tip>

## Webhooks

Cadastre no portal Svix (aba Webhooks do painel) os eventos do grupo **entrypoints**:

| `event`                                  | Quando dispara                                                                                                                         |
| ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `entrypoints.whatsapp.connected`         | Conexão concluída com sucesso. `data` inclui `tenantId`, `sessionId`, `occurredAt` e `entrypoint` (mesma forma do GET em `completed`). |
| `entrypoints.whatsapp.connection_failed` | Sessão **expirada** ou **falha definitiva**. `data` traz `status` (`expired` ou `failed`), `reason` e `sessionId`.                     |

Formato geral, assinatura Svix, retentativas e idempotência: [Webhooks](/api-reference/webhooks).

Exemplo enxuto de sucesso:

```json theme={null}
{
  "event": "entrypoints.whatsapp.connected",
  "data": {
    "tenantId": "tenant_…",
    "sessionId": "wa_connect_…",
    "occurredAt": "2026-05-08T12:00:00.000Z",
    "entrypoint": {
      "id": "wa_entrypoint_…",
      "name": "WhatsApp Business",
      "displayPhone": "+55 11 99999-0000",
      "phoneNumberId": "106540352242922",
      "wabaId": "524126980791429",
      "funnelId": "funnel_…",
      "funnelStepId": "funnel_step_…",
      "isCoexistence": false
    }
  }
}
```

## Fluxo recomendado para integradores

<Steps>
  <Step title="Criar sessão no servidor">
    Chame `POST` com `sk_`, opcionalmente funil e `returnUrl`. Persista `sessionId` associado ao usuário ou tenant da sua aplicação.
  </Step>

  <Step title="Abrir a URL para o usuário">
    Redirecione ou abra `url` em janela de topo. Mostre contagem regressiva até `expiresAt` se quiser melhorar a UX.
  </Step>

  <Step title="Aguardar o resultado">
    No handler de webhook, filtre por `sessionId`. Atualize seu banco com `entrypoint.id` em `connected`. Em `connection_failed`, informe o usuário e ofereça criar nova sessão.
  </Step>

  <Step title="Usar o canal conectado">
    Liste entrypoints (`GET /v1/entrypoints?platform=whatsapp`) ou use o `id` do webhook para enviar mensagens pela API de mensageria e automações já documentadas.
  </Step>
</Steps>

## SDK TypeScript

Com o pacote [`sparkcrm`](https://www.npmjs.com/package/sparkcrm):

```ts theme={null}
import SparkCRM from "sparkcrm";

const client = new SparkCRM({ apiKey: process.env.SPARK_API_KEY! });

const { sessionId, url, expiresAt } = await client.whatsappConnectionSessions.create({
  funnelStepId: "funnel_step_…",
  funnelId: "funnel_…",
  returnUrl: "https://seuapp.com/ok",
});

const session = await client.whatsappConnectionSessions.retrieve(sessionId);
```

Tipos de webhook: `EntrypointsWhatsappConnectedWebhook` e `EntrypointsWhatsappConnectionFailedWebhook` em [TypeScript — webhooks e tipos](/sdks/typescript/webhooks-e-tipos).

## Limitações e boas práticas

* **Uma sessão, um fluxo:** cada `POST` gera nova `url` e novo prazo. Se expirar ou falhar, crie outra sessão; não reutilize `url` antiga.
* **Prazo fixo de 20 minutos:** após `expiresAt`, o status passa a `expired` (webhook `connection_failed` com `reason: expired`).
* **Somente API oficial:** este fluxo não substitui WhatsApp Lite (QR code); use os entrypoints `whatsapp_lite` pelo painel ou outras APIs conforme a referência.
* **Funil opcional:** sem `funnelStepId`, o número conecta sem etapa padrão; você pode ajustar depois no painel em Canais.
* **Coexistência:** só marque `coexistence: true` quando o caso de uso exigir o modo coexistência com o app Business; o fluxo na página do Spark difere do Embedded Signup padrão.
* **Rate limit:** respeite `429` (`RATE_LIMIT_EXCEEDED`) com backoff; evite polling agressivo em muitas sessões paralelas.
* **Segurança:** nunca exponha `sk_` no front-end. Crie a sessão sempre no backend; o front só recebe a `url` (ou um redirect controlado por você).

## Erros comuns

| Situação                                    | O que fazer                                                                                             |
| ------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| `VALIDATION_ERROR` ao criar                 | Confira par `funnelId` + `funnelStepId`, `returnUrl` https válida e JSON conforme o schema.             |
| Popup bloqueado                             | Oriente o usuário a permitir popups ou use redirecionamento de página inteira para `url`.               |
| `phone_in_use`                              | O número já está em outro WABA/canal; desvincule na Meta ou escolha outro número.                       |
| GET continua `pending` após sucesso na tela | Aguarde alguns segundos ou confie no webhook; a conclusão pode levar um instante após a Meta.           |
| Webhook não chega                           | Verifique endpoint, filtro de eventos no portal e assinatura; veja [Webhooks](/api-reference/webhooks). |

## Leitura adicional

* [Lista e detalhe de entrypoints](/api-reference/entrypoints/lista-todos-os-entrypoints-configurados) — depois de conectar.
* [Webhooks de saída](/api-reference/webhooks) — configuração Svix e verificação de assinatura.
* [Disparos de campanha](/api-reference/campaigns) — uso do canal WhatsApp oficial com templates aprovados.
