
# API de FAQs

FAQs são as entradas de perguntas e respostas que seu bot de IA utiliza ao responder aos clientes. Cada FAQ pertence à sua conta e pode ser vinculada a uma ou mais campanhas, permitindo que a mesma resposta seja reutilizada onde for relevante. A API de FAQs permite que você gerencie essa biblioteca programaticamente — crie, atualize, importe em massa, reordene e vincule FAQs a campanhas a partir do seu próprio código.

Todos os endpoints abaixo são relativos à URL base `https://api.youraiconnector.com/v1`. Cada solicitação deve ser autenticada — consulte [Acesso à API](../integrations/api-access.md) e [Autenticação](authentication.md). O acesso à API é um recurso pago; sem ele, as solicitações são rejeitadas com um `403`.

> **Como o bot usa uma FAQ:** Quando você cria ou altera uma FAQ, a plataforma prepara seus dados de pesquisa (usados para corresponder a FAQ às perguntas recebidas) em segundo plano. Isso geralmente é concluído em poucos segundos, após o que o bot começa a usar a entrada automaticamente.


---

## O objeto FAQ

Cada FAQ retornada pela API possui este formato:

| Campo | Tipo | Descrição |
|---|---|---|
| `id` | string | O identificador único do FAQ. |
| `question` | string | A pergunta do cliente que esta entrada responde. |
| `answer` | string | A resposta que o bot de IA fornece. |
| `category` | string \| null | Rótulo de categoria de formato livre opcional. |
| `tags` | string[] | Rótulos opcionais para organizar FAQs. |
| `is_active` | boolean | Se o bot tem permissão para usar este FAQ. O padrão é `true`. |
| `is_global` | boolean | Marca o FAQ como não vinculado a uma campanha ou Agente específico. Isso não faz com que o FAQ seja aplicado em todos os lugares: um FAQ só é usado pelas campanhas e Agentes aos quais está vinculado. O padrão é `false`. |
| `usage_count` | integer | Quantas vezes este FAQ foi usado em respostas de IA. |
| `order_index` | integer | Posição de exibição deste FAQ dentro de sua campanha. |
| `campaign_ids` | string[] | IDs das campanhas às quais este FAQ está vinculado. |
| `created_at` | string \| null | Carimbo de data/hora ISO 8601 de quando o FAQ foi criado. |
| `updated_at` | string \| null | Carimbo de data/hora ISO 8601 da última alteração. |

Os campos que você pode **definir** são: `question`, `answer`, `is_active`, `is_global`, `category`, `tags` e `order_index`. A plataforma gerencia todo o resto (dados de pesquisa, contagens de uso, carimbos de data/hora); quaisquer outros campos no corpo da sua solicitação são ignorados.

---

## Listar FAQs

`GET /faqs`

Retorna as FAQs em sua conta, da mais recente para a mais antiga. Opcionalmente, filtre por uma campanha específica ou pelo estado ativo.

**Parâmetros de consulta**

| Parâmetro | Obrigatório | Descrição |
|---|---|---|
| `campaign_id` | Não | Retorna apenas FAQs vinculadas a esta campanha. |
| `is_active` | Não | Retorna apenas FAQs com este estado ativo (`true` ou `false`). Este filtro é aplicado por página, portanto, uma página pode conter menos itens que `limit`. |
| `limit` | Não | Máximo de FAQs por página. O padrão é `50`, o máximo é `100`. |
| `cursor` | Não | Um ID de FAQ para continuar após ele. Passe o valor `next_cursor` da página anterior. |

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/faqs?campaign_id=campaign123&limit=50&apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/faqs?campaign_id=campaign123&limit=50",
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
console.log(data.faqs, data.next_cursor);
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/faqs",
    params={"campaign_id": "campaign123", "limit": 50},
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
print(data["faqs"], data["next_cursor"])
```

**Resposta**

```json
{
  "success": true,
  "faqs": [
    {
      "id": "aBcD1234eFgH5678",
      "question": "How long does shipping take?",
      "answer": "Standard shipping takes 3-5 business days.",
      "category": "shipping",
      "tags": ["logistics", "delivery"],
      "is_active": true,
      "is_global": false,
      "usage_count": 12,
      "order_index": 0,
      "campaign_ids": ["campaign123"],
      "created_at": "2026-01-01T12:00:00.000Z",
      "updated_at": "2026-01-02T08:30:00.000Z"
    }
  ],
  "next_cursor": "aBcD1234eFgH5678"
}
```

Quando `next_cursor` é `null`, não há mais resultados.

---

## Obter uma FAQ

`GET /faqs/{faqId}`

Retorna uma única FAQ pelo seu ID.

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678?apiKey=YOUR_API_KEY"
```

**JavaScript**

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

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
faq = res.json()["faq"]
```

**Resposta**

```json
{
  "success": true,
  "faq": {
    "id": "aBcD1234eFgH5678",
    "question": "How long does shipping take?",
    "answer": "Standard shipping takes 3-5 business days.",
    "category": "shipping",
    "tags": ["logistics"],
    "is_active": true,
    "is_global": false,
    "usage_count": 12,
    "order_index": 0,
    "campaign_ids": ["campaign123"],
    "created_at": "2026-01-01T12:00:00.000Z",
    "updated_at": "2026-01-02T08:30:00.000Z"
  }
}
```

---

## Criar uma FAQ

`POST /faqs`

Cria uma nova FAQ e a vincula a uma campanha.

**Campos da requisição**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `campaign_id` | Sim | A campanha à qual vincular a nova FAQ. |
| `question` | Sim | A pergunta do cliente que esta entrada responde. |
| `answer` | Sim | A resposta que o bot deve fornecer. |
| `is_active` | Não | Se o bot pode usar esta FAQ. O padrão é `true`. |
| `is_global` | Não | Se a FAQ se aplica a todas as campanhas. O padrão é `false`. |
| `category` | Não | Um rótulo de categoria de formato livre. |
| `tags` | Não | Uma matriz de rótulos. |
| `order_index` | Não | Posição de exibição dentro da campanha. O padrão é `0`. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/faqs?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "campaign_id": "campaign123",
    "question": "How long does shipping take?",
    "answer": "Standard shipping takes 3-5 business days.",
    "category": "shipping",
    "tags": ["logistics"]
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/faqs", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    campaign_id: "campaign123",
    question: "How long does shipping take?",
    answer: "Standard shipping takes 3-5 business days.",
    category: "shipping",
    tags: ["logistics"],
  }),
});
const { faq_id } = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/faqs",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "campaign_id": "campaign123",
        "question": "How long does shipping take?",
        "answer": "Standard shipping takes 3-5 business days.",
        "category": "shipping",
        "tags": ["logistics"],
    },
)
faq_id = res.json()["faq_id"]
```

**Resposta**

```json
{
  "success": true,
  "faq_id": "aBcD1234eFgH5678"
}
```

---

## Atualizar uma FAQ

`PUT /faqs/{faqId}`

Atualiza parcialmente uma FAQ. Apenas os campos graváveis fornecidos são alterados; todo o resto mantém seu valor atual. Alterar o `question` ou `answer` atualiza automaticamente os dados de pesquisa da FAQ em segundo plano.

Se você enviar `question` ou `answer`, eles devem ser strings não vazias. Enviar campos graváveis não reconhecidos retorna um `400`.

**cURL**

```bash
curl -X PUT "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "is_active": false }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678",
  {
    method: "PUT",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ is_active: false }),
  }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.put(
    "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"is_active": False},
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "faq_id": "aBcD1234eFgH5678"
}
```

---

## Excluir uma FAQ

`DELETE /faqs/{faqId}`

Exclui permanentemente uma FAQ. Opcionalmente, passe `campaign_id` como um parâmetro de consulta para também remover a FAQ da lista de FAQ dessa campanha.

**Parâmetros de consulta**

| Parâmetro | Obrigatório | Descrição |
|---|---|---|
| `campaign_id` | Não | Também remove o FAQ da lista de FAQ desta campanha. |

**cURL**

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678?campaign_id=campaign123&apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678?campaign_id=campaign123",
  { 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/faqs/aBcD1234eFgH5678",
    params={"campaign_id": "campaign123"},
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**Resposta**

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

---

## Exclusão em massa de FAQs

`POST /faqs/bulk-delete`

Exclui até 500 FAQs em uma única solicitação. Quando `campaign_id` é fornecido, os FAQs excluídos também são removidos da lista de FAQ daquela campanha.

**Campos da requisição**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `faq_ids` | Sim | Um array não vazio de IDs de FAQ para excluir (máx. 500). |
| `campaign_id` | Não | Também remove os FAQs excluídos da lista de FAQ desta campanha. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/faqs/bulk-delete?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "faq_ids": ["faqId1", "faqId2"], "campaign_id": "campaign123" }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/faqs/bulk-delete", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    faq_ids: ["faqId1", "faqId2"],
    campaign_id: "campaign123",
  }),
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/faqs/bulk-delete",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"faq_ids": ["faqId1", "faqId2"], "campaign_id": "campaign123"},
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "deleted_count": 2
}
```

---

## Perguntas frequentes sobre importação

`POST /faqs/import`

Importe em massa até 500 perguntas frequentes e vincule todas a uma campanha. Itens cujo `question` corresponda a uma pergunta frequente existente em sua biblioteca (sem diferenciar maiúsculas de minúsculas) **atualizam** essa pergunta frequente em vez de criar uma duplicata.

> **Dica de desempenho:** A correspondência de duplicatas verifica toda a sua biblioteca de perguntas frequentes, portanto, bibliotecas muito grandes tornam as importações mais lentas. Prefira menos importações maiores em vez de muitas pequenas.

**Campos da requisição**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `campaign_id` | Sim | A campanha à qual todas as perguntas frequentes importadas estão vinculadas. |
| `faqs` | Sim | Uma matriz não vazia de itens de perguntas frequentes (máx. 500). Cada item deve ter um `question` e `answer` não vazios; também pode incluir `is_active`, `is_global`, `category`, `tags` e `order_index`. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/faqs/import?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "campaign_id": "campaign123",
    "faqs": [
      { "question": "Do you ship internationally?", "answer": "Yes, we ship to most countries worldwide." },
      { "question": "What is your return policy?", "answer": "You can return any item within 30 days." }
    ]
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/faqs/import", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    campaign_id: "campaign123",
    faqs: [
      {
        question: "Do you ship internationally?",
        answer: "Yes, we ship to most countries worldwide.",
      },
      {
        question: "What is your return policy?",
        answer: "You can return any item within 30 days.",
      },
    ],
  }),
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/faqs/import",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "campaign_id": "campaign123",
        "faqs": [
            {"question": "Do you ship internationally?", "answer": "Yes, we ship to most countries worldwide."},
            {"question": "What is your return policy?", "answer": "You can return any item within 30 days."},
        ],
    },
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "faq_ids": ["aBcD1234eFgH5678", "iJkL9012mNoP3456"],
  "imported_count": 2
}
```

`faq_ids` são os IDs das perguntas frequentes criadas ou atualizadas, na ordem em que você os forneceu.

---

## Reordenar perguntas frequentes

`POST /faqs/reorder`

Define a ordem de exibição das perguntas frequentes de uma campanha. Forneça a lista **completa** de IDs de perguntas frequentes na ordem desejada; a posição de cada pergunta frequente é atualizada para corresponder ao seu lugar na matriz.

**Campos da requisição**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `campaign_id` | Sim | A campanha cujas FAQs estão sendo reordenadas. |
| `ordered_faq_ids` | Sim | Uma matriz não vazia de todos os IDs de FAQ da campanha na ordem de exibição desejada (máximo de 500). |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/faqs/reorder?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "campaign_id": "campaign123",
    "ordered_faq_ids": ["faqId2", "faqId1", "faqId3"]
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/faqs/reorder", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    campaign_id: "campaign123",
    ordered_faq_ids: ["faqId2", "faqId1", "faqId3"],
  }),
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/faqs/reorder",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "campaign_id": "campaign123",
        "ordered_faq_ids": ["faqId2", "faqId1", "faqId3"],
    },
)
data = res.json()
```

**Resposta**

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

Se a campanha ou qualquer um dos IDs de FAQ não for encontrado em sua conta, a solicitação retornará `404 One or more FAQs were not found`.

---

## Vincular uma FAQ a uma campanha

`POST /faqs/{faqId}/link`

Vincula uma FAQ existente a uma campanha adicional. Uma FAQ pode ser compartilhada por qualquer número de campanhas, portanto, a mesma resposta só precisa ser mantida uma vez.

**Campos da requisição**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `campaign_id` | Sim | A campanha à qual vincular a FAQ. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678/link?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "campaign_id": "campaign456" }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678/link",
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ campaign_id: "campaign456" }),
  }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678/link",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"campaign_id": "campaign456"},
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "faq_id": "aBcD1234eFgH5678",
  "campaign_id": "campaign456"
}
```

---

## Desvincular uma FAQ de uma campanha

`POST /faqs/{faqId}/unlink`

Remove uma FAQ de uma campanha sem excluir a própria FAQ. A FAQ permanece em sua biblioteca e continua vinculada a quaisquer outras campanhas.

**Campos da requisição**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `campaign_id` | Sim | A campanha da qual a FAQ será removida. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678/unlink?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "campaign_id": "campaign456" }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678/unlink",
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ campaign_id: "campaign456" }),
  }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678/unlink",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"campaign_id": "campaign456"},
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "faq_id": "aBcD1234eFgH5678",
  "campaign_id": "campaign456"
}
```

---

## Reconstruir os dados de pesquisa de uma FAQ

`POST /faqs/{faqId}/rebuild-embeddings`

Coloca na fila uma reconstrução dos dados que o bot de IA usa para encontrar esta FAQ (seus dados de pesquisa semântica e por palavras-chave). Isso é útil se uma FAQ não estiver sendo detectada nas respostas como esperado. A reconstrução é executada em segundo plano e geralmente é concluída em poucos segundos; a FAQ pode ser temporariamente excluída das respostas da IA enquanto estiver sendo reconstruída.

Este endpoint retorna `202 Accepted` porque o trabalho continua após o envio da resposta. O `status` é sempre `"processing"` — busque a FAQ novamente mais tarde se precisar confirmar a conclusão.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678/rebuild-embeddings?apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678/rebuild-embeddings",
  { 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/faqs/aBcD1234eFgH5678/rebuild-embeddings",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "faq_id": "aBcD1234eFgH5678",
  "status": "processing"
}
```

---

## Gerenciamento de FAQ assistido por IA

Os endpoints abaixo vão além do CRUD simples: eles chamam as mesmas ferramentas de assistência por IA que o editor de FAQ do painel utiliza — encontrando duplicatas, gerando entradas a partir de um documento e correspondendo FAQs a tarefas abertas de lacunas de conhecimento. Os corpos das requisições neste conjunto usam nomes de campo `camelCase` (`campaignId`, `taskId`, `sourceIds`...), correspondendo aos formatos de requisição do próprio aplicativo, em vez do `snake_case` usado em outros lugares nesta página — copie os exemplos abaixo em vez de tentar adivinhar um nome de campo.

### Criar uma cópia de FAQ exclusiva para uma campanha

`POST /faqs/{faqId}/fork-for-campaign`

Cria um novo FAQ que é uma cópia de um existente, limitado a uma única campanha, e vincula essa campanha à nova cópia em vez da original. Use isso quando quiser personalizar uma resposta para uma campanha sem alterá-la em todos os outros lugares onde o FAQ original é usado. O FAQ original permanece no lugar — ele apenas perde o vínculo desta campanha.

**Campos da requisição**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `campaign_id` | Sim | A campanha para a qual a nova cópia será limitada e que será desvinculada do FAQ original. |
| `question` | Sim | A pergunta para a nova cópia específica da campanha. |
| `answer` | Sim | A resposta para a nova cópia específica da campanha. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678/fork-for-campaign?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "campaign_id": "campaign456",
    "question": "How long does shipping take to the EU?",
    "answer": "For EU orders, shipping takes 7-10 business days."
  }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678/fork-for-campaign",
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      campaign_id: "campaign456",
      question: "How long does shipping take to the EU?",
      answer: "For EU orders, shipping takes 7-10 business days.",
    }),
  }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678/fork-for-campaign",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "campaign_id": "campaign456",
        "question": "How long does shipping take to the EU?",
        "answer": "For EU orders, shipping takes 7-10 business days.",
    },
)
data = res.json()
```

**Resposta** — `201 Created`

```json
{
  "success": true,
  "faq_id": "nEwFaQiD9012mNoP",
  "campaign_id": "campaign456",
  "original_faq_id": "aBcD1234eFgH5678"
}
```

### Encontrar FAQs quase duplicados

`POST /faqs/dedupe`

Inicia um trabalho em segundo plano que verifica sua biblioteca de FAQ em busca de entradas quase duplicadas e sobrepostas, mesclando ou removendo-as onde houver confiança. Útil após uma importação em massa ou após várias rodadas de FAQs gerados por IA terem deixado a biblioteca com sobreposições. Apenas um trabalho de deduplicação pode ser executado por conta de cada vez — iniciar um segundo enquanto um trabalho ainda está em execução retorna `409`.

**Campos da requisição**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `sourceIds` | Não | Matriz de IDs de origem da base de conhecimento para limitar a deduplicação. Omita para verificar toda a sua biblioteca de FAQ. |

**cURL**

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

**JavaScript**

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

**Python**

```python
import requests

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

**Resposta** — `202 Accepted`

```json
{
  "success": true,
  "job_id": "dedupJob_aBc123"
}
```

O trabalho é executado em segundo plano e normalmente leva alguns minutos em uma biblioteca grande. Não há um endpoint de status separado — busque novamente [`GET /faqs`](#list-faqs) após uma breve espera para ver o que mudou. Quando terminar de revisar o resultado, chame o endpoint de descarte abaixo para limpá-lo.

### Descartar um resultado de verificação de duplicatas

`POST /faqs/dedupe/dismiss`

Limpa o trabalho de deduplicação concluído para que ele pare de aparecer como um resultado ativo. Idempotente — seguro para chamar mesmo se não houver nada para descartar. Retorna `409` se o trabalho ainda estiver `queued` ou `processing` (você não pode descartar uma execução que não foi concluída).

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/faqs/dedupe/dismiss?apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/faqs/dedupe/dismiss", {
  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/faqs/dedupe/dismiss",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**Resposta**

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

### Gerar FAQs a partir de documentos enviados

`POST /faqs/generate-from-documents`

Lê um ou mais documentos já armazenados no armazenamento de arquivos da sua conta e faz com que a IA crie rascunhos de FAQs a partir do conteúdo deles, verificando os rascunhos em relação à sua biblioteca existente para que ela reutilize ou atualize entradas em vez de criar duplicatas. Os resultados **não** são gravados imediatamente — eles são armazenados como um conjunto de alterações pendentes na campanha para você revisar e, em seguida, aplicados (ou descartados) com [Aplicar alterações de FAQ revisadas](#apply-reviewed-faq-changes) abaixo. Isso consome créditos, pois é uma etapa de geração de IA sobre o texto do documento.

Este endpoint não carrega o arquivo: `storagePath` deve apontar para um arquivo já existente na sua própria pasta de uploads (`users/{your user id}/uploads/`), seguindo a mesma convenção de [Importar um documento enviado](knowledge-base.md#import-an-uploaded-document) na API da Base de Conhecimento.

**Campos da requisição**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `campaignId` | Sim | A campanha para a qual as FAQs geradas são propostas. |
| `uploadedFiles` | Sim | Array não vazio de arquivos a serem lidos, cada um `{ storagePath, fileName, mimeType }`. `storagePath` deve começar com `users/{your user id}/uploads/`. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/faqs/generate-from-documents?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "campaignId": "campaign123",
    "uploadedFiles": [
      { "storagePath": "users/abc123uid/uploads/handbook.pdf", "fileName": "handbook.pdf", "mimeType": "application/pdf" }
    ]
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/faqs/generate-from-documents", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    campaignId: "campaign123",
    uploadedFiles: [
      { storagePath: "users/abc123uid/uploads/handbook.pdf", fileName: "handbook.pdf", mimeType: "application/pdf" },
    ],
  }),
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/faqs/generate-from-documents",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "campaignId": "campaign123",
        "uploadedFiles": [
            {"storagePath": "users/abc123uid/uploads/handbook.pdf", "fileName": "handbook.pdf", "mimeType": "application/pdf"},
        ],
    },
)
data = res.json()
```

**Resposta** — `202 Accepted`

```json
{
  "success": true,
  "faqCount": 6,
  "reusedCount": 2,
  "modifiedCount": 1,
  "newCount": 3
}
```

`faqCount` é o número total de alterações propostas aguardando revisão; `reusedCount`, `modifiedCount` e `newCount` detalham isso em FAQs que corresponderam a uma entrada existente sem alterações, aquelas que a IA propõe editar e as totalmente novas. Os arquivos enviados são excluídos do armazenamento assim que o processamento termina, independentemente de ter sido bem-sucedido ou não.

### Aplicar alterações de FAQ revisadas

`POST /faqs/apply-optimization`

Aplica (ou descarta) um conjunto pendente de alterações de FAQ propostas pela IA — o tipo produzido por [Gerar FAQs a partir de documentos](#generate-faqs-from-uploaded-documents) acima, ou pela revisão de otimização de FAQ do painel. Você escolhe exatamente quais alterações propostas aceitar; tudo o que você não mencionar permanece inalterado (uma alteração omitida nunca é tratada como uma rejeição que exclui algo).

**Campos da requisição**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `campaignId` | Um destes dois | A campanha cujas alterações pendentes de FAQ estão sendo aplicadas. |
| `agentId` | Um destes dois | O Agente de IA cujas alterações pendentes de FAQ estão sendo aplicadas, em uma conta nativa do agente. Forneça exatamente um entre `campaignId` / `agentId`, nunca ambos. |
| `acceptedChanges` | Sim | Array das alterações que você aceita, cada uma `{ action, faq_id?, faq_ref_path?, question?, answer?, edit_scope? }`. `action` é um entre `keep`, `remove`, `add_from_library`, `create_new`, `modify`. Envie um array vazio para descartar o conjunto pendente sem aplicar nada. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/faqs/apply-optimization?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "campaignId": "campaign123",
    "acceptedChanges": [
      { "action": "create_new", "question": "Do you ship to the EU?", "answer": "Yes, EU shipping takes 7-10 business days." },
      { "action": "remove", "faq_ref_path": "users/abc123uid/faqs/oldFaqId" }
    ]
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/faqs/apply-optimization", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    campaignId: "campaign123",
    acceptedChanges: [
      { action: "create_new", question: "Do you ship to the EU?", answer: "Yes, EU shipping takes 7-10 business days." },
      { action: "remove", faq_ref_path: "users/abc123uid/faqs/oldFaqId" },
    ],
  }),
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/faqs/apply-optimization",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "campaignId": "campaign123",
        "acceptedChanges": [
            {"action": "create_new", "question": "Do you ship to the EU?", "answer": "Yes, EU shipping takes 7-10 business days."},
            {"action": "remove", "faq_ref_path": "users/abc123uid/faqs/oldFaqId"},
        ],
    },
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "message": "Applied 2 FAQ changes",
  "faq_count": 7
}
```

`faq_count` é a contagem total de FAQs vinculadas da campanha (ou Agente) após a aplicação. Se não houvesse um conjunto de alterações pendentes para aplicar, a resposta será `{ "success": true, "message": "No pending FAQ changes to apply" }`.

### Encontrar FAQs semelhantes a uma tarefa

`POST /faqs/similar-for-task`

Classifica sua biblioteca de FAQ por relevância em relação à pergunta de uma tarefa de lacuna de conhecimento — a mesma pesquisa por trás do seletor "Usar uma FAQ existente" do painel. Somente leitura. `taskId` deve apontar para uma tarefa do tipo `faq_update`.

Este endpoint sempre responde `200`, mesmo em uma falha esperada, como uma tarefa desconhecida — verifique `success` no corpo da resposta em vez do status HTTP.

**Campos da requisição**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `taskId` | Sim | A tarefa `faq_update` para encontrar correspondências. |
| `limit` | Não | Máximo de correspondências a retornar. O padrão é 20, limitado a 50. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/faqs/similar-for-task?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "taskId": "task789", "limit": 10 }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/faqs/similar-for-task", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ taskId: "task789", limit: 10 }),
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/faqs/similar-for-task",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"taskId": "task789", "limit": 10},
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "data": {
    "task_id": "task789",
    "matches": [
      {
        "faq_id": "aBcD1234eFgH5678",
        "question": "How long does shipping take?",
        "answer": "Standard shipping takes 3-5 business days.",
        "category": "shipping",
        "created_at": "2026-01-01T12:00:00.000Z",
        "similarity": 0.81,
        "embedding_similarity": 0.81,
        "keyword_similarity": 0.6,
        "bm25_score": 4.2,
        "distance": 0.19
      }
    ]
  }
}
```

As correspondências são classificadas por `similarity` (correspondência semântica quando disponível, sobreposição de palavras-chave caso contrário), com a melhor primeiro. Em uma falha leve, o formato é `{ "success": false, "error": "...", "error_code": 404 }` — `error_code` reflete o que o status HTTP normalmente seria.

### Resolver uma tarefa com um FAQ existente

`POST /faqs/resolve-task`

Resolve uma tarefa de lacuna de conhecimento vinculando-a a um FAQ que você já possui (em vez de escrever um novo), envia a resposta desse FAQ ao contato que acionou a lacuna e marca a tarefa como concluída. Use isso após [Encontrar FAQs semelhantes a uma tarefa](#find-faqs-similar-to-a-task) revelar um FAQ existente que já cobre a pergunta.

Assim como o endpoint acima, este sempre responde `200` — verifique `success` no corpo da resposta.

**Campos da requisição**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `taskId` | Sim | A tarefa `faq_update` a ser resolvida. |
| `faqId` | Sim | O FAQ existente para vincular e enviar como resposta. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/faqs/resolve-task?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "taskId": "task789", "faqId": "aBcD1234eFgH5678" }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/faqs/resolve-task", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ taskId: "task789", faqId: "aBcD1234eFgH5678" }),
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/faqs/resolve-task",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"taskId": "task789", "faqId": "aBcD1234eFgH5678"},
)
data = res.json()
```

**Resposta**

```json
{
  "success": true,
  "data": {
    "task_id": "task789",
    "faq_id": "aBcD1234eFgH5678",
    "follow_up_status": "published"
  }
}
```

`follow_up_status` informa o que aconteceu com o acompanhamento do contato: `published` (enviado imediatamente), `queued` (a IA já estava respondendo a esse contato, então será enviado em seguida), `skipped_no_contact` (a tarefa não tem um contato vinculado) ou `skipped_no_campaign` (nenhuma campanha para enviá-lo).

---

## Erros da API de FAQs

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

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

| Status | Quando ocorre em um endpoint de FAQ |
|---|---|
| `400` | Um campo obrigatório está ausente ou inválido (por exemplo, um `question` vazio, um `campaign_id` ausente ou mais de 500 itens em uma solicitação em lote). |
| `404` | O FAQ ou a campanha não foi encontrado — ou não existe ou pertence a outra conta. |
| `409` | `POST /faqs/dedupe` foi chamado enquanto um trabalho de deduplicação já está `queued`/`processing`, ou `POST /faqs/dedupe/dismiss` foi chamado enquanto o trabalho ainda não terminou. |

Os códigos compartilhados que todo endpoint pode retornar — `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).

`POST /faqs/similar-for-task` e `POST /faqs/resolve-task` são as duas exceções nesta página: eles respondem `200` mesmo para uma falha esperada (tarefa desconhecida, tipo de tarefa incorreto) e colocam o status real no `error_code` do corpo da resposta — veja cada endpoint acima.

---

## Relacionado

- [API de Campanhas](campaigns.md) — as campanhas às quais seus FAQs estão vinculados.
- [API de Base de Conhecimento](knowledge-base.md) — importe sites e documentos para FAQs automaticamente e agrupe FAQs em grupos de conhecimento reutilizáveis.
- [Acesso à API](../integrations/api-access.md) — gere sua chave de API.
- [Autenticação](authentication.md) — todas as maneiras de passar sua chave.
