
# API de Conexão de Canais

Este guia mostra como conectar canais de mensagens a uma conta usando a API. Ele foi escrito para um desenvolvedor que está criando uma integração ou wrapper, portanto, foca nas solicitações exatas, na ordem em que devem ser feitas e nas respostas que você recebe.

Existe um padrão que você precisa entender de antemão, pois ele se aplica a quase todos os canais aqui.

## O padrão de conectar-e-consultar (poll)

A maioria dos canais não pode ser conectada com uma única chamada de API. Conectar WhatsApp, Instagram ou Messenger significa que o titular da conta precisa fazer login na sua própria conta do provedor e aprovar o acesso. **Não existe um caminho headless (totalmente automatizado)** para essa aprovação - uma pessoa real precisa abrir uma URL em um navegador ou escanear um código QR com seu telefone.

Portanto, o fluxo é sempre:

1. **Inicie a conexão** com uma `POST`. A resposta fornece uma URL para abrir ou um código QR para exibir.
2. **Transfira isso para o usuário final** - abra a URL no navegador dele ou renderize o código QR na tela para que ele escaneie.
3. **Consulte o endpoint de status** com `GET` em um intervalo curto (a cada poucos segundos) até que o status atinja um estado conectado.

O trabalho da sua integração é conduzir esse loop: mostrar a URL ou o QR, e então consultar até que esteja concluído. Planeje sua interface em torno da consulta - um spinner com uma mensagem "aguardando você concluir no seu navegador" funciona bem.

::: note
**Nota:** Antes de começar, certifique-se de que o acesso à API esteja habilitado no plano e que você possua uma chave de API. Consulte [Acesso à API](../integrations/api-access.md) para saber como gerar uma. Todas as solicitações abaixo usam a URL base `https://api.youraiconnector.com/v1` e você deve autenticar cada solicitação. Consulte [Autenticação](authentication.md) para as quatro formas aceitas - os exemplos aqui usam o cabeçalho `X-API-Key`, com um exemplo cURL por página mostrando a forma de consulta `?apiKey=` mais simples.
:::


---

## Instagram + Messenger (Meta)

Instagram e Messenger são conectados juntos em um único fluxo, porque ambos rodam em uma Página do Facebook. O titular da conta autoriza através do Facebook, você busca a lista de Páginas que ele gerencia e escolhe qual Página conectar.

### Passo 1 - Inicie a conexão do Instagram + Messenger

```
POST /channels/meta/connect
```

Isso retorna uma URL de consentimento. Nenhuma credencial é enviada nesta solicitação - a conexão é autorizada inteiramente no navegador.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/meta/connect?apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/channels/meta/connect", {
  method: "POST",
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
// Open data.oauth_url in the end user's browser.
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/channels/meta/connect",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
# Open data["oauth_url"] in the end user's browser.
```

**Resposta**

```json
{
  "success": true,
  "oauth_url": "https://www.facebook.com/v21.0/dialog/oauth?client_id=...&state=...",
  "state_token": "opaque-one-time-token",
  "connect_url": "https://api.youraiconnector.com/v1/channels/meta/connect/page?token=eyJhbGciOi...",
  "connect_url_expires_at": 1717000000000,
  "expires_at": "2026-06-10T12:30:00.000Z"
}
```

Abra `oauth_url` no navegador do usuário final para que ele possa fazer login no Facebook e aprovar o acesso. A tentativa de conexão expira em `expires_at` (cerca de 30 minutos) - se expirar, comece novamente. Trate `state_token` como um segredo de curta duração e não o registre em logs.

### Opção mais fácil para Instagram + Messenger: entregue `connect_url`

A resposta também inclui um `connect_url` pronto para uso: uma página hospedada que executa todo o fluxo para o titular da conta. Eles a abrem, fazem login no Facebook e, quando possuem mais de uma Página, ela exibe a lista e permite que escolham qual conectar - em seguida, ela relata o sucesso por conta própria. Forneça este link ao titular da conta em vez de abrir o `oauth_url` você mesmo, criar um seletor de Página e realizar a sondagem. O link funciona por cerca de 30 minutos (`connect_url_expires_at`); se expirar, inicie uma nova conexão. As etapas manuais abaixo são para integrações que desejam conduzir o fluxo e renderizar o seletor de Página por conta própria.

### Passo 2 - Verifique o status até que as páginas sejam carregadas

```
GET /channels/meta/status
```

Após o usuário concluir o login no Facebook, verifique este endpoint a cada poucos segundos. O campo `status` percorre estas etapas:

| `status` | Significado |
|---|---|
| `pending` | Consentimento ainda não concluído. Continue aguardando. |
| `token_received` | Autorizado, mas a lista de Páginas ainda está carregando. |
| `pages_loaded` | Páginas disponíveis - prossiga para o passo 3. |
| `connected` | Uma Página foi selecionada e o canal está ativo. |

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/channels/meta/status" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/channels/meta/status", {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
// Poll until data.status === "pages_loaded".
```

**Python**

```python
res = requests.get(
    "https://api.youraiconnector.com/v1/channels/meta/status",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
# Poll until data["status"] == "pages_loaded".
```

**Resposta (assim que as páginas forem carregadas)**

```json
{
  "success": true,
  "status": "pages_loaded",
  "pages": [
    {
      "id": "1234567890",
      "name": "My Business Page",
      "category": "Local business",
      "instagram_business_account": {
        "id": "17890000000000000",
        "username": "mybusiness"
      }
    }
  ],
  "selected_page": null
}
```

### Passo 3 - Listar as páginas (opcional)

Se você preferir buscar a lista de Páginas separadamente (por exemplo, para renderizar um seletor), use:

```
GET /channels/meta/pages
```

```bash
curl "https://api.youraiconnector.com/v1/channels/meta/pages" \
  -H "X-API-Key: YOUR_API_KEY"
```

Ele retorna o mesmo array `pages` que o endpoint de status. (O endpoint `status` já inclui as páginas, então esta chamada é apenas uma conveniência.)

### Passo 4 - Selecionar a página para conectar

```
POST /channels/meta/select-page
```

Envie o `page_id` da Página que o usuário escolheu. A conta do Instagram vinculada a essa Página é conectada automaticamente; você só precisa do objeto `instagram` se quiser substituir qual conta do Instagram usar.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/meta/select-page" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "page_id": "1234567890" }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/channels/meta/select-page", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ page_id: "1234567890" }),
});
const data = await res.json();
```

**Python**

```python
res = requests.post(
    "https://api.youraiconnector.com/v1/channels/meta/select-page",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"page_id": "1234567890"},
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "page_id": "1234567890",
  "instagram_business_account_id": "17890000000000000"
}
```

O canal agora está conectado. Um `GET /channels/meta/status` de acompanhamento reportará `status: "connected"`.

### Liste as publicações da página conectada

```
GET /channels/meta/posts?platform=instagram
```

Retorna as publicações recentes da página que você conectou - mídia do Instagram ou publicações do Facebook. É a partir disso que você renderiza um seletor ao configurar um Ponto de Entrada que reage a comentários em uma publicação específica.

| Parâmetro de consulta | Obrigatório | Descrição |
|---|---|---|
| `platform` | Sim | `instagram` ou `facebook`. Qualquer outra coisa retorna um `400`. |
| `limit` | Não | Quantas publicações retornar, `1`-`50`. O padrão é `25`. |
| `after` | Não | Cursor para a próxima página - passe o valor `nextCursor` da resposta anterior. |

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/channels/meta/posts?platform=instagram&limit=25" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Resposta**

```json
{
  "success": true,
  "connected": true,
  "platform": "instagram",
  "posts": [
    {
      "id": "17900000000000000",
      "caption": "New spring menu is live",
      "thumbnailUrl": "https://scontent.cdninstagram.com/...",
      "permalink": "https://www.instagram.com/p/Cxxxxxxxxxx/",
      "createdAt": "2026-05-02T09:12:00.000Z",
      "mediaType": "REELS"
    }
  ],
  "nextCursor": "QVFIUkxxxxxxxx"
}
```

`mediaType` é o rótulo próprio do Instagram (`REELS`, `FEED`, `STORY`, ou o formato - `IMAGE`, `VIDEO`, `CAROUSEL_ALBUM`); para o Facebook, é sempre `POST`. `nextCursor` é `null` na última página.

Se nada puder ser listado, a chamada ainda retorna `200` com `connected: false` e um array `posts` vazio, além de um `reason` informando o motivo:

| `reason` | O que fazer |
|---|---|
| _(ausente)_ | Nenhuma página está conectada ainda - execute o fluxo de conexão primeiro. |
| `no_instagram_account` | Uma página do Facebook está conectada, mas nenhuma conta comercial do Instagram está vinculada a ela. As publicações do Facebook ainda são listadas normalmente. |
| `token_expired` | A credencial da página armazenada não funciona mais - reconecte o canal. |

### Desconecte o Instagram + Messenger

```
DELETE /channels/meta
```

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/channels/meta" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Resposta**

```json
{ "success": true, "disconnected": true }
```

Isso interrompe o roteamento de entrada para Instagram e Messenger. É idempotente - chamá-lo quando nada está conectado ainda terá sucesso.

---

## WhatsApp Business

Isso conecta um número oficial do WhatsApp Business. O número já deve existir na conta antes de você chamar a conexão. Assim como na Meta, o titular da conta autoriza no navegador dele, então você faz a sondagem até que o número reporte `ONLINE`.

### Passo 1 - Inicie a conexão do WhatsApp Business

```
POST /channels/whatsapp/connect
```

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/whatsapp/connect?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "phone_number": "+14155551234" }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/channels/whatsapp/connect", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ phone_number: "+14155551234" }),
});
const data = await res.json();
// Open data.oauth_url in the account holder's browser.
```

**Python**

```python
res = requests.post(
    "https://api.youraiconnector.com/v1/channels/whatsapp/connect",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"phone_number": "+14155551234"},
)
data = res.json()
# Open data["oauth_url"] in the account holder's browser.
```

| Campo | Obrigatório | Descrição |
|---|---|---|
| `phone_number` | Sim | O número a ser conectado, no formato E.164 (ex: `+14155551234`). |
| `only_waba_sharing` | Não | Restringe a autorização ao compartilhamento de uma Conta do WhatsApp Business existente, pulando a configuração de um novo remetente. O padrão é `false`. |
| `retry` | Não | Executa novamente a autorização para um número cuja tentativa anterior não foi concluída. O padrão é `false`. |
| `business_name` | Não | Substituição cosmética para o nome da empresa exibido apenas na tela de consentimento (máx. 256 caracteres). Não é armazenado. |
| `description` | Não | Substituição cosmética para a descrição da empresa exibida apenas na tela de consentimento (máx. 256 caracteres). Não é armazenado. |

**Resposta**

```json
{
  "success": true,
  "status": "pending",
  "oauth_url": "https://www.facebook.com/v21.0/dialog/oauth?client_id=...&state=...",
  "state_token": "opaque-one-time-token",
  "expires_at": "2026-06-10T12:30:00.000Z"
}
```

Abra `oauth_url` no navegador do titular da conta para autorizar. Assim que ele aprovar, o registro será concluído em segundo plano.

### Passo 2 - Sondar o status até ONLINE

```
GET /channels/whatsapp/connect/{phoneNumber}/status
```

Sonde isso até que `status` seja `ONLINE`.

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/channels/whatsapp/connect/+14155551234/status" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const phone = encodeURIComponent("+14155551234");
const res = await fetch(
  `https://api.youraiconnector.com/v1/channels/whatsapp/connect/${phone}/status`,
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
// Poll until data.status === "ONLINE".
```

**Python**

```python
import urllib.parse

phone = urllib.parse.quote("+14155551234")
res = requests.get(
    f"https://api.youraiconnector.com/v1/channels/whatsapp/connect/{phone}/status",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
# Poll until data["status"] == "ONLINE".
```

**Resposta**

```json
{
  "success": true,
  "phone_number": "+14155551234",
  "channel": "whatsapp",
  "status": "ONLINE",
  "status_reason": null,
  "live": true
}
```

O campo `status` pode ser:

| `status` | Significado |
|---|---|
| `PENDING` | Autorizado, aprovação ainda em andamento. Continue sondando. |
| `ONLINE` | Conectado e pronto para enviar. |
| `RATE_LIMITED` | Muitas tentativas - aguarde antes de tentar novamente. |
| `REGISTRATION_FAILED` | A configuração não pôde ser concluída. |
| `DELETED` | O registro não existe mais. |

`live: true` significa que o status foi verificado junto ao provedor em tempo real; `false` significa que veio do último estado em cache.

### Desconecte um número do WhatsApp Business

```
DELETE /channels/whatsapp/{phoneNumber}
```

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/channels/whatsapp/+14155551234" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Resposta**

```json
{ "success": true, "phone_number": "+14155551234", "disconnected": true }
```

O número em si permanece na conta, para que você possa reconectá-lo mais tarde.

---

## WhatsApp Web

O WhatsApp Web vincula um número de WhatsApp comum escaneando um código QR, assim como vincular um dispositivo no aplicativo WhatsApp. O fluxo é: iniciar a sessão, buscar o código QR e exibi-lo, e então realizar a sondagem até que o status seja `connected`.

### Passo 1 - Inicie uma sessão de pareamento do WhatsApp Web

```
POST /channels/whatsapp-web/connections
```

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/whatsapp-web/connections?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "phone_number": "+15551230000" }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/channels/whatsapp-web/connections", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ phone_number: "+15551230000" }),
});
const data = await res.json();
```

**Python**

```python
res = requests.post(
    "https://api.youraiconnector.com/v1/channels/whatsapp-web/connections",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"phone_number": "+15551230000"},
)
data = res.json()
```

| Campo | Obrigatório | Descrição |
|---|---|---|
| `phone_number` | Sim | O número do WhatsApp para conectar, no formato E.164. |
| `proxy_country` | Não | Código de país ISO 3166-1 alpha-2 para a região de roteamento. Detectado automaticamente a partir do número quando omitido. |
| `force_new` | Não | Descarta qualquer sessão existente e inicia um novo pareamento. O padrão é `false`. |
| `import_contacts` | Não | Importa os contatos existentes do dispositivo na primeira conexão. O padrão é `false`. |
| `pause_ai_for_imported_contacts` | Não | Ao importar contatos, mantém as respostas automáticas pausadas para eles. O padrão é `true`. |
| `import_existing_chats` | Não | Importa o histórico de conversas existente (requer `import_contacts: true`). O padrão é `false`. |

**Resposta**

```json
{
  "success": true,
  "phone_number": "+15551230000",
  "session_id": "session-id",
  "status": "qr_pending",
  "connect_url": "https://api.youraiconnector.com/v1/channels/whatsapp-web/connect?token=eyJhbGciOi...",
  "connect_url_expires_at": 1717000000000,
  "poll_qr_path": "/v1/channels/whatsapp-web/connections/%2B15551230000/qr",
  "poll_status_path": "/v1/channels/whatsapp-web/connections/%2B15551230000/status"
}
```

### Opção mais fácil para WhatsApp Web: entregue `connect_url`

A resposta inclui um `connect_url` pronto para uso: uma página hospedada que exibe o código QR, atualiza-o automaticamente conforme ele gira e alterna para uma mensagem de sucesso no momento em que o número é vinculado. Basta fornecer este link ao titular da conta (abra-o em um navegador, envie para ele ou mostre-o como um QR/botão) e peça que ele o escaneie com o WhatsApp - você não precisa buscar o QR ou fazer polling de nada por conta própria. O link funciona por cerca de 30 minutos (`connect_url_expires_at`); se expirar antes que eles terminem, inicie uma nova conexão para obter um novo.

Este é o caminho recomendado quando uma pessoa pode abrir um link. As etapas manuais abaixo (buscar o QR você mesmo, verificar o status) são para integrações que desejam renderizar o QR dentro de sua própria interface.

A resposta também fornece o `poll_qr_path` e o `poll_status_path` exatos para você usar, para que não precise criá-los por conta própria.

### Passo 2 - Buscar o código QR e exibi-lo

```
GET /channels/whatsapp-web/connections/{phoneNumber}/qr
```

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/channels/whatsapp-web/connections/+15551230000/qr" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const phone = encodeURIComponent("+15551230000");
const res = await fetch(
  `https://api.youraiconnector.com/v1/channels/whatsapp-web/connections/${phone}/qr`,
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
// Render data.qr_data_url as an <img src> for the user to scan.
```

**Python**

```python
import urllib.parse

phone = urllib.parse.quote("+15551230000")
res = requests.get(
    f"https://api.youraiconnector.com/v1/channels/whatsapp-web/connections/{phone}/qr",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
# Render data["qr_data_url"] for the user to scan.
```

**Resposta**

```json
{
  "success": true,
  "phone_number": "+15551230000",
  "status": "qr_pending",
  "qr_code": "2@raw-qr-payload-string...",
  "qr_data_url": "data:image/png;base64,iVBORw0KGgo...",
  "expires_at": "2026-06-10T12:05:00.000Z"
}
```

Renderize o QR para o usuário escanear com seu telefone (WhatsApp > Aparelhos conectados > Conectar um aparelho):

- `qr_data_url` é uma imagem pronta para uso - coloque-a diretamente em uma tag `<img src>`.
- `qr_code` é o payload bruto caso você prefira gerar a imagem por conta própria.

O QR tem vida curta. Se você chamar isso logo após iniciar a sessão, poderá receber um `404` com "QR code not available yet" - apenas aguarde um momento e tente novamente. Se você receber um `410` ("QR code expired"), reinicie a conexão para obter um novo código.

### Passo 3 - Sondar o status até conectar

```
GET /channels/whatsapp-web/connections/{phoneNumber}/status
```

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/channels/whatsapp-web/connections/+15551230000/status" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const phone = encodeURIComponent("+15551230000");
const res = await fetch(
  `https://api.youraiconnector.com/v1/channels/whatsapp-web/connections/${phone}/status`,
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
// Poll until data.status === "connected" (or "open").
```

**Python**

```python
import urllib.parse

phone = urllib.parse.quote("+15551230000")
res = requests.get(
    f"https://api.youraiconnector.com/v1/channels/whatsapp-web/connections/{phone}/status",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
# Poll until data["status"] == "connected" (or "open").
```

**Resposta**

```json
{
  "success": true,
  "phone_number": "+15551230000",
  "status": "connected",
  "has_qr": false,
  "qr_expires_at": null,
  "last_activity": null,
  "message_count": null,
  "proxy": null,
  "live": true
}
```

| `status` | Significado |
|---|---|
| `not_initialized` | Nenhuma sessão ainda (falha terminal). |
| `qr_pending` | Aguardando o QR ser escaneado. |
| `connecting` | Escaneado, finalizando a configuração. |
| `connected` / `open` | Vinculado e ativo - isso é sucesso. |
| `disconnected` | Sessão encerrada (falha terminal). |

### Desconecte uma sessão do WhatsApp Web

```
DELETE /channels/whatsapp-web/connections/{phoneNumber}
```

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/channels/whatsapp-web/connections/+15551230000" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Resposta**

```json
{ "success": true, "phone_number": "+15551230000", "status": "removed" }
```

Isso desvincula o dispositivo e remove a conexão. Ele sempre limpa o estado local, portanto é idempotente mesmo que a sessão subjacente já tenha sido encerrada.

---

## Telegram

> **Disponibilidade:** O Telegram conecta-se como qualquer outro canal e está aberto para todas as contas — você não precisa que ele seja ativado para você. Os endpoints do Telegram abaixo ainda podem retornar `403` se o Telegram não estiver incluído no plano da conta, caso em que o erro será `"This channel is not included in your current plan. Upgrade to unlock it."`.

O Telegram conecta uma conta pessoal por meio de número de telefone e um código de login único (e uma senha de dois fatores, se a conta tiver uma configurada). O fluxo é: iniciar a sessão, enviar o código, opcionalmente enviar a senha e, em seguida, confirmar via status.

### Passo 1 - Inicie uma sessão de conexão do Telegram

```
POST /channels/telegram/connect
```

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/telegram/connect?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "phone_number": "+14155550100" }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/channels/telegram/connect", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ phone_number: "+14155550100" }),
});
const data = await res.json();
```

**Python**

```python
res = requests.post(
    "https://api.youraiconnector.com/v1/channels/telegram/connect",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"phone_number": "+14155550100"},
)
data = res.json()
```

| Campo | Obrigatório | Descrição |
|---|---|---|
| `phone_number` | Sim | O número de telefone da conta para conectar, no formato E.164. |
| `mode` | Não | `code` (padrão) envia um código de login único para a conta; `qr` retorna um token de login e uma URL de QR Code para exibição. |
| `proxy_country` | Não | Código de país ISO 3166-1 alpha-2 para a rota de rede de saída. |
| `force_new` | Não | Quando `true`, descarta qualquer sessão existente e começa do zero. |

**Resposta**

```json
{
  "success": true,
  "phone_number": "+14155550100",
  "status": "code_required",
  "session_id": "session-id",
  "connect_url": "https://api.youraiconnector.com/v1/channels/telegram/connect/page?token=eyJhbGciOi...",
  "connect_url_expires_at": 1717000000000
}
```

No modo `code`, a conta recebe um código de login no Telegram e `status` é `code_required`. (No modo `qr`, a resposta também inclui `login_token` e `qr_url` para exibir para leitura, e `status` é `qr_required`.)

### Opção mais fácil para Telegram: entregue `connect_url`

A resposta inclui um `connect_url` pronto para uso: uma página hospedada que finaliza a conexão por conta própria. No modo `code`, o titular da conta insere o código de login - e uma senha de verificação em duas etapas, caso a conta possua uma. No modo `qr`, a página exibe um QR code que se atualiza automaticamente para que ele seja escaneado pelo aplicativo do Telegram. De qualquer forma, a página relata o sucesso automaticamente, então você pode simplesmente fornecer este link ao titular da conta em vez de criar sua própria interface e realizar polling. O link funciona por cerca de 30 minutos (`connect_url_expires_at`); se expirar, inicie uma nova conexão para obter um novo link.

As etapas manuais abaixo (coletar o código você mesmo, enviá-lo, verificar o status via polling; ou renderizar `qr_url` e realizar polling) são destinadas a integrações que desejam renderizar a interface por conta própria.

### Passo 2 - Enviar o código de login

```
POST /channels/telegram/connect/{phoneNumber}/verify-code
```

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/telegram/connect/+14155550100/verify-code" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "code": "12345" }'
```

**JavaScript**

```javascript
const phone = encodeURIComponent("+14155550100");
const res = await fetch(
  `https://api.youraiconnector.com/v1/channels/telegram/connect/${phone}/verify-code`,
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ code: "12345" }),
  }
);
const data = await res.json();
```

**Python**

```python
import urllib.parse

phone = urllib.parse.quote("+14155550100")
res = requests.post(
    f"https://api.youraiconnector.com/v1/channels/telegram/connect/{phone}/verify-code",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"code": "12345"},
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "phone_number": "+14155550100",
  "status": "connected",
  "telegram_user_id": "100000001",
  "username": "myhandle"
}
```

Se `status` for `connected`, você terminou. Se a conta tiver a autenticação de dois fatores habilitada, `status` será `password_required` em vez disso - vá para o passo 3.

### Passo 3 - Enviar a senha de dois fatores (apenas se necessário)

```
POST /channels/telegram/connect/{phoneNumber}/verify-password
```

Chame isso apenas quando o passo 2 retornar `password_required`.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/telegram/connect/+14155550100/verify-password" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "password": "the-2fa-password" }'
```

**JavaScript**

```javascript
const phone = encodeURIComponent("+14155550100");
const res = await fetch(
  `https://api.youraiconnector.com/v1/channels/telegram/connect/${phone}/verify-password`,
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ password: "the-2fa-password" }),
  }
);
const data = await res.json();
```

**Python**

```python
import urllib.parse

phone = urllib.parse.quote("+14155550100")
res = requests.post(
    f"https://api.youraiconnector.com/v1/channels/telegram/connect/{phone}/verify-password",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"password": "the-2fa-password"},
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "phone_number": "+14155550100",
  "status": "connected",
  "telegram_user_id": "100000001",
  "username": "myhandle"
}
```

### Verifique o status do Telegram

```
GET /channels/telegram/connect/{phoneNumber}/status
```

```bash
curl "https://api.youraiconnector.com/v1/channels/telegram/connect/+14155550100/status" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Resposta**

```json
{
  "success": true,
  "phone_number": "+14155550100",
  "status": "connected",
  "telegram_user_id": "100000001",
  "live": true
}
```

`status` pode ser `connected`, `code_required`, `password_required`, `initializing`, `disconnected`, `not_initialized` ou `error`.

### Desconecte o Telegram

```
DELETE /channels/telegram/{phoneNumber}
```

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/channels/telegram/+14155550100" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Resposta**

```json
{ "success": true, "phone_number": "+14155550100", "status": "removed" }
```

Idempotente - chamadas repetidas são bem-sucedidas.

---

## Instagram (conta pessoal)

> Versão beta de disponibilidade limitada, habilitada por conta. Isso conecta uma conta pessoal do Instagram fazendo login com seu nome de usuário e senha (não a API oficial de Negócios). Se a conta não estiver habilitada para a versão beta, a chamada de conexão retornará um erro de permissão.

Como isso requer o próprio login do Instagram do titular da conta, o caminho mais simples é fornecer a eles o `connect_url` hospedado e permitir que insiram suas credenciais lá - sua integração nunca manipula a senha.

### Passo 1 - Inicie uma conexão do Instagram (pessoal)

```
POST /channels/instagram-private/connect
```

Envie o `username` e o `password` do Instagram.

**Resposta**

```json
{
  "success": true,
  "status": "connected",
  "connect_url": "https://api.youraiconnector.com/v1/channels/instagram-private/connect/page?token=eyJhbGciOi...",
  "connect_url_expires_at": 1717000000000
}
```

Se a conta tiver autenticação de dois fatores ou o Instagram apresentar um ponto de verificação, `status` retorna como `two_factor_required` ou `challenge_required` - envie o código para `/connect/{id}/verify-2fa` ou `/connect/{id}/verify-challenge` abaixo, então verifique `/connect/{id}/status` até `connected`. `{id}` é o nome de usuário normalizado do Instagram retornado como `account_id`/`username` na resposta acima - use-o em cada etapa abaixo.

### Etapa 2 - Enviar o código de dois fatores (se solicitado)

```
POST /channels/instagram-private/connect/{id}/verify-2fa
```

Chame isso apenas quando a etapa 1 (ou a etapa 3) retornar `two_factor_required`.

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/instagram-private/connect/yourbrand/verify-2fa" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "code": "123456" }'
```

**Resposta**

```json
{
  "success": true,
  "account_id": "yourbrand",
  "status": "connected",
  "ig_user_id": "17890000000000000",
  "username": "yourbrand"
}
```

`status` pode retornar `connected` (concluído), `two_factor_required` (código incorreto, tente novamente) ou `challenge_required` (o Instagram também solicita um código de ponto de verificação - vá para a etapa 3).

### Etapa 3 - Enviar o código de confirmação do ponto de verificação (se solicitado)

```
POST /channels/instagram-private/connect/{id}/verify-challenge
```

Chame isso apenas quando uma etapa anterior retornar `challenge_required`. A estrutura da solicitação e da resposta é a mesma da etapa 2 acima.

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/instagram-private/connect/yourbrand/verify-challenge" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "code": "123456" }'
```

### Verificar status do Instagram (pessoal)

```
GET /channels/instagram-private/connect/{id}/status
```

Verifique isso até que `status` seja `connected`, ou até que relate uma falha terminal.

```bash
curl "https://api.youraiconnector.com/v1/channels/instagram-private/connect/yourbrand/status" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Resposta**

```json
{
  "success": true,
  "account_id": "yourbrand",
  "status": "connected",
  "ig_user_id": "17890000000000000",
  "username": "yourbrand",
  "live": true
}
```

`status` pode ser `connected`, `two_factor_required`, `challenge_required`, `initializing`, `disconnected`, `not_initialized` ou `error`. `live: true` significa que isso foi lido ao vivo do worker de conexão em vez de um valor em cache.

### Opção mais fácil para Instagram (pessoal): entregue `connect_url`

A resposta inclui um `connect_url`: uma página hospedada onde o titular da conta insere seu nome de usuário e senha do Instagram (e um código de 2FA ou ponto de verificação, se o Instagram solicitar), e que relata o sucesso por conta própria. As credenciais vão direto para o Instagram e não são armazenadas. Forneça este link ao titular da conta em vez de coletar a senha dele em sua própria interface. O link funciona por cerca de 30 minutos (`connect_url_expires_at`).

### Desconectar Instagram (pessoal)

```
DELETE /channels/instagram-private/{id}
```

Idempotente - chamadas repetidas são bem-sucedidas.

### Sincronizar seguidores

```
POST /channels/instagram-private/{id}/sync-followers
```

Aciona manualmente uma sincronização de seguidores para uma conta conectada - o mesmo trabalho que é executado automaticamente em segundo plano, exposto aqui para uma ação de "Atualizar seguidores" sob demanda. Ele busca a lista atual de seguidores da conta, registra qualquer pessoa nova e (quando uma campanha ao vivo está com o alcance de seguidores ativado) envia aos novos seguidores uma DM de abertura, até um limite diário.

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/instagram-private/yourbrand/sync-followers" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Resposta**

```json
{
  "success": true,
  "accountId": "yourbrand",
  "totalFollowers": 1204,
  "newFollowers": 6,
  "dmsSent": 6,
  "isBaselineSeed": false
}
```

> Estes cinco campos são o único lugar nesta página que retornam `camelCase` em vez de `snake_case` - é assim que este endpoint está configurado hoje, não é um erro de digitação. `isBaselineSeed: true` significa que esta foi a primeira sincronização após a conexão, que apenas registra a lista inicial de seguidores e nunca envia DMs de alcance (portanto, `dmsSent` é sempre `0` nessa execução).

A primeira chamada para uma conta pode levar algum tempo (percorrendo a lista completa de seguidores); chamadas posteriores são mais rápidas, já que apenas os novos seguidores são diferenciados. `404` significa que a conta não está conectada; `412` significa que a conexão ainda não terminou de inicializar - aguarde e tente novamente.

---

## LINE

O LINE é o canal mais simples de conectar, pois não há redirecionamento de navegador ou polling. O cliente cria um canal de Messaging API no console do LINE Developers, copia dois valores e você os envia em uma única chamada. Em seguida, você fornece a ele uma URL de webhook para colar no console.

### Passo 1 - Conectar com as credenciais do canal

```
POST /channels/line
```

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/line?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "channel_access_token": "LONG_LIVED_CHANNEL_ACCESS_TOKEN",
    "channel_secret": "CHANNEL_SECRET"
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/channels/line", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    channel_access_token: "LONG_LIVED_CHANNEL_ACCESS_TOKEN",
    channel_secret: "CHANNEL_SECRET",
  }),
});
const data = await res.json();
```

**Python**

```python
res = requests.post(
    "https://api.youraiconnector.com/v1/channels/line",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "channel_access_token": "LONG_LIVED_CHANNEL_ACCESS_TOKEN",
        "channel_secret": "CHANNEL_SECRET",
    },
)
data = res.json()
```

| Campo | Obrigatório | Descrição |
|---|---|---|
| `channel_access_token` | Sim | O token de acesso de longa duração do canal de Messaging API da Conta Oficial. Usado para enviar e receber mensagens. |
| `channel_secret` | Sim | O segredo do canal de Messaging API, usado para verificar assinaturas de eventos de entrada. |
| `channel_id` | Não | O ID numérico do canal. Apenas informativo. |

**Resposta**

```json
{
  "success": true,
  "status": "connected",
  "bot_user_id": "Uxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "basic_id": "@mybusiness",
  "display_name": "My Business",
  "picture_url": "https://...",
  "chat_mode": "bot",
  "chat_mode_ok": true,
  "webhook_url": "https://api.youraiconnector.com/line/webhook/..."
}
```

Dois campos são importantes para o que você fará a seguir:

- **`webhook_url`** - o cliente deve colar isso no campo **Webhook URL** do canal do LINE no console do LINE Developers (e ativar "Use webhook"). Até que o façam, nenhuma mensagem de entrada chegará. Mostre isso a eles de forma proeminente.
- **`chat_mode_ok`** - quando `false`, a Conta Oficial está no modo "chat" e não receberá nem enviará mensagens até que seja alterada para o modo "bot" no LINE Official Account Manager. Bloqueie seu onboarding com base nesta flag e peça ao cliente para alterar o modo.

> O `channel_access_token` e o `channel_secret` nunca são retornados por nenhum endpoint. Armazene-os do seu lado se precisar deles novamente; caso contrário, cole-os novamente a partir do console do LINE.

O `bot_user_id` retornado aqui é o identificador de conexão que você usa nas chamadas de status, verificação e desconexão abaixo.

### Passo 2 - Reverificar após a configuração do webhook

```
POST /channels/line/{botUserId}/verify-webhook
```

Após o cliente terminar de configurar a URL do webhook e mudar para o modo bot, chame isto para revalidar o token armazenado e atualizar o modo de chat em cache.

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/line/Uxxxxxxxx.../verify-webhook" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Resposta**

```json
{
  "success": true,
  "token_valid": true,
  "chat_mode": "bot",
  "chat_mode_ok": true,
  "webhook_url": "https://api.youraiconnector.com/line/webhook/..."
}
```

Se `token_valid` for `false`, o token de acesso armazenado não autentica mais - peça ao cliente para reemití-lo no console e chamar `POST /channels/line` novamente com o novo token.

### Verificar status do LINE

```
GET /channels/line/{botUserId}/status
```

```bash
curl "https://api.youraiconnector.com/v1/channels/line/Uxxxxxxxx.../status" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Resposta**

```json
{
  "success": true,
  "bot_user_id": "Uxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "channel": "line",
  "status": "connected",
  "basic_id": "@mybusiness",
  "display_name": "My Business",
  "picture_url": "https://...",
  "chat_mode": "bot",
  "is_active": true,
  "live": false
}
```

O LINE não possui um feed de status ao vivo, portanto `live` é sempre `false` aqui - os valores refletem o estado capturado no momento da conexão (ou da última verificação).

### Desconectar LINE

```
DELETE /channels/line/{botUserId}
```

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/channels/line/Uxxxxxxxx..." \
  -H "X-API-Key: YOUR_API_KEY"
```

**Resposta**

```json
{ "success": true, "status": "removed", "bot_user_id": "Uxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }
```

---

## Viber

O Viber conecta da mesma forma que o LINE - cole o token de autenticação do bot do Painel Administrativo do Viber em uma chamada - com uma diferença que vale a pena saber: conectar também REGISTRA nosso webhook no seu bot naquele momento, então não há uma etapa de console separada posteriormente. Isso também significa que uma tentativa de conexão pode falhar se nossa entrada não conseguir responder à verificação síncrona de webhook do Viber, não apenas se o token em si estiver incorreto.

### Passo 1 - Conectar com o token de autenticação do bot

```
POST /channels/viber
```

| Campo | Obrigatório | Descrição |
|---|---|---|
| `auth_token` | Sim | O token de autenticação do bot, do Painel Administrativo do Viber (Configurações do Meu Bot). |

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/viber?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "auth_token": "444d5555e6666f7777a8888b9999c000" }'
```

**Resposta**

```json
{
  "success": true,
  "status": "connected",
  "bot_id": "botIdFromViber",
  "bot_name": "My Business Bot",
  "bot_avatar": "https://...",
  "bot_uri": "mybusinessbot",
  "subscribers_count": 0,
  "webhook_url": "https://api.youraiconnector.com/v1/incoming-viber-message/...",
  "event_types": ["delivered", "seen", "failed", "subscribed", "unsubscribed", "conversation_started"]
}
```

O token de autenticação nunca é retornado por nenhum endpoint - armazene-o do seu lado se precisar colá-lo novamente. `bot_id` é o identificador de conexão usado pelas chamadas de status, verificação e desconexão abaixo.

### Verificar status do Viber

```
GET /channels/viber/{botId}/status
```

Relata o estado da conexão armazenada. Adicione `?live=true` para também verificar novamente o bot no Viber e atualizar o registro do webhook em cache - útil antes de presumir que um bot silencioso está realmente quebrado.

```bash
curl "https://api.youraiconnector.com/v1/channels/viber/botIdFromViber/status?live=true" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Resposta**

```json
{
  "success": true,
  "bot_id": "botIdFromViber",
  "channel": "viber",
  "status": "connected",
  "bot_name": "My Business Bot",
  "bot_avatar": "https://...",
  "bot_uri": "mybusinessbot",
  "webhook_url": "https://api.youraiconnector.com/v1/incoming-viber-message/...",
  "registered_webhook": "https://api.youraiconnector.com/v1/incoming-viber-message/...",
  "webhook_ok": true,
  "subscribers_count": 128,
  "is_active": true,
  "live": true
}
```

`webhook_ok: false` significa que o webhook do bot não aponta mais para nós - as mensagens recebidas estão perdidas. Isso geralmente significa que outra ferramenta conectou o mesmo bot posteriormente (o registro de webhook do Viber segue a regra de "última gravação vence"). Corrija isso com a chamada de re-verificação abaixo, sem necessidade de pedir ao cliente para colar seu token novamente. `live` é `false` quando a resposta é o último estado em cache em vez de uma nova verificação no Viber.

### Registrar novamente o webhook

```
POST /channels/viber/{botId}/verify-webhook
```

A ação de reparo para `webhook_ok: false` - registra novamente nosso webhook no bot usando o token de autenticação já armazenado.

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/viber/botIdFromViber/verify-webhook" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Resposta**

```json
{ "success": true, "token_valid": true, "webhook_ok": true, "webhook_url": "https://api.youraiconnector.com/v1/incoming-viber-message/...", "event_types": ["delivered", "seen", "failed", "subscribed", "unsubscribed", "conversation_started"] }
```

`token_valid: false` significa que o token armazenado não funciona mais - reconecte com `POST /channels/viber` e um novo token.

### Desconectar Viber

```
DELETE /channels/viber/{botId}
```

Cancela o registro do nosso webhook no lado do Viber (melhor esforço) e remove a conexão.

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/channels/viber/botIdFromViber" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Resposta**

```json
{ "success": true, "status": "removed", "bot_id": "botIdFromViber", "webhook_removed": true }
```

---

## TikTok

> **Disponibilidade:** Beta de disponibilidade limitada, habilitado por conta. Conectar o TikTok retorna um erro de permissão até que a conta seja habilitada para isso.

O TikTok Business Messaging é um canal OAuth completo como o Meta, mas mais simples no lado da sondagem (polling): não há uma etapa dedicada de sondagem de status para implementar, pois a conta conectada aparece por conta própria assim que o TikTok redireciona de volta e a conexão é gravada. O endpoint de status abaixo existe para confirmar o estado sob demanda (ferramentas de suporte, verificações de integridade), não como algo em que você precise fazer um loop durante a conexão.

### Passo 1 - Iniciar a conexão com o TikTok

```
POST /channels/tiktok/connect
```

Não requer credenciais - o titular da conta autoriza inteiramente em seu navegador.

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/tiktok/connect?apiKey=YOUR_API_KEY"
```

**Resposta**

```json
{
  "success": true,
  "status": "pending_authorization",
  "oauth_url": "https://www.tiktok.com/v2/auth/authorize?client_key=...&state=...",
  "state_token": "opaque-one-time-token",
  "expires_at": "2026-06-10T12:30:00.000Z"
}
```

Abra `oauth_url` no navegador do titular da conta para que ele possa fazer login no TikTok e aprovar o acesso. O estado expira em `expires_at` (cerca de 30 minutos) - se expirar, comece novamente. Não há atalho de página hospedada `connect_url` para o TikTok; abrir `oauth_url` por conta própria é o único caminho.

### Verificar status do TikTok

```
GET /channels/tiktok/{openId}/status
```

`openId` é o open_id da Conta Comercial do TikTok, conhecido após a execução do callback OAuth.

```bash
curl "https://api.youraiconnector.com/v1/channels/tiktok/openIdFromTikTok/status" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Resposta**

```json
{
  "success": true,
  "open_id": "openIdFromTikTok",
  "channel": "tiktok",
  "status": "connected",
  "business_id": "openIdFromTikTok",
  "username": "mybusiness",
  "display_name": "My Business",
  "avatar_url": "https://...",
  "status_reason": null,
  "is_active": true,
  "live": false
}
```

O TikTok não possui uma verificação de integridade ativa e barata, portanto `live` é sempre `false` aqui - os campos refletem o que a conexão (ou a última atualização de token) gravou. `status: "reauth_required"` com `status_reason` definido significa que a conta precisa passar pela conexão novamente; os tokens do TikTok são atualizados automaticamente em uma rotação anual, e é isso que aparece se essa rotação falhar.

### Desconectar TikTok

```
DELETE /channels/tiktok/{openId}
```

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/channels/tiktok/openIdFromTikTok" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Resposta**

```json
{ "success": true, "status": "removed", "open_id": "openIdFromTikTok" }
```

---

## GoHighLevel

O GoHighLevel (GHL) é uma integração de CRM, não um canal de mensagens - conectá-lo não consome um slot de canal no plano, pois ele utiliza os canais existentes da conta em vez de adicionar um novo. É também a única integração nesta página que pode manter **mais de uma conexão ao mesmo tempo**: cada subconta GHL ("local") na qual o cliente instala o aplicativo recebe sua própria entrada.

### Passo 1 - Iniciar a conexão com o GHL

```
POST /channels/ghl/connect
```

| Campo | Obrigatório | Descrição |
|---|---|---|
| `brand` | Não | Qual listagem do marketplace GHL usar para autorizar. O padrão é a listagem padrão - relevante apenas se sua implantação tiver mais de um aplicativo de marketplace configurado. |

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/ghl/connect?apiKey=YOUR_API_KEY"
```

**Resposta**

```json
{
  "success": true,
  "status": "pending_authorization",
  "oauth_url": "https://marketplace.gohighlevel.com/oauth/chooselocation?client_id=...&state=...",
  "state_token": "opaque-one-time-token",
  "brand": "dmchamp",
  "expires_at": "2026-06-10T12:30:00.000Z"
}
```

Abra `oauth_url` no navegador do titular da conta para que ele possa escolher um local GHL e aprovar o acesso. O estado expira em `expires_at` (cerca de 30 minutos).

### Listar conexões GHL

```
GET /channels/ghl/status
```

Ao contrário de outros canais, este não é o status de uma única conexão - ele lista todos os locais que a conta conectou.

```bash
curl "https://api.youraiconnector.com/v1/channels/ghl/status" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Resposta**

```json
{
  "success": true,
  "connections": [
    {
      "location_id": "abc123location",
      "company_id": "xyz789company",
      "brand": "dmchamp",
      "status": "connected",
      "status_reason": null,
      "scopes": ["conversations.readonly", "conversations.write", "conversations/message.write"],
      "connected_at": "2026-06-01T10:00:00.000Z",
      "conversation_provider_id": "provider-id-in-ghl",
      "trigger_subscriptions": [
        { "id": "sub_1", "key": "InboundMessage", "workflow_id": "wf_123" }
      ]
    }
  ]
}
```

### Desconectar um local GHL

```
DELETE /channels/ghl/{locationId}
```

Exclui a conexão aqui, o que interrompe toda sincronização e gatilho para aquele local. Isso não desinstala o aplicativo no lado do GHL - o cliente o remove de suas instalações do marketplace GHL se desejar isso também.

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/channels/ghl/abc123location" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Resposta**

```json
{ "success": true, "status": "disconnected", "location_id": "abc123location" }
```

---

## Números de telefone (comprar e liberar)

Em vez de conectar um número existente, você pode comprar um novo número compatível com WhatsApp diretamente. Pesquise números disponíveis, compre um e, em seguida, faça o polling até que o provisionamento seja concluído.

::: note
**Nota:** Os números comprados aqui são compatíveis com o WhatsApp. O registro do remetente do WhatsApp é executado em segundo plano após a compra, portanto, você deve verificar o status até que ele atinja `ONLINE` antes de enviar. Os créditos são deduzidos na compra e **não** são reembolsados quando você libera o número.
:::


### Passo 1 - Pesquisar números disponíveis

```
GET /phone-numbers/available?country_code=ISO2
```

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/phone-numbers/available?country_code=US&apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/phone-numbers/available?country_code=US",
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
```

**Python**

```python
res = requests.get(
    "https://api.youraiconnector.com/v1/phone-numbers/available",
    params={"country_code": "US"},
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

| Parâmetro de consulta | Obrigatório | Descrição |
|---|---|---|
| `country_code` | Sim | Código de país ISO 3166-1 alpha-2 para pesquisar (por exemplo, `US`, `GB`, `NL`). |
| `type` | Não | Classe de número preferencial, `local` ou `mobile`. Ambas as classes ainda podem ser retornadas. |

**Resposta**

```json
{
  "success": true,
  "phone_numbers": [
    {
      "phone_number": "+14155551234",
      "purchase_credits": 50,
      "monthly_credits": 50,
      "cost_usd": 1.15
    }
  ]
}
```

Cada resultado mostra o `purchase_credits` único e o `monthly_credits` recorrente. Um número fornecido pela plataforma custa pelo menos 50 créditos por mês, aumentando conforme o preço mensal da própria operadora, cobrado na compra e em cada renovação. Use o `purchase_credits` / `monthly_credits` que a pesquisa retornar; nunca calcule um preço por conta própria. A primeira pesquisa em uma nova conta provisiona alguns recursos subjacentes, por isso pode ser um pouco mais lenta do que as pesquisas subsequentes.

### Passo 2 - Comprar um número

```
POST /phone-numbers
```

Use um `phone_number` dos resultados da pesquisa.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/phone-numbers" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": "+14155551234",
    "country_code": "US",
    "display_name": "Support line"
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/phone-numbers", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    phone_number: "+14155551234",
    country_code: "US",
    display_name: "Support line",
  }),
});
const data = await res.json();
```

**Python**

```python
res = requests.post(
    "https://api.youraiconnector.com/v1/phone-numbers",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "phone_number": "+14155551234",
        "country_code": "US",
        "display_name": "Support line",
    },
)
data = res.json()
```

| Campo | Obrigatório | Descrição |
|---|---|---|
| `phone_number` | Sim | Um número retornado pela pesquisa de números disponíveis, no formato E.164. |
| `country_code` | Sim | Código de país ISO 3166-1 alpha-2 (por exemplo, `US`). |
| `display_name` | Não | Um rótulo amigável. O padrão é o número de telefone. |
| `category` | Não | Rótulo de categoria opcional. |

**Resposta**

```json
{
  "success": true,
  "phone_number": "+14155551234",
  "channel": "whatsapp",
  "whatsapp_status": "PURCHASED",
  "outgoing_status": "PURCHASED",
  "status": "PURCHASED",
  "purchase_credits": 50,
  "monthly_credits": 50
}
```

O número começa no estado `PURCHASED`. O registro no WhatsApp prossegue então em segundo plano: `PURCHASED` -> `PENDING` -> `ONLINE`.

> Se a compra falhar porque um endereço comercial está faltando ou outro detalhe obrigatório não foi definido, você receberá um `400` com uma `error` descritiva. Configure o detalhe ausente e tente novamente.

### Passo 3 - Consultar até ficar ONLINE

```
GET /phone-numbers/{phoneNumber}/status
```

Este é o endpoint de status de número de telefone compartilhado - ele funciona tanto para números do WhatsApp comprados quanto para seus outros números conectados.

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/phone-numbers/+14155551234/status" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const phone = encodeURIComponent("+14155551234");
const res = await fetch(
  `https://api.youraiconnector.com/v1/phone-numbers/${phone}/status`,
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
// Poll until data.status === "ONLINE".
```

**Python**

```python
import urllib.parse

phone = urllib.parse.quote("+14155551234")
res = requests.get(
    f"https://api.youraiconnector.com/v1/phone-numbers/{phone}/status",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
# Poll until data["status"] == "ONLINE".
```

**Resposta**

```json
{
  "success": true,
  "phone_number": "+14155551234",
  "channel": "whatsapp",
  "status": "ONLINE",
  "status_reason": null,
  "live": true
}
```

### Passo 4 - Liberar um número

```
DELETE /phone-numbers/{phoneNumber}
```

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/phone-numbers/+14155551234" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Resposta**

```json
{ "success": true, "phone_number": "+14155551234", "released": true }
```

O que isso faz depende de a quem o número pertence.

Para um número **alugado através da plataforma**, trata-se de uma liberação real: o remetente do WhatsApp é cancelado, o número é devolvido à operadora e removido da conta, um período de resfriamento de 7 dias é aplicado, durante o qual o número não pode ser recomprado por ninguém, e nenhum crédito é reembolsado.

Para um número que **a conta trouxe por conta própria** (sua própria conta Twilio, seu próprio aplicativo Meta ou conta do WhatsApp Business, ou um gateway de SMS Android), a mesma chamada apenas o remove da conta. Nada é liberado no provedor upstream e nenhum período de espera é registrado, portanto, o número pode ser reconectado imediatamente. Seu registro de remetente do WhatsApp, se houvesse um, pode ou não sobreviver: o processo de encerramento tenta excluir o remetente usando as credenciais da Twilio gerenciadas pela plataforma da conta. Em uma conta que ainda está na configuração gerenciada, essas credenciais são válidas e o remetente é excluído, portanto, reconectar significa registrá-lo novamente. Em uma conta que mudou para sua própria Twilio, a exclusão não pode ser autenticada e o remetente permanece registrado nessa conta — reconectar é, então, apenas reanexar o remetente existente.

### Adicionar um número que você já possui (BYO)

```
POST /phone-numbers/byo
```

Pula completamente o fluxo de pesquisa e compra acima. Use isso quando a conta trouxer seu próprio número (seu próprio Twilio, sua própria conta comercial do Meta WhatsApp ou um gateway SMS Android) em vez de alugar um através da plataforma. Isso apenas registra o número - nenhum crédito é cobrado e nada é provisionado com um provedor aqui. O número permanece inativo até que o titular da conta conclua o OAuth do WhatsApp para registrar um Remetente nele (o mesmo fluxo que o botão "Trazer seu próprio número" do painel inicia).

| Campo | Obrigatório | Descrição |
|---|---|---|
| `phone_number` | Sim | O número a ser adicionado, no formato E.164 (por exemplo, `+14155551234`). |
| `country_code` | Sim | Código de país ISO 3166-1 alpha-2 (por exemplo, `US`). |
| `display_name` | Não | Um rótulo amigável. O padrão é o número de telefone. |
| `category` | Não | Rótulo de categoria opcional. |

```bash
curl -X POST "https://api.youraiconnector.com/v1/phone-numbers/byo?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": "+14155551234",
    "country_code": "US",
    "display_name": "Support line"
  }'
```

**Resposta** (`201 Created`):

```json
{
  "success": true,
  "phone_number": "+14155551234",
  "channel": "whatsapp",
  "type": "BYO",
  "whatsapp_status": "ADDED",
  "outgoing_status": "ADDED",
  "is_active": false
}
```

Um `phone_number` que não é um número E.164 real (ou que se parece com o número de teste do WhatsApp da Meta, que nunca pode enviar mensagens para clientes reais) retorna `400`. Adicionar um número que já existe na conta - mesmo escrito de forma ligeiramente diferente, como as formas `+52` vs `+521` do México - retorna `409` em vez de criar uma linha duplicada.

### Definir um número como principal

```
POST /phone-numbers/{phoneNumber}/set-primary
```

Altera um número para `is_active: true` e todos os outros números na conta para `is_active: false`, atomicamente - a conta nunca termina com dois números ativos, ou nenhum, durante a solicitação. `is_active` não pode ser definido através do endpoint de atualização geral de propósito; esta chamada dedicada é a única maneira de alterar qual número é o principal.

```bash
curl -X POST "https://api.youraiconnector.com/v1/phone-numbers/+14155551234/set-primary" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Resposta**

```json
{
  "success": true,
  "phone_number": {
    "id": "+14155551234",
    "phone_number": "+14155551234",
    "display_name": "Support line",
    "channel": "whatsapp",
    "is_active": true,
    "whatsapp_status": "ONLINE"
  }
}
```

`phone_number` aqui é o objeto de número completo (a mesma forma que `GET /phone-numbers` retorna), não apenas a string. Um `phoneNumber` que não está na conta retorna `404`.

### Remover o registro de um número (sem liberá-lo)

```
DELETE /phone-numbers/{phoneNumber}/record
```

Uma exclusão simples do registro do número nesta conta - sem liberação ou cancelamento de registro no lado do provedor, e sem o período de resfriamento de 7 dias como se aplica na etapa de liberação acima. Use isso para limpar registros BYO, WhatsApp Web, Telegram ou LINE, ou uma entrada obsoleta, sem passar pelo fluxo de liberação gerenciada. Ao contrário de uma liberação, excluir um número que não está na conta é um `404`, não um sucesso silencioso.

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/phone-numbers/+14155551234/record" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Resposta**

```json
{ "success": true, "phone_number": "+14155551234", "deleted": true }
```

---

## Direcionar um canal para uma campanha

Conectar um canal traz mensagens **para dentro** da conta. Isso não decide **qual Agente de IA as responderá**.

O roteamento é gerenciado por **Pontos de Entrada** (Entry Points) em um Agente de IA, não por campanhas. Cada canal possui um Ponto de Entrada padrão que nomeia o Agente que responderá a novos contatos desconhecidos nesse canal:

| O que você deseja fazer | Chamada |
|---|---|
| Apontar um canal para o Agente que deve respondê-lo | `PUT /entry-points/channel-defaults` com corpo `{ "channel": "instagram", "agent_id": "AGENT_ID" }` |
| Verificar se a hierarquia de Pontos de Entrada está ativa para a conta | `GET /entry-points/routing-status`, que retorna `{ "success": true, "cutover_enabled": true }` assim que os Pontos de Entrada decidem o roteamento daquela conta |
| Deixar um canal sem nenhum Agente respondendo | `DELETE /entry-points/channel-defaults?channel=instagram` |

Até que um canal tenha um Ponto de Entrada, uma primeira mensagem de alguém com quem você nunca falou ainda é armazenada, mas nada a processa e nenhum assistente responde. Este é o passo que a maioria das integrações perde: conectar o Instagram e criar um Agente não é suficiente por si só — você também precisa apontar o canal para o Agente. O conjunto completo de chamadas — incluindo um Agente por número de WhatsApp, palavras-chave e regras de comentários — está na [API de Pontos de Entrada](entry-points.md).

`POST /channels/campaign` ainda grava o mapa de roteamento de campanha legado por canal, documentado abaixo, mas esse mapa não é mais consultado para roteamento de entrada em nenhuma conta; ele é mantido apenas para reversão. Não desenvolva com base nele.

### Roteamento de um ou mais canais (mapa de roteamento de campanha legado)

`POST /channels/campaign`

**Campos da requisição**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `campaign_id` | Sim | A campanha que deve responder a novos contatos nesses canais. Deve pertencer à conta. |
| `channels` | Sim | Uma matriz não vazia de canais para direcionar. Permitidos: `whatsapp`, `whatsapp_web`, `telegram`, `instagram`, `messenger`, `chat_widget`, `custom_channel`, `sms`, `email`. |

O slot de direcionamento e a lista de `enabled_channels` da campanha são atualizados juntos em uma operação atômica, para que nunca fiquem desalinhados. Um canal já direcionado para uma campanha diferente é simplesmente redirecionado para esta.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/campaign?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "campaign_id": "NBCXrhqGPSFsd6MV7pRo",
    "channels": ["instagram", "messenger"]
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/channels/campaign", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    campaign_id: "NBCXrhqGPSFsd6MV7pRo",
    channels: ["instagram", "messenger"],
  }),
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/channels/campaign",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "campaign_id": "NBCXrhqGPSFsd6MV7pRo",
        "channels": ["instagram", "messenger"],
    },
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "campaign_id": "NBCXrhqGPSFsd6MV7pRo",
  "channels": ["instagram", "messenger"]
}
```

### O que precisa ser verdadeiro para o direcionamento realmente funcionar

Em uma conta que ainda lê o mapa de roteamento de campanha legado, o roteamento é bem-sucedido como uma chamada de API, mas três coisas na campanha decidem se uma mensagem de entrada real será respondida. Verifique todas as três quando um canal roteado permanecer em silêncio.

| Requisito | O que acontece caso contrário |
|---|---|
| `type` é `Incoming from Unknown Contacts` ou `Combined` | A solicitação é rejeitada com `400`. Campanhas de Saída e Palavras-chave não podem ocupar um slot de roteamento. |
| `status` é `Live` | O roteamento é armazenado, mas nunca captura nada. Uma campanha `Draft` é a causa mais comum de "Eu roteei e nada acontece". |
| `ai_mode` é `true` | O contato é criado e a mensagem armazenada, mas o assistente nunca responde. |

A correspondência de palavras-chave agora reside nos Pontos de Entrada — crie um Ponto de Entrada do tipo `keyword` no Agente de IA que deve responder.

### Uma campanha por canal

Cada canal possui exatamente um slot de roteamento legado. Roteamento de uma segunda campanha para o mesmo canal aponta silenciosamente o slot novamente e retorna `200` — não há erro de conflito. A campanha anterior continua lidando com os contatos que já possui; ela apenas para de receber novos.

### Limpar o roteamento de um canal

`DELETE /channels/campaign/{channel}`

Remove o roteamento de um canal específico, independentemente da campanha para a qual ele aponta atualmente, e remove o canal da `enabled_channels` dessa campanha. Novos contatos desconhecidos no canal não serão mais capturados por nenhuma campanha. Contatos que já estão na campanha continuam como antes.

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/channels/campaign/instagram?apiKey=YOUR_API_KEY"
```

**Resposta**

```json
{
  "success": true,
  "channel": "instagram",
  "cleared": true,
  "campaign_id": "NBCXrhqGPSFsd6MV7pRo"
}
```

É idempotente: limpar um canal que nunca foi roteado também retorna `200`, com `cleared: false` e `campaign_id: null`. Este endpoint requer o recurso de **campanhas de entrada** no plano; sem ele, você receberá um `403`.


---

## Use seu próprio aplicativo Meta (Instagram + Messenger)

Por padrão, a conexão do Instagram + Messenger é executada através do aplicativo Meta da plataforma, portanto, o nome desse aplicativo é o que o titular da conta vê na tela de consentimento do Facebook. Se você quiser que a tela de consentimento mostre a **sua** marca, você pode registrar seu próprio aplicativo Meta e rotear todo o fluxo através dele. Uma vez configurado, isso se aplica à sua conta — nada muda nas chamadas de conexão acima, exceto a marca.

> **Isso cobre apenas Instagram + Messenger.** As conexões do WhatsApp, WhatsApp Web, Telegram e LINE não são afetadas por um aplicativo Meta personalizado.

### O que seu aplicativo precisa primeiro

Esta é a parte que leva tempo, e acontece inteiramente do lado da Meta:

1. **Um aplicativo** do tipo Business, com os produtos Messenger e Instagram adicionados.
2. **Acesso Avançado** (via Meta App Review) para: `pages_show_list`, `pages_messaging`, `pages_manage_metadata`, `pages_read_engagement`, `instagram_basic`, `instagram_manage_messages`. Sem o Acesso Avançado, apenas pessoas que possuem uma função no seu aplicativo podem concluir a conexão — as conexões dos seus clientes falharão. A Análise de Aplicativo geralmente leva algumas semanas e requer a Verificação Comercial.
3. **Uma configuração de Login do Facebook para Empresas** criada dentro do seu aplicativo, concedendo as mesmas permissões. Seu ID de configuração numérico é por aplicativo, portanto, você deve criar o seu próprio.

Se o seu aplicativo não tiver nenhuma das permissões necessárias, a conexão falhará no momento da conexão com um erro claro nomeando o que está faltando (visível no poll `/status` como `byo_app_missing_permissions`) — em vez de parecer funcionar e falhar na primeira mensagem.

### Passo 1 - Salve seu aplicativo

`PUT /account-config/meta-app`

| Campo | Obrigatório | Descrição |
|---|---|---|
| `app_id` | Sim | Seu ID de Aplicativo Meta (Configurações → Básico). |
| `app_secret` | Sim | Seu Segredo de Aplicativo Meta. Verificado com a Meta antes de ser armazenado, depois criptografado. Nunca retornado por nenhum endpoint. |
| `config_id` | Sim | O ID numérico da configuração de Login do Facebook para Empresas dentro do seu aplicativo. |

Todos os três são necessários para o fluxo de Login do Facebook. Se você executar apenas a via de envio de token de Login do Instagram descrita abaixo, você pode deixá-los de fora completamente.

```bash
curl -X PUT "https://api.youraiconnector.com/v1/account-config/meta-app?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "app_id": "1234567890123456",
    "app_secret": "your-app-secret",
    "config_id": "9876543210987654"
  }'
```

**Resposta**

```json
{
  "success": true,
  "app_id": "1234567890123456",
  "config_id": "9876543210987654",
  "verify_token": "1f4c…a9",
  "webhook_urls": {
    "instagram": "https://api.youraiconnector.com/v1/incoming-instagram-message/byo/YOUR_ACCOUNT_ID",
    "messenger": "https://api.youraiconnector.com/v1/incoming-messenger-message/byo/YOUR_ACCOUNT_ID"
  }
}
```

### Passo 2 - Configure seu aplicativo para se comunicar conosco

No painel do seu aplicativo Meta:

1. **Webhooks** - para os produtos Instagram e Messenger, defina a URL de Callback para o valor `webhook_urls` correspondente da resposta, e o token de Verificação para `verify_token`. Inscreva-se nos campos `messages`, `messaging_postbacks` e `comments`.
2. **URIs de Redirecionamento OAuth Válidas** - adicione `https://api.youraiconnector.com/v1/auth-meta-callback-handler` para que o fluxo de consentimento possa retornar.

`GET /account-config/meta-app` retorna o mesmo material de configuração a qualquer momento; `DELETE /account-config/meta-app` remove o aplicativo (conexões futuras revertem para o aplicativo da plataforma — remova também a assinatura do webhook dentro do seu aplicativo).

### Passo 3 - Conecte-se como de costume

Nada mais muda. O `POST /channels/meta/connect` (e a página `connect_url` hospedada) usa automaticamente seu aplicativo para sua conta; o `uses_byo_meta_app: true` da resposta confirma qual aplicativo a tela de consentimento mostrará. O envio de mensagens, a seleção de páginas e as desconexões funcionam de forma idêntica.

## Traga seu próprio aplicativo de Login do Instagram (push de token)

A seção acima aborda o fluxo de Login do Facebook, onde a conta se conecta por meio de uma Página do Facebook. A Meta também oferece a **API do Instagram com Login do Instagram** (Login Comercial para Instagram): o titular da conta se autentica no próprio Instagram, sem envolver uma conta ou Página do Facebook.

Se sua plataforma já executa seu próprio aplicativo da Meta com esse produto, você não precisa de nenhum fluxo OAuth do nosso lado. Seus clientes autorizam **seu** aplicativo, e você nos envia a credencial finalizada por conta:

1. Você salva as credenciais do seu aplicativo do Instagram uma vez (para que possamos verificar seus webhooks).
2. Por conta, você envia o ID da conta profissional do Instagram + o token de usuário do Instagram de longa duração que seu aplicativo obteve.
3. Você aponta o webhook de mensagens do Instagram do seu aplicativo para nós. Eventos para contas que você nunca enviou são reconhecidos e ignorados.
4. Você é o proprietário do ciclo de vida do token: atualize os tokens em seu próprio sistema e envie cada token atualizado com a mesma chamada. Nós nunca atualizamos um token enviado.

### O que seu aplicativo precisa primeiro

- O produto **Instagram** ("Configuração de API com login do Instagram") adicionado ao seu aplicativo da Meta. Esse produto tem seu **próprio par de ID do Aplicativo e Segredo do Aplicativo**, separado do ID/Segredo do Aplicativo do Facebook — encontre-os no painel de configuração do produto.
- **Acesso Avançado** (via Revisão de Aplicativo da Meta) para `instagram_business_basic` e `instagram_business_manage_messages` (adicione `instagram_business_manage_comments` se você usar automações de comentários). Sem isso, apenas pessoas com uma função no seu aplicativo podem autorizá-lo.

### Passo 1 - Salve as credenciais do seu aplicativo do Instagram

O mesmo endpoint de antes — envie o par do Instagram para `PUT /account-config/meta-app`. Os campos do Facebook não são necessários para esta via: envie o par sozinho se o Login do Instagram for tudo o que você executa, ou junto com os campos do Facebook se você executar ambos. Um salvamento sempre descreve a configuração completa, portanto, qualquer conjunto que você deixar de fora será removido.

| Campo | Obrigatório | Descrição |
|---|---|---|
| `instagram_app_id` | Juntos | O ID do Aplicativo numérico do próprio produto Instagram (não o ID do Aplicativo do Facebook). |
| `instagram_app_secret` | Juntos | O Segredo do Aplicativo do próprio produto Instagram. Criptografado em repouso, nunca retornado. |

```bash
curl -X PUT "https://api.youraiconnector.com/v1/account-config/meta-app?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "instagram_app_id": "1122334455667788",
    "instagram_app_secret": "your-instagram-app-secret"
  }'
```

**Resposta** — carrega a URL do webhook de Login do Instagram (as URLs `instagram` e `messenger` só aparecem quando os campos do Facebook também são armazenados):

```json
{
  "success": true,
  "instagram_app_id": "1122334455667788",
  "verify_token": "1f4c…a9",
  "webhook_urls": {
    "instagram_login": "https://api.youraiconnector.com/v1/incoming-instagram-login-message/byo/YOUR_ACCOUNT_ID"
  }
}
```

No painel de **Webhooks** do seu aplicativo para o produto Instagram, defina a URL de Callback como `webhook_urls.instagram_login`, o token de Verificação como `verify_token` e inscreva-se nos campos `messages` e `comments`.

### Passo 2 - Envie um token por conta

`PUT /channels/instagram-login/token`

Funciona com `sub_account_id` como qualquer outra rota, para que uma chave de agência possa provisionar toda a sua frota.

| Campo | Obrigatório | Descrição |
|---|---|---|
| `ig_user_id` | Sim | O **ID da conta profissional do Instagram** — o campo `user_id` de `GET https://graph.instagram.com/v21.0/me?fields=user_id,username`. Este é o mesmo ID que os webhooks do Instagram carregam como `entry.id`. ⚠️ **Não** é o campo `id` de `/me` — esse é limitado ao aplicativo e difere por aplicativo da Meta. Enviar o ID limitado ao aplicativo retorna um `400` indicando o erro. |
| `access_token` | Sim | O token de usuário do Instagram de longa duração que seu aplicativo obteve para essa conta. Validado ao vivo no Instagram antes de ser armazenado: o token deve funcionar e deve pertencer a `ig_user_id`. |
| `expires_at` | Não | Expiração ISO-8601 do token. Alternativamente, envie `expires_in` (segundos). O padrão é 60 dias. |
| `username` | Não | O @handle da conta; nós o lemos do Instagram de qualquer maneira. |

```bash
curl -X PUT "https://api.youraiconnector.com/v1/channels/instagram-login/token?apiKey=YOUR_AGENCY_KEY&sub_account_id=CLIENT_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "ig_user_id": "17841400000000000",
    "access_token": "IGAAR…",
    "expires_at": "2026-11-01T00:00:00Z"
  }'
```

**Resposta**

```json
{
  "success": true,
  "ig_user_id": "17841400000000000",
  "username": "acme.studio",
  "expires_at": "2026-11-01T00:00:00.000Z",
  "webhook_url": "https://api.youraiconnector.com/v1/incoming-instagram-login-message/byo/YOUR_ACCOUNT_ID"
}
```

Como parte do envio, inscrevemos seu aplicativo nos webhooks dessa conta (`subscribed_apps` com o token enviado), para que as mensagens comecem a fluir sem qualquer chamada extra do seu lado.

**Atualizando** - envie o token atualizado para o mesmo endpoint com o mesmo `ig_user_id`; isso atualiza o token armazenado e a expiração no local.

**Conflitos** - uma conta do Instagram nunca está ativa em duas conexões. Se a conta já estiver conectada em outro lugar, ou nesta mesma conta através do fluxo da Página do Facebook, o push retorna um `409` informando qual conexão desconectar primeiro. Uma conexão via fluxo do Facebook nunca é substituída automaticamente, pois ela também pode estar servindo o Messenger.

### Passo 3 - Desconecte quando um cliente sair

`DELETE /channels/instagram-login/token` (mesma autenticação e `sub_account_id`) cancela a inscrição dos webhooks da melhor forma possível e remove a credencial armazenada. Isso sempre é bem-sucedido, mesmo quando o token já expirou — e, uma vez que a credencial é removida, os eventos de webhook daquela conta são ignorados.

---

## Dicas para criar um wrapper confiável

- **Faça polling suavemente.** A cada poucos segundos é o suficiente. Pare assim que atingir um estado terminal (`connected` / `ONLINE`, ou um status de falha) e coloque um tempo limite geral sensato no loop (as etapas do navegador/QR expiram, veja cada `expires_at`).
- **Codifique números de telefone em URL no caminho.** O `+` inicial deve ser enviado como `%2B`. Os endpoints recuperam dígitos puros também, mas a codificação é o padrão seguro.
- **Nunca espere segredos de volta.** Tokens de acesso, segredos de canal e tokens de página são aceitos ou armazenados, mas nunca retornados em nenhuma resposta.
- **Lide com o bloqueio de autenticação.** Um `403` significa que o acesso à API não está no plano, ou que o canal que você está conectando não está incluído no plano da conta. Veja [Acesso à API](../integrations/api-access.md).
- **Respeite o limite de taxa.** Solicitações autenticadas são limitadas a 300 por minuto; um `429` significa que você deve aguardar e tentar novamente. Veja [Autenticação](authentication.md).

## Próximos passos

- [Autenticação](authentication.md) - as quatro formas de autenticação aceitas e o formato de erro.
- [Acesso à API](../integrations/api-access.md) - gerando e gerenciando sua chave de API.
