
# API da Base de Conhecimento

A sua base de conhecimento é aquilo que a IA lê. É composta por duas partes, e esta página abrange ambas:

- **Fontes de conhecimento** (`/kb-sources`) — as páginas web e documentos carregados que fornece à plataforma. Cada um é lido, dividido em secções e transformado em FAQs que a sua IA pode utilizar para responder.
- **Grupos de conhecimento** (`/kb-groups`) — conjuntos nomeados de FAQs que pode aplicar a um Agente ou a uma campanha numa única chamada, para que um corpo de conhecimento que já tenha curado possa ser reutilizado no próximo Agente que criar.

As FAQs que uma fonte produz vão parar à mesma biblioteca que as que escreve manualmente, por isso, assim que uma importação termina, pode lê-las, editá-las e associá-las com a [API de FAQs](faqs.md).

Todos os endpoints abaixo são relativos ao URL base `https://api.youraiconnector.com/v1`. Todos os pedidos devem ser autenticados — consulte [Acesso à API](../integrations/api-access.md) e [Autenticação](authentication.md). O acesso à API é uma funcionalidade paga; sem ele, os pedidos são rejeitados com um `403`.


> **A importação consome créditos.** Ler uma página ou documento e escrever FAQs a partir dele consome créditos, aproximadamente em proporção à quantidade de conteúdo existente. Utilize [Estimar uma importação](#estimate-what-an-import-will-cost) antes de se comprometer com uma pesquisa de grande dimensão.

---

## Como funciona uma importação

A importação é uma tarefa em segundo plano, não algo que termina enquanto espera. Cada endpoint de importação responde imediatamente com um `source_id`, e deve consultar essa fonte até que esteja concluída:

1. **Iniciar a importação** — `POST /kb-sources/url` (uma página), `POST /kb-sources/file` (um documento carregado) ou `POST /kb-sources/bulk-import` (até 100 páginas). Recebe um ID de fonte e um `status: "queued"`.
2. **Consultar** — `GET /kb-sources/{sourceId}` até que o `status` deixe de ser `queued` ou `processing`.
3. **Ler as FAQs** — quando o estado for `ready`, as entradas produzidas estarão na sua biblioteca de FAQs: `GET /faqs`.

Cada fonte reporta um destes estados:

| Estado | O que significa |
|---|---|
| `queued` | À espera de ser lido. Ainda não foi cobrado nada. |
| `processing` | A ser lido e transformado em FAQs neste momento. |
| `ready` | Concluído. As suas FAQs estão na sua biblioteca. |
| `failed` | Não pôde ser importado. O `error_message` indica o motivo. |
| `cancelled` | Parado antes de ser lido (ver [Parar uma importação](#stop-an-import)). |
| `paused` | Parado porque a sua própria chave de IA falhou a meio da importação (ver [Retomar uma importação em pausa](#resume-a-paused-import)). |
| `deleting` | Uma remoção em massa está a processar o conteúdo. |
| `unknown` | O registo não apresenta estado. Considere-o como não pronto. |

> **Anexar ao importar.** Passe `autoLinkToAgentId` em qualquer endpoint de importação e a fonte — juntamente com cada FAQ que produz — é adicionada ao conhecimento desse Agente na mesma chamada, sem necessidade de um passo de associação posterior. O `autoLinkToCampaignId` faz o mesmo para uma campanha clássica. A associação é feita com o melhor esforço: um ID que não existe, ou que pertence a outra conta, é ignorado silenciosamente e a importação continua a decorrer, por isso confirme a associação lendo o Agente novamente.

---

## Importar uma página web

`POST /kb-sources/url`

Adiciona uma página web à sua base de conhecimento.

**Campos do pedido**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `url` | Sim | `http` ou `https` completo da página. |
| `autoLinkToAgentId` | Não | ID de um Agente de IA ao qual anexar a fonte importada. |
| `autoLinkToCampaignId` | Não | Legado. ID de uma campanha à qual anexar a fonte importada. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/kb-sources/url?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/pricing",
    "autoLinkToAgentId": "ag7HkQ2ZpLxR3mNb"
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/kb-sources/url", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://example.com/pricing",
    autoLinkToAgentId: "ag7HkQ2ZpLxR3mNb",
  }),
});
const { source_id } = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/kb-sources/url",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "url": "https://example.com/pricing",
        "autoLinkToAgentId": "ag7HkQ2ZpLxR3mNb",
    },
)
source_id = res.json().get("source_id")
```

**Resposta** — `202 Accepted`

```json
{
  "success": true,
  "source_id": "kb_src_abc123",
  "status": "queued",
  "batch_id": "batch_9f2a"
}
```

Consulte `source_id` com [Verificar uma fonte](#check-a-source) até que o estado seja `ready` ou `failed`.

Se a mesma página já estiver na sua base de conhecimento, nada de novo é colocado na fila e recebe um `200` em vez disso — e se pediu uma ligação automática, a fonte existente é ligada para si de qualquer forma:

```json
{
  "success": true,
  "status": "exists",
  "skipped_duplicate": 1
}
```

Um `url` em falta, ou um que não seja um endereço `http`/`https` válido, devolve `400`.

---

## Importar um documento carregado

`POST /kb-sources/file`

Adiciona um documento que **já se encontra no armazenamento de ficheiros da sua conta** como fonte de conhecimento. Tipos suportados: PDF, DOCX, TXT, MD, CSV e XLSX.

> **Este endpoint não transporta o ficheiro.** Não existe carregamento multipart, nem corpo base64, nem transferência a partir de um URL: envia a localização de armazenamento de um ficheiro que já existe, e este deve estar na sua própria pasta de carregamentos (`storage_path` tem de começar com `users/{your user id}/uploads/`) ou o pedido será recusado com `403`. O painel de controlo coloca os ficheiros lá quando os arrasta para lá. Se não tiver forma de colocar um ficheiro lá, importe uma página web com [Importar uma página web](#import-a-web-page) em vez disso.

**Campos do pedido**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `storage_path` | Sim | Onde reside o ficheiro carregado. Deve começar com `users/{your user id}/uploads/`. |
| `filename` | Sim | Nome original do ficheiro, incluindo a sua extensão — é assim que o tipo de ficheiro é detetado. |
| `mime_type` | Sim | Tipo MIME do ficheiro, por exemplo `application/pdf`. |
| `autoLinkToAgentId` | Não | ID de um Agente de IA ao qual anexar o documento. |
| `autoLinkToCampaignId` | Não | Legado. ID de uma campanha à qual anexar o documento. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/kb-sources/file?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "storage_path": "users/abc123uid/uploads/handbook.pdf",
    "filename": "handbook.pdf",
    "mime_type": "application/pdf",
    "autoLinkToAgentId": "ag7HkQ2ZpLxR3mNb"
  }'
```

**Resposta** — `202 Accepted`

```json
{
  "success": true,
  "source_id": "kb_src_abc123",
  "status": "queued"
}
```

| Estado | Quando |
|---|---|
| `400` | Falta um campo obrigatório, ou o ficheiro não é de um tipo que possamos ler. |
| `403` | `storage_path` está fora da sua própria pasta de carregamentos. |

---

## Verificar uma fonte

`GET /kb-sources/{sourceId}`

A consulta que se segue a cada importação e atualização. Repita-a até que o estado seja `ready` ou `failed`.

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/kb-sources/kb_src_abc123?apiKey=YOUR_API_KEY"
```

**JavaScript**

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

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/kb-sources/kb_src_abc123",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
source = res.json()
```

**Resposta**

```json
{
  "success": true,
  "source_id": "kb_src_abc123",
  "status": "ready",
  "faq_count": 24,
  "section_count": 31,
  "error_message": null
}
```

| Campo | Tipo | Descrição |
|---|---|---|
| `status` | string | Onde a origem se encontra no pipeline (consulte a [tabela de estado](#how-an-import-works)). |
| `faq_count` | integer | Quantas FAQs foram geradas a partir desta origem até ao momento. |
| `section_count` | integer | Em quantas secções de conteúdo a origem foi dividida. |
| `error_message` | string \| null | O motivo da falha da importação, quando o estado é `failed`. `null` caso contrário. |

---

## Eliminar uma origem

`DELETE /kb-sources/{sourceId}`

Remove uma origem de conhecimento. **Por predefinição, as FAQs produzidas pela mesma são mantidas** — adicione `delete_faqs=true` para as remover também.

**Parâmetros de consulta**

| Parâmetro | Obrigatório | Descrição |
|---|---|---|
| `delete_faqs` | Não | Defina como `true` para eliminar também todas as FAQs que esta origem produziu. O valor predefinido é `false`. |

**cURL**

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/kb-sources/kb_src_abc123?delete_faqs=true&apiKey=YOUR_API_KEY"
```

**Resposta**

```json
{
  "success": true,
  "faqs_deleted": 24
}
```

`faqs_deleted` é `0`, a menos que tenha solicitado `delete_faqs=true`.

---

## Importar várias páginas de uma só vez

`POST /kb-sources/bulk-import`

Adiciona até 100 páginas web numa única chamada — o seguimento habitual de [Descobrir páginas num website](#discover-pages-on-a-website) ou [Encontrar novas páginas num website](#find-new-pages-on-a-website). As páginas que já se encontram na sua base de conhecimento são ignoradas em vez de duplicadas (e continuam ligadas ao Agente quando solicitado).

**Campos do pedido**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `urls` | Sim | Endereços a importar. Pelo menos 1, no máximo 100 por chamada. |
| `autoLinkToAgentId` | Não | ID de um Agente de IA ao qual associar cada página importada. |
| `autoLinkToCampaignId` | Não | Legado. ID de uma campanha à qual associar cada página importada. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/kb-sources/bulk-import?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "urls": ["https://example.com/pricing", "https://example.com/faq"],
    "autoLinkToAgentId": "ag7HkQ2ZpLxR3mNb"
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/kb-sources/bulk-import", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    urls: ["https://example.com/pricing", "https://example.com/faq"],
    autoLinkToAgentId: "ag7HkQ2ZpLxR3mNb",
  }),
});
const { queued_source_ids } = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/kb-sources/bulk-import",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "urls": ["https://example.com/pricing", "https://example.com/faq"],
        "autoLinkToAgentId": "ag7HkQ2ZpLxR3mNb",
    },
)
queued_source_ids = res.json()["queued_source_ids"]
```

**Resposta** — `202 Accepted`

```json
{
  "success": true,
  "batch_id": "batch_9f2a",
  "queued": 2,
  "skipped_duplicate": 0,
  "queued_source_ids": ["kb_src_abc123", "kb_src_def456"]
}
```

Consulte cada ID em `queued_source_ids` com [Verificar uma origem](#check-a-source). O envio de uma matriz `urls` vazia, uma entrada que não seja uma string ou mais de 100 entradas devolve `400`.

---

## Eliminar várias origens de uma só vez

`POST /kb-sources/bulk-delete`

Remove até 2.000 origens de conhecimento numa única chamada. A remoção é executada em segundo plano e receberá um e-mail quando terminar.

> **A eliminação em massa remove sempre as FAQs também.** Ao contrário de [Eliminar uma fonte](#delete-a-source), que as mantém a menos que peça o contrário, este endpoint elimina cada fonte juntamente com as FAQs que produziu. Não existe opção para as manter.

**Campos do pedido**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `sourceIds` | Sim | IDs das fontes a remover. Pelo menos 1, no máximo 2.000 por chamada. |
| `domainLabel` | Não | Um nome amigável para esta limpeza. Usado apenas no e-mail de conclusão. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/kb-sources/bulk-delete?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sourceIds": ["kb_src_abc123", "kb_src_def456"],
    "domainLabel": "example.com"
  }'
```

**Resposta** — `202 Accepted`

```json
{
  "success": true,
  "batch_id": "del_batch_31a",
  "queued": 2
}
```

---

## Descobrir páginas num site

`POST /kb-sources/discover-pages`

Explora um site a partir de um endereço inicial e lista as páginas encontradas no mesmo domínio, cada uma com uma opinião sobre se vale a pena importar. **Nada é importado e nada é selecionado por si** — este é o passo "o que existe neste site" que executa antes de decidir o que enviar para [Importar muitas páginas de uma vez](#import-many-pages-at-once).

**Campos do pedido**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `url` | Sim | Endereço a partir do qual começar a explorar, normalmente a página inicial do site. |
| `maxPages` | Não | Limite superior de quantas páginas devolver. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/kb-sources/discover-pages?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://example.com", "maxPages": 100 }'
```

**Resposta**

```json
{
  "success": true,
  "source_type": "sitemap",
  "pages": [
    {
      "url": "https://example.com/pricing",
      "title": "Pricing",
      "depth": 1,
      "score": 95,
      "recommendation": "add",
      "reason_key": "core_page"
    }
  ]
}
```

| Campo | Tipo | Descrição |
|---|---|---|
| `source_type` | string | Como as páginas foram encontradas — `sitemap` (o sitemap do próprio site) ou `link_discovery` (seguindo links). |
| `url` | string | Endereço completo da página. |
| `title` | string \| null | Título da página, quando foi possível lê-lo. |
| `depth` | integer | A quantos links de distância da página inicial esta página foi encontrada. |
| `score` | integer | Quão útil a página parece como conhecimento, de `0` a `100`. |
| `recommendation` | string | `add` (claramente vale a pena importar, pontuação 90 ou superior), `maybe` (limítrofe), ou `skip` (conteúdo que raramente ajuda um assistente — registos de alterações, páginas legais, traduções duplicadas). |
| `reason_key` | string | Uma razão estável e legível por máquina por trás da recomendação, por exemplo `core_page`, `changelog_history`, `legal_page` ou `locale_duplicate`. |

> **A exploração é feita com o melhor esforço.** Se o site não puder ser lido, a resposta é ainda `200`, com `success: false`, uma lista `pages` vazia e uma mensagem `error`. Verifique `success` antes de ler `pages`.

Um `url` em falta devolve `400`.

---

## Estimar o custo de uma importação

`POST /kb-sources/estimate-cost`

Calcula quantos créditos uma importação proposta consumiria, antes de se comprometer com ela. As páginas são obtidas e os documentos são lidos para medir o seu tamanho, mas nada é importado e a estimativa em si não gasta créditos.

**Campos do pedido**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `urls` | Não | Endereços de páginas que está a considerar importar. |
| `files` | Não | Ficheiros já carregados que está a considerar. Cada entrada precisa de `storage_path`, `filename` e `mime_type`. |
| `tier` | Não | O nível de qualidade de IA em que a importação será executada, para que a estimativa corresponda ao que lhe será realmente cobrado. Deixe de fora para a taxa padrão. |

Envie `urls`, `files`, ou ambos.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/kb-sources/estimate-cost?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "urls": ["https://example.com/pricing"] }'
```

**Resposta**

```json
{
  "success": true,
  "estimates": [
    { "ref": "https://example.com/pricing", "chunks": 7, "credits": 7 }
  ],
  "total_chunks": 7,
  "total_credits": 7
}
```

Cada linha reflete o URL ou caminho de armazenamento em `ref` para que possa correspondê-lo à sua entrada. Uma página ou ficheiro que não pôde ser lido ainda recebe uma linha, contada como um bloco, com um `error` associado.

---

## Parar uma importação

`POST /kb-sources/cancel-import`

Para as páginas que ainda estão à espera na fila de importação — o botão "parar importação" para uma pesquisa que se revelou maior do que esperava. Cancelar uma página em espera não tem custos, porque ainda não foi lida.

As páginas que já estão a ser processadas **não** são paradas: o seu trabalho está em curso e é cobrado de qualquer forma, por isso concluem o processo. A resposta indica quantas foram.

**Campos do pedido**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `host` | Não | Parar apenas as páginas em espera neste website (por exemplo `docs.example.com`). Deixe em branco para parar todas as importações em espera na conta. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/kb-sources/cancel-import?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "host": "docs.example.com" }'
```

**Resposta**

```json
{
  "success": true,
  "cancelled": 412,
  "in_flight": 3
}
```

---

## Retomar uma importação pausada

`POST /kb-sources/resume-import`

Reinicia uma importação que foi pausada porque a sua própria chave de IA deixou de funcionar.

> Ao chamar isto, está a dar o seu consentimento para concluir a importação com a chave que estiver ativa no momento — o que pode significar gastar créditos da plataforma se a sua própria chave continuar inativa.

**Campos do pedido**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `host` | Não | Retomar apenas as páginas pausadas neste website. Deixe em branco para retomar tudo o que está pausado. |

**cURL**

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

**Resposta**

```json
{
  "success": true,
  "resumed": 58
}
```

---

## Encontrar novas páginas num website

`POST /kb-sources/refresh-domain`

Explora um website do qual já importou e reporta apenas as páginas que ainda **não** estão na sua base de conhecimento, cada uma com a mesma recomendação que a descoberta de páginas. Nada é importado e nada é alterado.

As duas ações de seguimento são chamadas deliberadamente separadas, pelo que desistir desta não tem qualquer custo:

- importe as novas páginas que pretende com [Importar várias páginas de uma vez](#import-many-pages-at-once);
- releia as páginas que já possui com [Atualizar todas as páginas de um site](#refresh-every-page-on-a-website).

**Campos do pedido**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `baseUrl` | Sim | Qualquer endereço no site, ou apenas o host. |
| `maxPages` | Não | Limite superior de quantas páginas explorar. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/kb-sources/refresh-domain?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "baseUrl": "https://example.com" }'
```

**Resposta**

```json
{
  "success": true,
  "source_type": "sitemap",
  "discovered": 249,
  "new_pages": [
    {
      "url": "https://example.com/new-guide",
      "score": 95,
      "recommendation": "add",
      "reason_key": "core_page"
    }
  ],
  "new_urls_queued": 0,
  "existing_refresh_queued": 249
}
```

| Campo | Tipo | Descrição |
|---|---|---|
| `discovered` | integer | Quantas páginas foram encontradas no site no total. |
| `new_pages` | array | Páginas que ainda não estão na sua base de conhecimento. Nada é colocado em fila para si — importe as que desejar. |
| `new_urls_queued` | integer | Sempre `0`. Mantido por retrocompatibilidade; este endpoint nunca coloca nada em fila. |
| `existing_refresh_queued` | integer | Quantas páginas que já importou deste site foram encontradas prontas para serem relidas. Nada é colocado em fila por esta chamada. |
| `batch_id` | string | Presente apenas quando um lote foi criado. |

Tal como a descoberta, isto falha de forma suave: um site que não pode ser lido ainda devolve `200`, com `success: false`, um `new_pages` vazio e um `error`. Um `baseUrl` em falta ou vazio devolve `400`.

---

## Atualizar todas as páginas de um site

`POST /kb-sources/trigger-domain-refresh`

Releia todas as páginas que já importou de um site, para que as suas FAQs sigam o conteúdo atual do site: as secções alteradas são atualizadas, as novas secções são adicionadas e as secções removidas são eliminadas.

Isto coloca o trabalho em fila e devolve imediatamente. Acompanhe com [Acompanhar a atualização de um site](#track-a-website-refresh) e pare com [Parar a atualização de um site](#stop-a-website-refresh).

**Campos do pedido**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `baseUrl` | Sim | Qualquer endereço no site, ou apenas o host. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/kb-sources/trigger-domain-refresh?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "baseUrl": "https://example.com" }'
```

**Resposta**

```json
{
  "success": true,
  "queued": 249
}
```

---

## Acompanhar a atualização de um site

`GET /kb-sources/domain-refresh-status`

O estado de progresso da atualização de um site, para que possa mostrar o progresso como "221 de 249".

**Parâmetros de consulta**

| Parâmetro | Obrigatório | Descrição |
|---|---|---|
| `baseUrl` | Sim | Qualquer endereço no site, ou apenas o host. |

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/kb-sources/domain-refresh-status?baseUrl=https://example.com&apiKey=YOUR_API_KEY"
```

**Resposta**

```json
{
  "success": true,
  "job": {
    "domainBatchId": "job_7c1e",
    "host": "example.com",
    "total": 249,
    "pending": 28,
    "succeeded": 219,
    "failed": 2,
    "skippedDuplicate": 0,
    "status": "refreshing",
    "startedAtIso": "2026-06-15T09:00:00.000Z"
  }
}
```

`job` é `null` quando não existe nenhuma atualização em curso para esse site. As páginas concluídas até ao momento são `total` menos `pending`. O trabalho `status` é um de `refreshing` (ainda a processar páginas), `deduplicating` (a passagem de limpeza no final), ou o final `completed`, `failed` e `cancelled`. Guarde o `domainBatchId` — é o que passa para o endpoint de cancelamento.

Um `baseUrl` em falta ou vazio devolve `400`.

---

## Parar a atualização de um site

`POST /kb-sources/refresh-domain/cancel`

Para a atualização de um site que ainda está a processar as suas páginas. As páginas já concluídas mantêm o seu conteúdo atualizado; as páginas que ainda não foram iniciadas são descartadas e as páginas que estavam a ser lidas novamente regressam ao seu estado anterior.

**Campos do pedido**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `jobId` | Sim | O `domainBatchId` devolvido por [Monitorizar a atualização de um site](#track-a-website-refresh). |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/kb-sources/refresh-domain/cancel?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "jobId": "job_7c1e" }'
```

**Resposta**

```json
{
  "success": true,
  "status": "cancelled",
  "cancelled_units": 28,
  "sources_reset": 3,
  "sources_cancelled": 25
}
```

| Campo | Tipo | Descrição |
|---|---|---|
| `status` | string | Estado da atualização após esta chamada: `cancelled`, `deduplicating`, `completed` ou `failed`. |
| `cancelled_units` | integer | Quanto trabalho ainda estava pendente quando o cancelamento foi efetuado. `0` num cancelamento repetido. |
| `sources_reset` | integer | Páginas retiradas do processamento e devolvidas a `ready`. |
| `sources_cancelled` | integer | Páginas novas desta atualização que ainda estavam na fila e foram agora canceladas. |

Cancelar duas vezes não tem consequências — a segunda chamada reporta o mesmo estado final. Uma vez que a atualização tenha avançado para a fase de limpeza, já não pode ser parada e a resposta devolve `success: false` e `reason: "already_finalizing"`. Um `jobId` em falta devolve `400`, e um trabalho que não se encontra na sua conta devolve `404`.

---

## Atualizar uma única fonte

`POST /kb-sources/{sourceId}/refresh`

Lê novamente uma página web que já importou e alinha as suas FAQ com o conteúdo atual da página: as secções alteradas são atualizadas, as novas são adicionadas e as removidas são descartadas.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/kb-sources/kb_src_abc123/refresh?apiKey=YOUR_API_KEY"
```

**Resposta** — `202 Accepted`

```json
{
  "success": true,
  "source_id": "kb_src_abc123",
  "status": "queued"
}
```

Consulte a fonte até que o seu estado saia de `queued` e `processing`. Um ID de fonte que não se encontre na sua conta devolve `404`.

---

## Escolher as páginas mais relevantes

`POST /kb-sources/select-relevant-pages`

Solicita à IA que escolha as cinco páginas, de uma lista de candidatas, que melhor descrevem um negócio — utilizado ao gerar um manual de campanha a partir de um site. Isto consome créditos.

**Campos do pedido**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `urls` | Sim | Endereços das páginas candidatas a escolher, normalmente provenientes da descoberta de páginas. |
| `homeUrl` | Sim | A página inicial do site, utilizada como contexto para a escolha. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/kb-sources/select-relevant-pages?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "homeUrl": "https://example.com",
    "urls": ["https://example.com/about", "https://example.com/pricing"]
  }'
```

**Resposta**

```json
{
  "success": true,
  "pages": [
    { "url": "https://example.com/pricing", "title": "Pricing", "type": "pricing" }
  ]
}
```

Este é um auxiliar, não um recurso: em caso de falha, responde na mesma com `200`, com `success: false`, uma lista `pages` vazia e uma mensagem `error`.

---

## Grupos de conhecimento

Um **grupo de conhecimento** é um conjunto nomeado de FAQs — "Envios e devoluções", "Integração" — que pode aplicar a um Agente ou a uma campanha numa única chamada. O grupo contém referências, não cópias: as próprias FAQs permanecem na sua biblioteca única, pelo que editar uma com a [API de FAQs](faqs.md) atualiza-a em todos os locais onde é utilizada.

Aplicar um grupo apenas **adiciona** o que falta, pelo que aplicar o mesmo grupo duas vezes é inofensivo e `added_count` devolve `0` na segunda vez.

---

## Criar um grupo de conhecimento

`POST /kb-groups`

Cria um grupo. Começa vazio — adicione-lhe FAQs com [Adicionar uma FAQ a um grupo](#add-a-faq-to-a-group).

**Campos do pedido**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `name` | Sim | Nome do grupo. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/kb-groups?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Shipping and returns" }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/kb-groups", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ name: "Shipping and returns" }),
});
const { group_id } = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/kb-groups",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"name": "Shipping and returns"},
)
group_id = res.json()["group_id"]
```

**Resposta** — `201 Created`

```json
{
  "success": true,
  "group_id": "kbg_abc123"
}
```

---

## Mudar o nome de um grupo de conhecimento

`PUT /kb-groups/{groupId}`

Altera o nome de um grupo. As suas FAQs permanecem inalteradas.

**Campos do pedido**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `name` | Sim | Novo nome do grupo. |

**cURL**

```bash
curl -X PUT "https://api.youraiconnector.com/v1/kb-groups/kbg_abc123?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Shipping, returns and refunds" }'
```

**Resposta**

```json
{
  "success": true,
  "group_id": "kbg_abc123",
  "name": "Shipping, returns and refunds"
}
```

---

## Eliminar um grupo de conhecimento

`DELETE /kb-groups/{groupId}`

Elimina o grupo. Apenas o conjunto é removido — as FAQs nele contidas permanecem na sua biblioteca e tudo ao que o grupo já tinha sido aplicado mantém essas FAQs.

**cURL**

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/kb-groups/kbg_abc123?apiKey=YOUR_API_KEY"
```

**Resposta**

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

---

## Adicionar uma FAQ a um grupo

`POST /kb-groups/{groupId}/faqs`

Coloca uma FAQ existente num grupo. Isto apenas altera o pacote — não associa a FAQ a nenhum Agente por si só; aplique o grupo para esse efeito.

**Campos do pedido**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `faq_id` | Sim | ID da FAQ a adicionar. |

**cURL**

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

**Resposta**

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

---

## Remover uma FAQ de um grupo

`DELETE /kb-groups/{groupId}/faqs/{faqId}`

Retira uma FAQ de um grupo. A FAQ em si não é eliminada e os Agentes aos quais o grupo já tinha sido aplicado mantêm-na.

**cURL**

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/kb-groups/kbg_abc123/faqs/aBcD1234eFgH5678?apiKey=YOUR_API_KEY"
```

**Resposta**

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

---

## Aplicar um grupo a um Agente

`POST /kb-groups/{groupId}/apply-to-agent`

Adiciona todas as FAQs do grupo ao conhecimento de um Agente de IA numa única chamada — a forma rápida de fornecer a um novo Agente um conjunto de conhecimentos que já tenha organizado.

**Campos do pedido**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `agent_id` | Sim | ID do Agente de IA ao qual aplicar o grupo. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/kb-groups/kbg_abc123/apply-to-agent?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "agent_id": "ag7HkQ2ZpLxR3mNb" }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/kb-groups/kbg_abc123/apply-to-agent",
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ agent_id: "ag7HkQ2ZpLxR3mNb" }),
  }
);
const { added_count } = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/kb-groups/kbg_abc123/apply-to-agent",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"agent_id": "ag7HkQ2ZpLxR3mNb"},
)
added_count = res.json()["added_count"]
```

**Resposta**

```json
{
  "success": true,
  "group_id": "kbg_abc123",
  "agent_id": "ag7HkQ2ZpLxR3mNb",
  "added_count": 12
}
```

`added_count` é o número de FAQs que foram efetivamente adicionadas — `0` quando o grupo está vazio ou já foi aplicado.

---

## Aplicar um grupo a uma campanha

`POST /kb-groups/{groupId}/apply-to-campaign`

A versão de campanha clássica da chamada acima. Numa conta baseada em Agentes, utilize [Aplicar um grupo a um Agente](#apply-a-group-to-an-agent) em vez disso.

**Campos do pedido**

| Campo | Obrigatório | Descrição |
|---|---|---|
| `campaign_id` | Sim | ID da campanha à qual aplicar o grupo. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/kb-groups/kbg_abc123/apply-to-campaign?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "campaign_id": "campaign123" }'
```

**Resposta**

```json
{
  "success": true,
  "group_id": "kbg_abc123",
  "campaign_id": "campaign123",
  "added_count": 12
}
```

---

## Erros da API da Base de Conhecimento

Estes endpoints devolvem o envelope de erro padrão:

```json
{
  "success": false,
  "error": "Knowledge base source not found."
}
```

| Estado | Quando ocorre num endpoint da base de conhecimento |
|---|---|
| `400` | Falta um campo obrigatório ou é inválido — um `url` vazio, um `baseUrl` ou `jobId` em falta, mais de 100 URLs numa importação em massa, mais de 2.000 IDs numa eliminação em massa, ou um tipo de ficheiro que não conseguimos ler. |
| `402` | Créditos insuficientes para executar a importação. Carregue a conta e tente novamente. |
| `403` | Um `storage_path` fora da sua própria pasta de carregamentos — ou o seu plano não inclui acesso à API. |
| `404` | A fonte, grupo, FAQ, Agente, campanha ou tarefa de atualização não foi encontrada — ou não existe ou pertence a outra conta. |

> **As falhas parciais não são erros.** A descoberta (`discover-pages`, `refresh-domain`) e o auxiliar de seleção de páginas respondem `200` com `success: false` e uma mensagem `error` quando o website não pode ser lido, em vez de falhar o pedido. Verifique sempre `success` antes de ler os dados.

Os códigos partilhados que qualquer endpoint pode devolver — `401`, `403` (o seu plano não inclui acesso à API), `429` (limite de taxa) e `500` — estão listados com orientações de repetição em [Erros e Paginação](errors-and-pagination.md).

---

## Relacionado

- [API de FAQs](faqs.md) — leia, edite e associe as FAQs que as suas fontes produzem.
- [Gerir FAQs](../ai-automation/faq-management.md) — a mesma base de conhecimento no painel de controlo.
- [Agentes de IA](../ai-agents/ai-agents.md) — os Agentes aos quais associa fontes e grupos.
- [Acesso à API](../integrations/api-access.md) — gere a sua chave de API.
- [Autenticação](authentication.md) — todas as formas de transmitir a sua chave.
