
# API della Knowledge Base

La tua knowledge base è ciò da cui l'IA attinge le informazioni. È composta da due parti, ed entrambe sono trattate in questa pagina:

- **Fonti di conoscenza** (`/kb-sources`) — le pagine web e i documenti caricati che fornisci alla piattaforma. Ognuno viene letto, suddiviso in sezioni e trasformato in FAQ a cui la tua IA può rispondere.
- **Gruppi di conoscenza** (`/kb-groups`) — pacchetti denominati di FAQ che puoi applicare a un Agente o a una campagna con una singola chiamata, in modo che un corpo di conoscenze già curato possa essere riutilizzato sul prossimo Agente che creerai.

Le FAQ prodotte da una fonte finiscono nella stessa libreria di quelle scritte a mano, quindi una volta terminata l'importazione puoi leggerle, modificarle e collegarle con le [API delle FAQ](faqs.md).

Tutti gli endpoint seguenti sono relativi all'URL di base `https://api.youraiconnector.com/v1`. Ogni richiesta deve essere autenticata: consulta [Accesso API](../integrations/api-access.md) e [Autenticazione](authentication.md). L'accesso all'API è una funzionalità a pagamento; in caso contrario, le richieste verranno rifiutate con un `403`.


> **L'importazione consuma crediti.** Leggere una pagina o un documento e scrivere FAQ a partire da essi consuma crediti, approssimativamente in proporzione alla quantità di contenuti. Usa [Stima un'importazione](#estimate-what-an-import-will-cost) prima di procedere con una scansione di grandi dimensioni.

---

## Come funziona un'importazione

L'importazione è un processo in background, non qualcosa che termina mentre attendi. Ogni endpoint di importazione risponde immediatamente con un `source_id`, e tu interroghi quella fonte finché non è completata:

1. **Avvia l'importazione** — `POST /kb-sources/url` (una pagina), `POST /kb-sources/file` (un documento caricato), o `POST /kb-sources/bulk-import` (fino a 100 pagine). Riceverai un ID sorgente e un `status: "queued"`.
2. **Interroga** — `GET /kb-sources/{sourceId}` finché `status` non è più `queued` o `processing`.
3. **Leggi le FAQ** — quando lo stato è `ready`, le voci prodotte si trovano nella tua libreria FAQ: `GET /faqs`.

Ogni fonte riporta uno di questi stati:

| Stato | Cosa significa |
|---|---|
| `queued` | In attesa di essere letto. Non è stato ancora addebitato nulla. |
| `processing` | In fase di lettura e conversione in FAQ. |
| `ready` | Completato. Le sue FAQ sono nella tua libreria. |
| `failed` | Impossibile importare. `error_message` indica il motivo. |
| `cancelled` | Interrotto prima della lettura (vedi [Interrompi un'importazione](#stop-an-import)). |
| `paused` | Interrotto perché la tua chiave IA ha fallito durante l'importazione (vedi [Riprendi un'importazione in pausa](#resume-a-paused-import)). |
| `deleting` | È in corso una rimozione in blocco. |
| `unknown` | Il record non ha uno stato. Consideralo come non pronto. |

> **Collega durante l'importazione.** Passa `autoLinkToAgentId` su qualsiasi endpoint di importazione e la fonte — insieme a ogni FAQ che produce — verrà aggiunta alla knowledge base di quell'Agente nella stessa chiamata, senza passaggi di collegamento successivi. `autoLinkToCampaignId` fa lo stesso per una campagna classica. Il collegamento è un tentativo: un ID che non esiste, o che appartiene a un altro account, viene ignorato silenziosamente e l'importazione viene comunque eseguita, quindi conferma il collegamento leggendo nuovamente l'Agente.

---

## Importa una pagina web

`POST /kb-sources/url`

Aggiunge una pagina web alla tua knowledge base.

**Campi della richiesta**

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `url` | Sì | Indirizzo `http` o `https` completo della pagina. |
| `autoLinkToAgentId` | No | ID di un Agente IA a cui collegare la fonte importata. |
| `autoLinkToCampaignId` | No | Legacy. ID di una campagna a cui collegare la fonte importata. |

**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")
```

**Risposta** — `202 Accepted`

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

Esegui il polling di `source_id` con [Controlla una fonte](#check-a-source) finché lo stato non è `ready` o `failed`.

Se la stessa pagina è già presente nella tua knowledge base, non viene accodato nulla di nuovo e riceverai invece un `200` — e se hai richiesto un collegamento automatico, la fonte esistente verrà comunque collegata per te:

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

Un `url` mancante, o uno che non è un indirizzo `http`/`https` valido, restituisce `400`.

---

## Importa un documento caricato

`POST /kb-sources/file`

Aggiunge un documento che si trova **già nell'archivio file del tuo account** come fonte di conoscenza. Tipi supportati: PDF, DOCX, TXT, MD, CSV e XLSX.

> **Questo endpoint non trasporta il file.** Non c'è caricamento multipart, nessun corpo base64 e nessun download da un URL: invii la posizione di archiviazione di un file che esiste già, e deve trovarsi nella tua cartella di caricamento (`storage_path` deve iniziare con `users/{your user id}/uploads/`) o la richiesta verrà rifiutata con `403`. La dashboard inserisce i file lì quando li trascini. Se non hai modo di inserire un file lì, importa una pagina web con [Importa una pagina web](#import-a-web-page) in alternativa.

**Campi della richiesta**

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `storage_path` | Sì | Dove risiede il file caricato. Deve iniziare con `users/{your user id}/uploads/`. |
| `filename` | Sì | Nome originale del file inclusa l'estensione — è così che viene rilevato il tipo di file. |
| `mime_type` | Sì | Tipo MIME del file, ad esempio `application/pdf`. |
| `autoLinkToAgentId` | No | ID di un Agente IA a cui collegare il documento. |
| `autoLinkToCampaignId` | No | Legacy. ID di una campagna a cui collegare il 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"
  }'
```

**Risposta** — `202 Accepted`

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

| Stato | Quando |
|---|---|
| `400` | Manca un campo obbligatorio, o il file non è di un tipo leggibile. |
| `403` | `storage_path` si trova al di fuori della tua cartella di caricamento. |

---

## Controlla una fonte

`GET /kb-sources/{sourceId}`

Il polling che segue ogni importazione e aggiornamento. Ripetilo finché lo stato non è `ready` o `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()
```

**Risposta**

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

| Campo | Tipo | Descrizione |
|---|---|---|
| `status` | string | Dove si trova la sorgente nella pipeline (vedi la [tabella dello stato](#how-an-import-works)). |
| `faq_count` | integer | Quante FAQ sono state generate da questa sorgente finora. |
| `section_count` | integer | In quante sezioni di contenuto è stata suddivisa la sorgente. |
| `error_message` | string \| null | Perché l'importazione non è riuscita, quando lo stato è `failed`. `null` altrimenti. |

---

## Eliminare una sorgente

`DELETE /kb-sources/{sourceId}`

Rimuove una sorgente di conoscenza. **Per impostazione predefinita, le FAQ prodotte vengono conservate** — aggiungi `delete_faqs=true` per rimuovere anche quelle.

**Parametri di query**

| Parametro | Obbligatorio | Descrizione |
|---|---|---|
| `delete_faqs` | No | Imposta su `true` per eliminare anche ogni FAQ prodotta da questa sorgente. Il valore predefinito è `false`. |

**cURL**

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

**Risposta**

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

`faqs_deleted` è `0` a meno che tu non abbia richiesto `delete_faqs=true`.

---

## Importare molte pagine contemporaneamente

`POST /kb-sources/bulk-import`

Aggiunge fino a 100 pagine web in una sola chiamata — il consueto seguito di [Scoprire pagine su un sito web](#discover-pages-on-a-website) o [Trovare nuove pagine su un sito web](#find-new-pages-on-a-website). Le pagine già presenti nella tua base di conoscenza vengono ignorate invece di essere duplicate (e rimangono collegate all'Agente quando richiesto).

**Campi della richiesta**

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `urls` | Sì | Indirizzi da importare. Almeno 1, al massimo 100 per chiamata. |
| `autoLinkToAgentId` | No | ID di un Agente IA a cui collegare ogni pagina importata. |
| `autoLinkToCampaignId` | No | Legacy. ID di una campagna a cui collegare ogni pagina importata. |

**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"]
```

**Risposta** — `202 Accepted`

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

Esegui il polling di ogni ID in `queued_source_ids` con [Controllare una sorgente](#check-a-source). L'invio di un array `urls` vuoto, di una voce non stringa o di più di 100 voci restituisce `400`.

---

## Eliminare molte sorgenti contemporaneamente

`POST /kb-sources/bulk-delete`

Rimuove fino a 2.000 sorgenti di conoscenza in una sola chiamata. La rimozione viene eseguita in background e riceverai un'email al termine dell'operazione.

> **L'eliminazione in blocco rimuove sempre anche le FAQ.** A differenza di [Elimina una fonte](#delete-a-source), che le conserva a meno che non venga richiesto diversamente, questo endpoint elimina ogni fonte insieme alle FAQ che ha prodotto. Non c'è opzione per conservarle.

**Campi della richiesta**

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `sourceIds` | Sì | ID delle fonti da rimuovere. Almeno 1, al massimo 2.000 per chiamata. |
| `domainLabel` | No | Un nome descrittivo per questa operazione di pulizia. Utilizzato solo nell'email di completamento. |

**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"
  }'
```

**Risposta** — `202 Accepted`

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

---

## Esplora le pagine di un sito web

`POST /kb-sources/discover-pages`

Esplora un sito web partendo da un indirizzo iniziale ed elenca le pagine trovate sullo stesso dominio, ognuna con un parere sull'opportunità di importarla. **Non viene importato nulla e non viene selezionato nulla per te**: questo è il passaggio "cosa c'è su questo sito" da eseguire prima di decidere cosa inviare a [Importa molte pagine contemporaneamente](#import-many-pages-at-once).

**Campi della richiesta**

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `url` | Sì | Indirizzo da cui iniziare l'esplorazione, solitamente la home page del sito. |
| `maxPages` | No | Limite massimo al numero di pagine da restituire. |

**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 }'
```

**Risposta**

```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 | Descrizione |
|---|---|---|
| `source_type` | string | Come sono state trovate le pagine: `sitemap` (la sitemap del sito) o `link_discovery` (seguendo i link). |
| `url` | string | Indirizzo completo della pagina. |
| `title` | string \| null | Titolo della pagina, quando leggibile. |
| `depth` | integer | A quanti link di distanza dalla pagina iniziale è stata trovata questa pagina. |
| `score` | integer | Quanto la pagina appare utile come conoscenza, da `0` a `100`. |
| `recommendation` | string | `add` (chiaramente utile da importare, punteggio 90 o superiore), `maybe` (al limite), o `skip` (contenuto che raramente aiuta un assistente: changelog, pagine legali, traduzioni duplicate). |
| `reason_key` | string | Un motivo stabile e leggibile dalla macchina alla base della raccomandazione, ad esempio `core_page`, `changelog_history`, `legal_page` o `locale_duplicate`. |

> **L'esplorazione è un tentativo.** Se il sito non può essere letto, la risposta è comunque `200`, con `success: false`, un elenco `pages` vuoto e un messaggio `error`. Controlla `success` prima di leggere `pages`.

Un `url` mancante restituisce `400`.

---

## Stima il costo di un'importazione

`POST /kb-sources/estimate-cost`

Calcola quanti crediti consumerebbe un'importazione proposta, prima di impegnarsi. Le pagine vengono recuperate e i documenti letti per misurarne la dimensione, ma non viene importato nulla e la stima stessa non consuma crediti.

**Campi della richiesta**

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `urls` | No | Indirizzi delle pagine che stai valutando di importare. |
| `files` | No | File già caricati che stai valutando. Ogni voce richiede `storage_path`, `filename` e `mime_type`. |
| `tier` | No | Il livello di qualità dell'IA su cui verrà eseguita l'importazione, in modo che la stima corrisponda a ciò che ti verrà effettivamente addebitato. Lascialo vuoto per la tariffa standard. |

Invia `urls`, `files`, o entrambi.

**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"] }'
```

**Risposta**

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

Ogni riga riporta l'URL o il percorso di archiviazione in `ref` in modo da poterlo abbinare al tuo input. Una pagina o un file che non è stato possibile leggere ottiene comunque una riga, conteggiata come un chunk, con un `error` sopra.

---

## Interrompere un'importazione

`POST /kb-sources/cancel-import`

Interrompe le pagine ancora in attesa nella coda di importazione: il pulsante "interrompi importazione" per una scansione che si è rivelata più grande del previsto. Annullare una pagina in attesa non costa nulla, poiché non è ancora stata letta.

Le pagine già in fase di elaborazione **non** vengono interrotte: il loro lavoro è in corso e viene addebitato in ogni caso, quindi vengono completate. La risposta riporta quante erano.

**Campi della richiesta**

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `host` | No | Interrompe solo le pagine in attesa su questo sito web (ad esempio `docs.example.com`). Lascialo vuoto per interrompere ogni importazione in attesa sull'account. |

**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" }'
```

**Risposta**

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

---

## Riprendere un'importazione in pausa

`POST /kb-sources/resume-import`

Riavvia un'importazione che era stata messa in pausa perché la tua chiave AI ha smesso di funzionare.

> Chiamare questo metodo **costituisce** il tuo consenso a completare l'importazione con qualsiasi chiave sia attiva in quel momento, il che potrebbe significare spendere crediti della piattaforma se la tua chiave è ancora inattiva.

**Campi della richiesta**

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `host` | No | Riprende solo le pagine in pausa su questo sito web. Lascialo vuoto per riprendere tutto ciò che è in pausa. |

**cURL**

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

**Risposta**

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

---

## Trovare nuove pagine su un sito web

`POST /kb-sources/refresh-domain`

Esplora un sito web da cui hai già effettuato un'importazione e segnala solo le pagine che **non** sono ancora presenti nella tua base di conoscenza, ognuna con lo stesso consiglio della scoperta delle pagine. Nulla viene importato e nulla viene modificato.

I due passaggi successivi sono chiamate deliberatamente separate, quindi abbandonare questa operazione non costa nulla:

- importa le nuove pagine che desideri con [Importa molte pagine contemporaneamente](#import-many-pages-at-once);
- rileggi le pagine che già possiedi con [Aggiorna ogni pagina di un sito web](#refresh-every-page-on-a-website).

**Campi della richiesta**

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `baseUrl` | Sì | Qualsiasi indirizzo sul sito web, o solo l'host. |
| `maxPages` | No | Limite superiore al numero di pagine da esplorare. |

**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" }'
```

**Risposta**

```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 | Descrizione |
|---|---|---|
| `discovered` | integer | Quante pagine sono state trovate in totale sul sito. |
| `new_pages` | array | Pagine non ancora presenti nella tua base di conoscenza. Non viene accodato nulla per te: importa quelle che desideri. |
| `new_urls_queued` | integer | Sempre `0`. Mantenuto per compatibilità con le versioni precedenti; questo endpoint non accoda mai nulla. |
| `existing_refresh_queued` | integer | Quante pagine già importate da questo sito sono state trovate pronte per essere rilette. Nulla viene accodato da questa chiamata. |
| `batch_id` | string | Presente solo quando è stato creato un batch. |

Come per l'individuazione, questo fallisce in modo non bloccante: un sito che non può essere letto restituisce comunque `200`, con `success: false`, un `new_pages` vuoto e un `error`. Un `baseUrl` mancante o vuoto restituisce `400`.

---

## Aggiorna ogni pagina di un sito web

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

Rilegge ogni pagina che hai già importato da un sito web, in modo che le sue FAQ seguano il contenuto attuale del sito: le sezioni modificate vengono aggiornate, quelle nuove aggiunte e quelle rimosse eliminate.

Questo accoda il lavoro e restituisce immediatamente. Segui con [Monitora l'aggiornamento di un sito web](#track-a-website-refresh) e interrompilo con [Interrompi l'aggiornamento di un sito web](#stop-a-website-refresh).

**Campi della richiesta**

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `baseUrl` | Sì | Qualsiasi indirizzo sul sito web, o solo l'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" }'
```

**Risposta**

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

---

## Monitora l'aggiornamento di un sito web

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

A che punto è l'aggiornamento di un sito web, così da poter mostrare il progresso come "221 di 249".

**Parametri di query**

| Parametro | Obbligatorio | Descrizione |
|---|---|---|
| `baseUrl` | Sì | Qualsiasi indirizzo sul sito web, o solo l'host. |

**cURL**

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

**Risposta**

```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 non è in esecuzione alcun aggiornamento per quel sito web. Le pagine completate finora sono `total` meno `pending`. Il lavoro `status` è uno tra `refreshing` (elaborazione delle pagine in corso), `deduplicating` (passaggio di pulizia finale), o i finali `completed`, `failed` e `cancelled`. Conserva `domainBatchId`: è ciò che passi all'endpoint di annullamento.

Un `baseUrl` mancante o vuoto restituisce `400`.

---

## Interrompi l'aggiornamento di un sito web

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

Interrompe l'aggiornamento di un sito web che sta ancora elaborando le sue pagine. Le pagine già completate mantengono il loro contenuto aggiornato; le pagine non ancora avviate vengono rimosse e le pagine che erano in fase di rilettura tornano al loro stato precedente.

**Campi della richiesta**

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `jobId` | Sì | L'`domainBatchId` restituito da [Monitora l'aggiornamento di un sito web](#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" }'
```

**Risposta**

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

| Campo | Tipo | Descrizione |
|---|---|---|
| `status` | string | Stato dell'aggiornamento dopo questa chiamata: `cancelled`, `deduplicating`, `completed` o `failed`. |
| `cancelled_units` | integer | Quanta parte del lavoro era ancora in sospeso al momento dell'annullamento. `0` in caso di annullamento ripetuto. |
| `sources_reset` | integer | Pagine rimosse dall'elaborazione e riportate a `ready`. |
| `sources_cancelled` | integer | Pagine nuove di questo aggiornamento che erano ancora in coda e sono ora annullate. |

Annullare due volte è innocuo: la seconda chiamata riporta lo stesso stato finale. Una volta che l'aggiornamento è passato alla fase di pulizia, non può più essere interrotto e la risposta restituisce `success: false` e `reason: "already_finalizing"`. Un `jobId` mancante restituisce `400`, e un lavoro che non è presente nel tuo account restituisce `404`.

---

## Aggiorna una singola fonte

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

Rilegge una pagina web che hai già importato e allinea le sue FAQ al contenuto attuale della pagina: le sezioni modificate vengono aggiornate, quelle nuove aggiunte e quelle rimosse eliminate.

**cURL**

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

**Risposta** — `202 Accepted`

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

Esegui il polling della fonte finché il suo stato non esce da `queued` e `processing`. Un ID fonte non presente nel tuo account restituisce `404`.

---

## Seleziona le pagine più pertinenti

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

Chiede all'IA di scegliere le cinque pagine, da un elenco di candidate, che descrivono meglio un'attività: utilizzato durante la generazione di un playbook di campagna da un sito web. Questa operazione consuma crediti.

**Campi della richiesta**

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `urls` | Sì | Indirizzi delle pagine candidate tra cui scegliere, solitamente provenienti dall'individuazione delle pagine. |
| `homeUrl` | Sì | La home page del sito, utilizzata come contesto per la scelta. |

**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"]
  }'
```

**Risposta**

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

Questo è un helper, non una risorsa: in caso di errore risponde comunque `200`, con `success: false`, un elenco `pages` vuoto e un messaggio `error`.

---

## Gruppi di conoscenza

Un **gruppo di conoscenza** è un insieme denominato di FAQ — "Spedizioni e resi", "Onboarding" — che puoi applicare a un Agente o a una campagna con una sola chiamata. Il gruppo contiene riferimenti, non copie: le FAQ stesse rimangono nella tua libreria unica, quindi modificarne una con la [API delle FAQ](faqs.md) la aggiorna ovunque venga utilizzata.

L'applicazione di un gruppo **aggiunge** sempre e solo ciò che manca, quindi applicare lo stesso gruppo due volte è innocuo e `added_count` restituisce `0` la seconda volta.

---

## Creare un gruppo di conoscenza

`POST /kb-groups`

Crea un gruppo. Inizia vuoto: aggiungi FAQ al suo interno con [Aggiungi una FAQ a un gruppo](#add-a-faq-to-a-group).

**Campi della richiesta**

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `name` | Sì | Nome del gruppo. |

**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"]
```

**Risposta** — `201 Created`

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

---

## Rinominare un gruppo di conoscenza

`PUT /kb-groups/{groupId}`

Cambia il nome di un gruppo. Le sue FAQ rimangono invariate.

**Campi della richiesta**

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `name` | Sì | Nuovo nome per il gruppo. |

**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" }'
```

**Risposta**

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

---

## Eliminare un gruppo di conoscenza

`DELETE /kb-groups/{groupId}`

Elimina il gruppo. Viene rimosso solo il pacchetto: le FAQ al suo interno rimangono nella tua libreria e tutto ciò a cui il gruppo era già stato applicato mantiene tali FAQ.

**cURL**

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

**Risposta**

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

---

## Aggiungi una FAQ a un gruppo

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

Inserisce una FAQ esistente in un gruppo. Questo modifica solo il bundle: non collega la FAQ a nessun Agente di per sé; applica il gruppo per quello.

**Campi della richiesta**

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `faq_id` | Sì | ID della FAQ da aggiungere. |

**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" }'
```

**Risposta**

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

---

## Rimuovi una FAQ da un gruppo

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

Rimuove una FAQ da un gruppo. La FAQ in sé non viene eliminata e gli Agenti a cui il gruppo era già stato applicato la manterranno.

**cURL**

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

**Risposta**

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

---

## Applica un gruppo a un Agente

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

Aggiunge ogni FAQ nel gruppo alla conoscenza di un Agente AI in un'unica chiamata: il modo rapido per fornire a un nuovo Agente un corpo di conoscenze che hai già curato.

**Campi della richiesta**

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `agent_id` | Sì | ID dell'Agente AI a cui applicare il gruppo. |

**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"]
```

**Risposta**

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

`added_count` indica quante FAQ sono state effettivamente aggiunte: `0` quando il gruppo è vuoto o già applicato.

---

## Applica un gruppo a una campagna

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

La versione per campagne classiche della chiamata precedente. Su un account basato su Agenti, usa invece [Applica un gruppo a un Agente](#apply-a-group-to-an-agent).

**Campi della richiesta**

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `campaign_id` | Sì | ID della campagna a cui applicare il gruppo. |

**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" }'
```

**Risposta**

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

---

## Errori dell'API della Knowledge Base

Questi endpoint restituiscono il formato di errore standard:

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

| Stato | Quando si verifica su un endpoint della knowledge base |
|---|---|
| `400` | Un campo obbligatorio manca o non è valido: un `url` vuoto, un `baseUrl` o `jobId` mancante, più di 100 URL in un'importazione massiva, più di 2.000 ID in un'eliminazione massiva o un tipo di file che non possiamo leggere. |
| `402` | Crediti insufficienti per eseguire l'importazione. Ricarica e riprova. |
| `403` | Un `storage_path` al di fuori della tua cartella di caricamento, oppure il tuo piano non include l'accesso API. |
| `404` | La fonte, il gruppo, la FAQ, l'Agente, la campagna o il processo di aggiornamento non sono stati trovati: o non esistono o appartengono a un altro account. |

> **Gli errori lievi (soft failures) non sono errori.** La scoperta (`discover-pages`, `refresh-domain`) e l'helper di selezione delle pagine rispondono `200` con `success: false` e un messaggio `error` quando il sito web non può essere letto, invece di far fallire la richiesta. Controlla sempre `success` prima di leggere i dati.

I codici condivisi che ogni endpoint può restituire — `401`, `403` (il tuo piano non include l'accesso all'API), `429` (limite di frequenza) e `500` — sono elencati con indicazioni sui tentativi in [Errori e Paginazione](errors-and-pagination.md).

---

## Correlati

- [API FAQ](faqs.md) — leggi, modifica e collega le FAQ prodotte dalle tue fonti.
- [Gestione FAQ](../ai-automation/faq-management.md) — la stessa knowledge base nella dashboard.
- [Agenti AI](../ai-agents/ai-agents.md) — gli Agenti a cui colleghi fonti e gruppi.
- [Accesso API](../integrations/api-access.md) — genera la tua chiave API.
- [Autenticazione](authentication.md) — tutti i modi per trasmettere la tua chiave.
