
# API de Modelos do WhatsApp

Os modelos de mensagem do WhatsApp são mensagens pré-escritas que foram aprovadas para envio fora da janela normal de conversação de 24 horas — por exemplo, uma mensagem de boas-vindas, um lembrete de agendamento ou um aviso de reengajamento. Esta API permite listar, criar, editar, enviar, verificar e excluir modelos programaticamente.

Todos os caminhos abaixo são relativos à URL base da API:

```
https://api.youraiconnector.com/v1
```

Toda solicitação deve ser autenticada. Consulte [Autenticação](authentication.md) para os quatro métodos aceitos. Os exemplos nesta página usam o cabeçalho `X-API-Key` (e uma forma de parâmetro de consulta para cURL).

::: note
**Nota:** Os modelos operam no canal da API do WhatsApp Business, portanto, esta parte da API requer acesso à API e um plano que inclua canais do WhatsApp. Sem eles, as solicitações serão rejeitadas com um `403`.
:::


---

## Trabalhando com subcontas (agências)


---

## Estados de aprovação

Como as mensagens enviadas fora de uma conversa aberta devem ser revisadas pelo WhatsApp primeiro, cada modelo possui um `status` de aprovação:

| Status | Significado |
|---|---|
| `draft` | Criado ou salvo, mas ainda não enviado para revisão. Você ainda pode editá-lo. |
| `received` | Enviado e aceito na fila de revisão. |
| `pending` | Em revisão. |
| `approved` | Liberado para envio. |
| `rejected` | Rejeitado. O campo `rejection_reason` explica o motivo; corrija-o e envie novamente. |

Apenas modelos `draft` e `rejected` podem ser editados ou (re)enviados. Uma vez que um modelo esteja `approved`, ele é bloqueado — crie um novo se precisar de alterações.

> **Aprovação automática:** Alguns canais não exigem uma etapa de revisão externa. Modelos criados ou enviados para uma campanha em tal canal são armazenados como `approved` imediatamente, sem um ID de conteúdo (`sid`).

---

## Modelos em contas conectadas ao Meta

Estes endpoints funcionam da mesma maneira, independentemente da conexão do WhatsApp que sua conta utiliza, mas o que acontece por trás deles é diferente:

- Em uma **conexão gerenciada do WhatsApp**, os modelos são registrados no provedor de mensagens e `sid` é o ID de conteúdo do provedor (`HXXXXXXXX…`).
- Em uma conta cujo número opera em sua **própria Conta Comercial do WhatsApp** (qualquer uma das opções de conexão Meta), os modelos são criados e revisados **nessa Conta Comercial do WhatsApp** e `sid` é o ID de modelo da própria Meta — uma string numérica como `"3394843740694756"`. `status` ainda utiliza os valores na tabela acima, e `rejection_reason` ainda carrega a explicação da Meta.

Dois endpoints extras existem para isso: um para perguntar em qual conexão você está e outro para reconciliar sua lista de modelos com sua Conta Comercial do WhatsApp. Os modelos que já existem na Conta Comercial do WhatsApp são importados para sua biblioteca pela sincronização, portanto, um `GET /whatsapp-templates` posterior os lista como qualquer outro modelo.

### Verificar em qual conexão os modelos são executados

`GET /whatsapp-templates/provider`

| Campo | Descrição |
|---|---|
| `provider` | `twilio` quando os modelos são registrados no provedor de mensagens gerenciado, `meta` quando eles residem em sua própria Conta Comercial do WhatsApp. |
| `lane` | Qual conexão Meta está em uso — `meta_cloud_api` (seu próprio aplicativo Meta) ou `meta_embedded` (conectado através do nosso aplicativo Meta). `null` em uma conexão gerenciada. |
| `waba_id` | A Conta Comercial do WhatsApp na qual os modelos são criados, ou `null`. |
| `templates_enabled` | `false` quando a conexão Meta ainda não foi concluída (sem Conta Comercial do WhatsApp ou token de acesso armazenado). A criação ou envio de modelos falhará com um `400` até que isso seja feito. |

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/whatsapp-templates/provider?apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/whatsapp-templates/provider", {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/whatsapp-templates/provider",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "provider": "meta",
  "lane": "meta_cloud_api",
  "waba_id": "2357661648036355",
  "templates_enabled": true
}
```

### Sincronizar modelos do Meta

Atualiza o status de aprovação de cada modelo que reside em sua Conta Comercial do WhatsApp e importa qualquer modelo que exista lá, mas que ainda não esteja em sua biblioteca. É seguro chamar quantas vezes desejar. Em uma conexão gerenciada, não há nada para sincronizar, portanto, a chamada não faz nada e simplesmente informa quantos modelos você possui.

`POST /whatsapp-templates/meta-sync`

| Campo | Descrição |
|---|---|
| `imported` | Modelos encontrados na Conta Comercial do WhatsApp que foram adicionados à sua biblioteca por esta chamada. |
| `updated` | Modelos existentes cujo status ou detalhes foram alterados. |
| `total` | Modelos em sua biblioteca após a sincronização. |

**cURL**

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

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/whatsapp-templates/meta-sync", {
  method: "POST",
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/whatsapp-templates/meta-sync",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "provider": "meta",
  "imported": 2,
  "updated": 5,
  "total": 12
}
```

### Falar diretamente com o Meta (avançado)

Se você precisar de algo que os endpoints acima não expõem — cabeçalhos, rodapés, botões de modelo ou um modelo totalmente criado manualmente — o `/v1/meta-templates` encaminha sua solicitação diretamente para a API de modelos da Meta, sem armazenar nada em sua biblioteca de modelos. Isso só funciona em contas cujo número opera em sua própria Conta Comercial do WhatsApp; em uma conexão gerenciada, cada chamada retorna `400` solicitando que você conecte um aplicativo Meta primeiro.

| Endpoint | O que faz |
|---|---|
| `GET /meta-templates` | Lista os modelos em sua Conta Comercial do WhatsApp com seu status mais recente. Adicione `?name=` para filtrar por um nome de modelo exato. Retorna `{ "success": true, "templates": [...] }`. |
| `POST /meta-templates` | Cria um modelo e o envia para revisão da Meta em uma única etapa. Requer `name`, `language` e `body` (ou um array `components` completo em vez de `body`). Opcional: `variables` (array de strings), `category` (`MARKETING`, `UTILITY` ou `AUTHENTICATION`), `header`, `footer`, `buttons`. Retorna `201` com `{ "success": true, "template": {...} }`. |
| `DELETE /meta-templates/{name}` | Exclui o modelo pelo seu nome Meta — **todos os idiomas** dele. Adicione `?hsm_id=` com o ID de modelo da Meta para remover um único idioma. Retorna `{ "success": true, "name": "..." }`. |

Um modelo que a Meta recusa retorna `400` com a explicação da própria Meta em `error`.

---

## Listar modelos

Retorna todos os modelos em sua conta, com um resumo leve de cada um.

`GET /whatsapp-templates`

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/whatsapp-templates?apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/whatsapp-templates", {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/whatsapp-templates",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "data": [
    {
      "id": "template_abc123",
      "name": "welcome_message",
      "status": "approved",
      "language": "en",
      "body": "Hi {{first_name}}, thanks for reaching out!"
    },
    {
      "id": "template_def456",
      "name": "appointment_reminder",
      "status": "pending",
      "language": "en",
      "body": "Hi {{first_name}}, this is a reminder about your appointment."
    }
  ]
}
```

---

## Obter um modelo

Retorna os detalhes completos de um único modelo, incluindo suas variáveis, status e carimbos de data/hora.

`GET /whatsapp-templates/{templateId}`

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123",
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "template": {
    "id": "template_abc123",
    "name": "welcome_message",
    "body": "Hi {{first_name}}, thanks for reaching out!",
    "language": "en",
    "variables": ["first_name"],
    "status": "approved",
    "sid": "HXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "type": "general",
    "category": "marketing",
    "rejection_reason": null,
    "campaign_id": "campaign123",
    "date_created": "2026-06-01T10:00:00.000Z",
    "date_updated": "2026-06-02T08:30:00.000Z",
    "submitted_at": "2026-06-01T10:05:00.000Z",
    "approved_at": "2026-06-02T08:30:00.000Z"
  }
}
```

Um modelo que não existe em sua conta retorna `404` com `{ "success": false, "error": "Template not found" }`.

---

## Criar um modelo

Cria um modelo para a mensagem de abertura de uma campanha e o envia para aprovação em uma única etapa.

`POST /whatsapp-templates`

| Campo | Obrigatório | Descrição |
|---|---|---|
| `campaign_id` | Sim | A campanha à qual o modelo pertence. |
| `name` | Sim | Um nome para o modelo. |
| `language` | Sim | Código do idioma, por exemplo `en`, `es`, `de`, `pt_BR`, `zh_CN`. |
| `body` | Sim | O texto da mensagem, com até 1024 caracteres. |
| `variables` | Não | Lista ordenada de nomes de variáveis usados no corpo. |

Os espaços reservados de variáveis podem ser escritos como `{{first_name}}`, `{first_name}` ou `[first_name]` — todos são normalizados para o formato de chaves duplas.

O resultado depende dos canais da campanha:

- **Campanha da API do WhatsApp Business:** o conteúdo é enviado para revisão do WhatsApp. A resposta contém `campaign_status` (`received` ou `pending`) e um `template_sid`.
- **Um canal sem etapa de revisão externa:** o modelo é armazenado e aprovado automaticamente (`campaign_status: "approved"`, `template_sid: null`).
- **Sem canal do WhatsApp na campanha:** nada é criado e `campaign_status` é `not_applicable`.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/whatsapp-templates?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "campaign_id": "campaign123",
    "name": "welcome_message",
    "language": "en",
    "body": "Hi {{first_name}}, thanks for reaching out!",
    "variables": ["first_name"]
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/whatsapp-templates", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    campaign_id: "campaign123",
    name: "welcome_message",
    language: "en",
    body: "Hi {{first_name}}, thanks for reaching out!",
    variables: ["first_name"],
  }),
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/whatsapp-templates",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "campaign_id": "campaign123",
        "name": "welcome_message",
        "language": "en",
        "body": "Hi {{first_name}}, thanks for reaching out!",
        "variables": ["first_name"],
    },
)
data = res.json()
```

**Resposta** (enviado para revisão)

```json
{
  "success": true,
  "campaign_status": "pending",
  "template_sid": "HXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
```

---

## Criar um modelo independente

Cria um modelo em sua biblioteca de modelos sem vinculá-lo à mensagem de abertura de uma campanha. Esta é a etapa de criação do ciclo de vida que o restante desta página segue: crie-o aqui, edite-o, envie-o para revisão, verifique seu status e exclua-o quando não precisar mais dele.

`POST /whatsapp-templates/docs`

| Campo | Obrigatório | Descrição |
|---|---|---|
| `name` | Sim | Um nome para o modelo. |
| `language` | Sim | Código do idioma, por exemplo `en`, `es`, `de`, `pt_BR`, `zh_CN`. |
| `body` | Sim | O texto da mensagem, com até 1024 caracteres. |
| `variables` | Não | Lista ordenada de nomes de variáveis usados no corpo. |
| `status` | Não | `draft` (padrão) armazena sem enviar; `submitted` coloca na fila para revisão do WhatsApp imediatamente. |
| `type` | Não | `general` (padrão) ou `smart_followup`. |
| `category` | Não | `marketing`, `utility`, `authentication` ou `authentication-international`. |
| `campaign_id` | Não | Vincula o modelo a uma de suas campanhas. |

> **Modelos de autenticação (código único).** O WhatsApp não aceita modelos de autenticação de texto livre: o corpo da mensagem é predefinido pelo WhatsApp e o modelo deve conter um botão de "copiar código". Quando você cria um modelo com `category: "authentication"`, nós o enviamos nesse formato fixo para você. O seu `body` é mantido como a prévia exibida no aplicativo, mas o texto que seu contato recebe é a redação do próprio WhatsApp (o código, um lembrete de segurança e uma nota de expiração de 10 minutos). Declare exatamente uma variável, por exemplo `["code"]`, e passe o código ao enviar (consulte o campo `variables` em [Enviar um modelo para um contato](#send-a-template-to-a-contact)). O código deve ter menos de 15 caracteres.

> **Qual criação devo usar?** Use esta quando quiser um modelo que você mesmo possa editar e enviar. Use `POST /whatsapp-templates` (acima) quando quiser definir a mensagem de abertura de uma campanha — essa requer `campaign_id` e escreve diretamente na campanha.

Um modelo criado como `submitted` é enviado para revisão do WhatsApp em segundo plano, portanto, verifique o endpoint de status para obter o resultado em vez de esperar por ele na resposta.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/whatsapp-templates/docs?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "welcome_message",
    "language": "en",
    "body": "Hi {{first_name}}, thanks for reaching out!",
    "variables": ["first_name"],
    "status": "draft",
    "category": "marketing"
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/whatsapp-templates/docs", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    name: "welcome_message",
    language: "en",
    body: "Hi {{first_name}}, thanks for reaching out!",
    variables: ["first_name"],
    status: "draft",
    category: "marketing",
  }),
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/whatsapp-templates/docs",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "name": "welcome_message",
        "language": "en",
        "body": "Hi {{first_name}}, thanks for reaching out!",
        "variables": ["first_name"],
        "status": "draft",
        "category": "marketing",
    },
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "template_id": "template_abc123",
  "status": "draft"
}
```

Um `name`, `language` ou `body` ausente, um idioma não suportado, um `status` diferente de `draft` ou `submitted`, um `type` ou `category` desconhecido, ou um corpo com mais de 1024 caracteres retorna `400` com uma `error` explicativa. Um `campaign_id` que não seja uma de suas campanhas retorna `404`.

---

## Atualizar um modelo

Edita um modelo que ainda não foi aprovado. Apenas modelos com status `draft` ou `rejected` podem ser editados. Forneça qualquer combinação de `name`, `body`, `language` e `variables` — apenas os campos que você enviar serão alterados.

`PUT /whatsapp-templates/{templateId}`

> A edição **não** reenvia o modelo para análise. Use o endpoint de envio posteriormente.

**cURL**

```bash
curl -X PUT "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "body": "Hi {{first_name}}, here is an update for you.",
    "variables": ["first_name"]
  }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123",
  {
    method: "PUT",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      body: "Hi {{first_name}}, here is an update for you.",
      variables: ["first_name"],
    }),
  }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.put(
    "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "body": "Hi {{first_name}}, here is an update for you.",
        "variables": ["first_name"],
    },
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "template_id": "template_abc123"
}
```

Tentar editar um modelo que já está `approved` (ou que não pode ser editado), não enviar campos ou enviar um valor inválido retorna `400` com uma `error` explicativa.

---

## Enviar um modelo para aprovação

Envia um modelo `draft` ou `rejected` para análise. Modelos em um canal que não exige análise externa são aprovados imediatamente; todos os outros são enviados ao WhatsApp e o `status` retornado (geralmente `received` ou `pending`) é armazenado no modelo.

`POST /whatsapp-templates/{templateId}/submit`

> **Modelos de acompanhamento** devem declarar e usar suas variáveis obrigatórias antes de poderem ser enviados: um placeholder de primeiro nome, além de um placeholder de contexto pessoal para acompanhamentos inteligentes.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/submit" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/submit",
  { method: "POST", headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/submit",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "template_id": "template_abc123",
  "status": "pending",
  "sid": "HXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
```

---

## Verificar status de aprovação

Um endpoint leve para consultar o status atual de um modelo. O status é lido a partir do registro armazenado, que é atualizado periodicamente em segundo plano, portanto, uma aprovação ou rejeição muito recente pode levar um pouco de tempo para aparecer.

`GET /whatsapp-templates/{templateId}/status`

**cURL**

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

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/status",
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/status",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "template_id": "template_abc123",
  "name": "welcome_message",
  "status": "approved",
  "sid": "HXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "rejection_reason": null,
  "date_updated": "2026-06-02T08:30:00.000Z"
}
```

---

## Excluir um modelo

Remove o registro do modelo da sua conta.

`DELETE /whatsapp-templates/{templateId}`

::: warning
**Importante:** Em uma conexão gerenciada, apenas o registro armazenado é removido — o conteúdo que o WhatsApp já aprovou pode permanecer registrado no provedor de mensagens. Em uma conta que utiliza sua própria Conta do WhatsApp Business, o modelo também é excluído dessa conta. De qualquer forma, se uma campanha ainda utilizar este modelo, redirecione essa campanha para outro modelo **antes** de excluir, caso contrário, os envios que dependem dele falharão.
:::


**cURL**

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

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123",
  { method: "DELETE", headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.delete(
    "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "template_id": "template_abc123",
  "note": "The template record was removed from your account. Content already approved by WhatsApp may remain registered with the messaging provider."
}
```

---

## Enviar um modelo para um contato

Envia um modelo aprovado para um contato, mesmo quando não há uma conversa aberta — isso reabre a sessão de chat. Você pode direcionar o contato por `contactId` ou por `phoneNumber`, e escolher o modelo por `whatsappTemplateId` ou por `templateName`.

`POST /whatsapp-templates/send`

| Campo | Obrigatório | Descrição |
|---|---|---|
| `contactId` | Um destes dois | O ID do contato. |
| `phoneNumber` | Um destes dois | O número de telefone do contato (com código do país, sem espaços). Pesquisado ou criado, se necessário. |
| `whatsappTemplateId` | Um destes dois | O ID do modelo. |
| `templateName` | Um destes dois | O nome do modelo, conforme exibido no aplicativo. |
| `firstName` | Não | Usado para preencher um contato recém-criado. |
| `lastName` | Não | Usado para preencher um contato recém-criado. |
| `email` | Não | Usado para preencher um contato recém-criado. |
| `variables` | Não | Valores explícitos para as variáveis do modelo, indexados pelo nome da variável, por exemplo `{ "code": "482913" }`. Um valor fornecido aqui prevalece sobre os campos do contato para essa variável; as variáveis que você omitir ainda serão preenchidas a partir do contato, conforme descrito abaixo. É assim que você passa um código único para um modelo de autenticação. |

O corpo do modelo suporta substituição avançada de variáveis:

- **Variáveis básicas:** `{{first_name}}`, `{{email}}`, `{{company}}`
- **Valores padrão:** `{{first_name|there}}` exibe `there` se o campo estiver vazio
- **Transformações:** `{{company|uppercase}}`, `{{name|lowercase}}`, `{{name|capitalize}}`
- **Combinado:** `{{company|Your Company|uppercase}}`

> **Créditos:** O envio de um modelo consome créditos. O custo exato depende do país do destinatário e da categoria do modelo.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/whatsapp-templates/send?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contactId": "contact123",
    "whatsappTemplateId": "template_abc123"
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/whatsapp-templates/send", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    contactId: "contact123",
    whatsappTemplateId: "template_abc123",
  }),
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/whatsapp-templates/send",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "contactId": "contact123",
        "whatsappTemplateId": "template_abc123",
    },
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "data": "WhatsApp template message sent successfully"
}
```

Uma solicitação sem um identificador de contato e sem ambos os identificadores de modelo retorna `400`. Se sua conta não tiver as credenciais de mensagens necessárias para enviar, a resposta será `403`.

---

## Criar ou atualizar o modelo ativo de uma campanha

Um segundo par de endpoints para o modelo de abertura de uma campanha, delimitado por caminho em vez de um `campaign_id` no corpo. Estes são os que devem ser usados para uma campanha que já está ativa: ao contrário de [Criar um modelo](#create-a-template) acima, a atualização aqui também reenvia os rascunhos de acompanhamento da campanha para revisão, para que o modelo de abertura e seus acompanhamentos permaneçam sincronizados.

`POST /whatsapp-templates/campaign/{campaignId}` cria o modelo de abertura da campanha. `PUT /whatsapp-templates/campaign/{campaignId}` edita-o — a campanha já deve ter um modelo, caso contrário, isso retornará `400`.

| Campo | Obrigatório | Descrição |
|---|---|---|
| `name` | Sim | Um nome para o modelo. |
| `language` | Sim | Código do idioma, por exemplo `en`, `es`, `de`, `pt_BR`, `zh_CN`. |
| `body` | Sim | O texto da mensagem, até 1024 caracteres. |
| `variables` | Sim | Lista ordenada de nomes de variáveis usados no corpo. Passe um array vazio se o modelo não usar nenhum. |

**cURL** (criar)

```bash
curl -X POST "https://api.youraiconnector.com/v1/whatsapp-templates/campaign/campaign123?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "welcome_message",
    "language": "en",
    "body": "Hi {{first_name}}, thanks for reaching out!",
    "variables": ["first_name"]
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/whatsapp-templates/campaign/campaign123", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    name: "welcome_message",
    language: "en",
    body: "Hi {{first_name}}, thanks for reaching out!",
    variables: ["first_name"],
  }),
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/whatsapp-templates/campaign/campaign123",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "name": "welcome_message",
        "language": "en",
        "body": "Hi {{first_name}}, thanks for reaching out!",
        "variables": ["first_name"],
    },
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "campaign_status": "pending",
  "template_sid": "HXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "message": "WhatsApp template created and campaign updated successfully."
}
```

Para editar, altere o método para `PUT` e use os mesmos campos — isso reenvia o modelo de abertura (e os rascunhos de acompanhamento da campanha, em uma campanha da API do WhatsApp) para revisão.

Uma campanha que não pertence à sua conta retorna `404`; uma campanha pertencente a outra conta para a qual você não está autorizado retorna `403`. Editar uma campanha sem um modelo existente retorna `400`.

---

## Enviar um modelo para um contato existente

Uma alternativa mais simples, delimitada por caminho, ao [Enviar um modelo para um contato](#send-a-template-to-a-contact) acima: tanto o modelo quanto o contato já devem existir — nada é pesquisado pelo nome ou criado instantaneamente.

`POST /whatsapp-templates/{templateId}/send-to-contact`

| Campo | Obrigatório | Descrição |
|---|---|---|
| `contactId` | Sim | O ID do contato. Deve pertencer à sua conta. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/send-to-contact?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "contactId": "contact123" }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/send-to-contact",
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ contactId: "contact123" }),
  }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/send-to-contact",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"contactId": "contact123"},
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "data": "WhatsApp template message sent successfully"
}
```

> **Créditos:** O envio consome créditos, precificados da mesma forma que o endpoint acima. Um `contactId` que esteja faltando ou não esteja em sua conta retorna `403`; um `templateId` que não existe retorna `404`.

---

## Envio em massa de um modelo

Envie um modelo para muitos contatos em uma única chamada, com uma prévia de custo que você pode exibir antes de confirmar.

### Estimar o custo primeiro

Retorna quanto o envio custaria, detalhado por país de destino, sem enviar nada ou mover créditos. O preço do modelo é por país de destino, portanto, isso deve ser calculado no lado do servidor em relação aos contatos reais, em vez de estimado no lado do cliente.

`POST /whatsapp-templates/{templateId}/estimate-bulk-cost`

| Campo | Obrigatório | Descrição |
|---|---|---|
| `contactIds` | Sim | Contatos para precificar, até 500 por chamada. Duplicatas são contadas uma vez. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/estimate-bulk-cost?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "contactIds": ["contact123", "contact456"] }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/estimate-bulk-cost",
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ contactIds: ["contact123", "contact456"] }),
  }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/estimate-bulk-cost",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"contactIds": ["contact123", "contact456"]},
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "data": {
    "countries": [
      {
        "countryCode": "1",
        "name": "United States",
        "iso": "US",
        "flag": "🇺🇸",
        "contactCount": 120,
        "costPerContact": 0.5,
        "subtotal": 60.0
      }
    ],
    "totalContacts": 120,
    "totalTemplateCost": 60.0,
    "templateCategory": "marketing",
    "skippedContacts": 2
  }
}
```

`skippedContacts` conta IDs que estavam faltando, não eram seus ou não possuíam número de telefone — a estimativa cobre apenas o restante, portanto, um valor diferente de zero significa que o envio real alcançará menos contatos do que você selecionou.

### Enviar o lote

Envia o modelo para cada contato na lista, resolvendo quaisquer variáveis inteligentes por contato e cobrando créditos por envio.

`POST /whatsapp-templates/{templateId}/bulk-send`

| Campo | Obrigatório | Descrição |
|---|---|---|
| `contactIds` | Sim | Contatos para os quais enviar, até 5000 por chamada. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/bulk-send?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "contactIds": ["contact123", "contact456"] }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/bulk-send",
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ contactIds: ["contact123", "contact456"] }),
  }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/whatsapp-templates/template_abc123/bulk-send",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"contactIds": ["contact123", "contact456"]},
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "data": { "sent": 118, "failed": 2, "total": 120 }
}
```

Um contato que falha (não encontrado, não está na sua conta ou erro de envio) é ignorado e contado em `failed` em vez de interromper o lote. Um `contactIds` vazio, mais de 5000 IDs em um envio (500 em uma estimativa) ou um `templateId` ausente retorna `400`.

---

## Tentar novamente uma mensagem com falha

Dois endpoints para reenviar uma mensagem que falhou, sem criar um novo registro de mensagem ou gastar créditos novamente.

`POST /whatsapp-templates/messages/{contactId}/{messageId}/retry-template` tenta novamente uma mensagem de modelo com falha especificamente — ele resolve novamente o conteúdo do modelo a partir da campanha se a mensagem com falha ainda não o contiver. Apenas mensagens com status `failed` e tipo `template` podem ser tentadas novamente desta forma.

`POST /whatsapp-templates/messages/{contactId}/{messageId}/retry` é independente de canal e funciona para qualquer mensagem que não seja de modelo com falha (por exemplo, WhatsApp Web), despachando para o caminho de envio correto com base no canal da mensagem. Ele aceita status `failed`, `failed_connection`, `limit_exceeded` ou `queued_retry`.

Nenhum dos endpoints aceita um corpo de solicitação.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/whatsapp-templates/messages/contact123/msg_abc789/retry-template?apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/whatsapp-templates/messages/contact123/msg_abc789/retry-template",
  { method: "POST", headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/whatsapp-templates/messages/contact123/msg_abc789/retry-template",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "data": "Message retry initiated successfully"
}
```

Para a versão independente de canal, troque o caminho para `.../msg_abc789/retry`. Uma mensagem cujo status não é elegível para nova tentativa, ou (no endpoint de modelo) que não é uma mensagem de modelo, retorna `400`. Um contato ou mensagem ausente retorna `404`.

---

## Perfil do WhatsApp Business

Gerencie o perfil do WhatsApp Business (sobre, endereço, descrição, e-mail, sites, categoria da empresa e logotipo) exibido para os contatos no WhatsApp. Funciona tanto em uma conexão gerenciada quanto em uma conta que executa sua própria Conta do WhatsApp Business.

### Salvar o perfil

`PUT /whatsapp-templates/profile`

| Campo | Obrigatório | Descrição |
|---|---|---|
| `phoneNumber` | Sim | O número do WhatsApp ao qual este perfil pertence. Deve estar conectado em sua conta. |
| `about` | Não | Texto curto "Sobre" exibido no perfil. |
| `address` | Não | Endereço da empresa. |
| `description` | Não | Descrição mais longa da empresa. |
| `email` | Não | E-mail de contato exibido no perfil. |
| `websites` | Não | Matriz de URLs de sites. Cada uma deve ser uma URL válida. |
| `vertical` | Não | Categoria da empresa, por exemplo `Retail` ou `Professional Services`. |
| `profilePictureHandle` | Não | O identificador retornado pelo endpoint de upload de imagem abaixo, para definir a foto do perfil. |

**cURL**

```bash
curl -X PUT "https://api.youraiconnector.com/v1/whatsapp-templates/profile?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phoneNumber": "+31612345678",
    "about": "We reply within a few hours",
    "email": "support@example.com",
    "websites": ["https://example.com"]
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/whatsapp-templates/profile", {
  method: "PUT",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    phoneNumber: "+31612345678",
    about: "We reply within a few hours",
    email: "support@example.com",
    websites: ["https://example.com"],
  }),
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.put(
    "https://api.youraiconnector.com/v1/whatsapp-templates/profile",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "phoneNumber": "+31612345678",
        "about": "We reply within a few hours",
        "email": "support@example.com",
        "websites": ["https://example.com"],
    },
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "data": "WhatsApp Business profile updated successfully"
}
```

Um `phoneNumber` ausente, uma URL de site inválida ou um `phoneNumber` não conectado em sua conta retornará `400` ou `404`.

### Fazer upload de uma foto de perfil

Baixa uma imagem de uma URL fornecida por você e faz o upload para o WhatsApp, retornando um identificador. Passe esse identificador como `profilePictureHandle` na chamada de salvar perfil acima para defini-lo como a foto — este endpoint apenas faz o upload da imagem, ele não a define por conta própria.

`POST /whatsapp-templates/profile/picture`

| Campo | Obrigatório | Descrição |
|---|---|---|
| `phoneNumber` | Sim | O número do WhatsApp ao qual este perfil pertence. |
| `fileUrl` | Sim | Uma URL publicamente acessível para a imagem a ser carregada. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/whatsapp-templates/profile/picture?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phoneNumber": "+31612345678",
    "fileUrl": "https://example.com/logo.png"
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/whatsapp-templates/profile/picture", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    phoneNumber: "+31612345678",
    fileUrl: "https://example.com/logo.png",
  }),
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/whatsapp-templates/profile/picture",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "phoneNumber": "+31612345678",
        "fileUrl": "https://example.com/logo.png",
    },
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "data": "1234567890123456"
}
```

`data` é o identificador da imagem carregada. Um `phoneNumber` ou `fileUrl` ausente, ou um `phoneNumber` sem token de acesso do WhatsApp registrado, retornará `400`; uma `fileUrl` inacessível ou inválida retornará um erro descrevendo o motivo da falha no download.

---

## Verificar o status de um remetente

Consulta (e atualiza) o status de envio em tempo real de um número do WhatsApp conectado com o provedor de mensagens. Útil para confirmar se um número está realmente apto a enviar mensagens antes de depender dele.

`GET /whatsapp-templates/sender-status/{phoneNumber}`

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/whatsapp-templates/sender-status/+31612345678" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/whatsapp-templates/sender-status/+31612345678",
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/whatsapp-templates/sender-status/+31612345678",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "data": "ONLINE"
}
```

`data` é um de `ONLINE` (enviando normalmente), `PENDING` (ainda sendo verificado) ou `DELETED` (o provedor não reconhece mais este remetente — reconecte o número). Um `phoneNumber` sem informações comerciais do WhatsApp registradas retornará `404`.

---

## Gere modelos de acompanhamento com IA

A plataforma pode escrever modelos de acompanhamento de WhatsApp para uma campanha para você — os lembretes enviados quando uma conversa fica inativa — a partir das próprias instruções e objetivos da campanha. Existe um endpoint de trabalho que é executado em segundo plano, além de três endpoints mais antigos mantidos para integrações existentes. Todos eles utilizam créditos de IA.

### Iniciar um trabalho de geração

`POST /campaigns/{campaignId}/template-generation`

| Campo | Obrigatório | Descrição |
|---|---|---|
| `type` | Não | `all` (o padrão) escreve todo o conjunto de acompanhamento. `cold_only` escreve apenas as mensagens para contatos que nunca responderam. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/campaigns/campaign_abc123/template-generation?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "type": "all" }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/campaigns/campaign_abc123/template-generation",
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ type: "all" }),
  }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/campaigns/campaign_abc123/template-generation",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"type": "all"},
)
data = res.json()
```

**Resposta** (`202`)

```json
{ "success": true, "campaign_id": "campaign_abc123", "type": "all" }
```

A chamada retorna assim que o trabalho é colocado na fila. Leia a campanha (`GET /campaigns/{campaignId}`, veja a [API de Campanhas](campaigns.md)) e observe seu objeto `template_generation_status` até que ele termine:

| Campo | Descrição |
|---|---|
| `status` | `processing` enquanto o trabalho é executado, depois `completed` ou `failed`. |
| `progress` | 0 a 100. |
| `current_template`, `total_templates` | Quantos modelos foram escritos até agora, do total que o trabalho escreverá — 11 para uma campanha de saída ou combinada, 9 caso contrário. |
| `error` | Por que um trabalho `failed` parou, por exemplo, falta de créditos. |
| `started_at`, `completed_at` | Quando o trabalho começou e terminou. |

Os modelos gerados são aplicados à campanha como qualquer outro, portanto, aparecem em [Listar modelos](#list-templates) e ainda passam pela aprovação do WhatsApp antes de poderem ser enviados. Um `400` significa que `type` foi algo diferente de `all` ou `cold_only`; um `404` significa que a campanha não existe ou pertence a outra conta.

Agentes possuem uma versão equivalente desta chamada, `POST /agents/{agentId}/template-generation`, que escreve os acompanhamentos para um Agente e termina durante a chamada no caso comum — veja [Gerar mensagens de acompanhamento](agents.md#generate-follow-up-messages) na API de Agentes de IA.

### Os endpoints de geração mais antigos

Três endpoints anteriores realizam o mesmo trabalho e são mantidos para que as integrações existentes continuem funcionando. Novos códigos devem usar o endpoint de trabalho acima.

| Endpoint | O que faz |
|---|---|
| `POST /whatsapp-templates/campaign/{campaignId}/generate-async` | Inicia a geração de acompanhamento para a campanha em segundo plano e retorna `202` com `{ "success": true, "data": { "result": "success", "message": "..." } }`. Os créditos são cobrados antecipadamente (ignorados em uma conta que traz sua própria chave de IA) e o `template_generation_status` da campanha relata o progresso exatamente como acima. |
| `POST /whatsapp-templates/campaign/{campaignId}/generate-followups` | Gera todos os nove modelos de acompanhamento durante a chamada — para uma campanha criada antes da existência de acompanhamentos automáticos, ou uma que precise que eles sejam escritos novamente — e retorna `200` com `templatesGenerated` dentro de `data`. |
| `POST /whatsapp-templates/agent/{agentId}/generate-followups` | A mesma geração síncrona abordada pelo Agente. A resposta adiciona `agent_id`, `campaign_id` e `target`: `"campaign"` quando os modelos foram escritos na campanha do Agente, `"agent"` (com `campaign_id: null`) quando o Agente não tem campanha e eles foram armazenados no próprio Agente. Um Agente ausente ou estrangeiro é um `404`. |

Todos os três precisam de acompanhamentos automáticos na conta e créditos suficientes — um `400` indica qual está faltando — e o par endereçado à campanha retorna `403` quando a campanha pertence a outra conta.

---

## Erros da API de Templates

Os endpoints de template retornam o envelope de erro padrão:

```json
{
  "success": false,
  "error": "Template not found"
}
```

Um `404` nesses endpoints geralmente significa que o recurso não foi encontrado — ou ele não existe ou pertence a outra conta. Alguns endpoints (criação/atualização com escopo de campanha e envios para um contato existente) retornam `403` em vez disso quando a campanha ou o contato pertence a outra pessoa, em vez de não existir. Alguns endpoints também incluem um campo `error_code` que reflete o status HTTP. Os códigos compartilhados que todos os endpoints podem retornar — `400`, `401`, `403` (seu plano não inclui acesso à API), `429` (limite de taxa) e `500` — estão listados com orientações de nova tentativa em [Erros e Paginação](errors-and-pagination.md).

---

## Próximos passos

- [Autenticação](authentication.md) — as quatro maneiras de autenticar uma solicitação.
- [Erros e Limites de Taxa](errors-and-pagination.md) — códigos de status e o limite de 300 req/min.
- [API de Campanhas](campaigns.md) — gerencie as campanhas às quais os modelos estão vinculados.
