
# FAQs-API

FAQs är de frågor och svar som din AI-bot använder när den svarar kunder. Varje FAQ tillhör ditt konto och kan kopplas till en eller flera kampanjer, så att samma svar kan återanvändas överallt där det är relevant. Med FAQs-API:et kan du hantera detta bibliotek programmatiskt — skapa, uppdatera, massimportera, ändra ordning och koppla FAQs till kampanjer från din egen kod.

Alla slutpunkter nedan är relativa till bas-URL:en `https://api.youraiconnector.com/v1`. Varje anrop måste autentiseras — se [API-åtkomst](../integrations/api-access.md) och [Autentisering](authentication.md). API-åtkomst är en betalfunktion; utan den avvisas anrop med ett `403`.

> **Hur boten använder en FAQ:** När du skapar eller ändrar en FAQ förbereder plattformen dess sökdata (som används för att matcha FAQ:n med inkommande frågor) i bakgrunden. Detta tar vanligtvis några sekunder, varefter boten automatiskt börjar använda posten.


---

## FAQ-objektet

Varje FAQ som returneras från API:et har följande struktur:

| Fält | Typ | Beskrivning |
|---|---|---|
| `id` | string | FAQ-postens unika identifierare. |
| `question` | string | Kundfrågan som denna post besvarar. |
| `answer` | string | Svaret som AI-boten ger. |
| `category` | string \| null | Valfri fritextetikett för kategori. |
| `tags` | string[] | Valfria etiketter för att organisera FAQ-poster. |
| `is_active` | boolean | Om boten får använda denna FAQ. Standardvärde är `true`. |
| `is_global` | boolean | Markerar att FAQ-posten inte är bunden till en specifik kampanj eller agent. Det innebär inte att FAQ-posten gäller överallt: en FAQ används endast av de kampanjer och agenter den är länkad till. Standardvärde är `false`. |
| `usage_count` | integer | Hur många gånger denna FAQ har använts i AI-svar. |
| `order_index` | integer | Visningsposition för denna FAQ inom dess kampanj. |
| `campaign_ids` | string[] | ID:n för de kampanjer som denna FAQ är länkad till. |
| `created_at` | string \| null | ISO 8601-tidsstämpel för när FAQ-posten skapades. |
| `updated_at` | string \| null | ISO 8601-tidsstämpel för den senaste ändringen. |

Fälten du kan **ange** är: `question`, `answer`, `is_active`, `is_global`, `category`, `tags` och `order_index`. Plattformen hanterar allt annat (sökdata, användningsstatistik, tidsstämplar); alla andra fält i din anropskropp ignoreras.

---

## Lista FAQs

`GET /faqs`

Returnerar FAQs på ditt konto, med de nyaste först. Filtrera valfritt efter en enskild kampanj eller aktivt tillstånd.

**Frågeparametrar**

| Parameter | Krävs | Beskrivning |
|---|---|---|
| `campaign_id` | Nej | Returnera endast FAQs kopplade till denna kampanj. |
| `is_active` | Nej | Returnera endast FAQs med detta aktiva tillstånd (`true` eller `false`). Detta filter tillämpas per sida, så en sida kan innehålla färre objekt än `limit`. |
| `limit` | Nej | Maximalt antal FAQs per sida. Standard `50`, max `100`. |
| `cursor` | Nej | Ett FAQ-ID att fortsätta efter. Skicka med `next_cursor`-värdet från föregående sida. |

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

**Svar**

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

När `next_cursor` är `null` finns det inga fler resultat.

---

## Hämta en FAQ

`GET /faqs/{faqId}`

Returnerar en enskild FAQ baserat på dess 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"]
```

**Svar**

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

---

## Skapa en FAQ

`POST /faqs`

Skapar en ny FAQ och kopplar den till en kampanj.

**Begäransfält**

| Fält | Krävs | Beskrivning |
|---|---|---|
| `campaign_id` | Ja | Kampanjen som den nya FAQ:n ska kopplas till. |
| `question` | Ja | Kundfrågan som detta inlägg besvarar. |
| `answer` | Ja | Svaret som boten ska ge. |
| `is_active` | Nej | Huruvida boten får använda denna FAQ. Standardvärde är `true`. |
| `is_global` | Nej | Huruvida FAQ:n gäller för alla kampanjer. Standardvärde är `false`. |
| `category` | Nej | En fritextkategori-etikett. |
| `tags` | Nej | En lista med etiketter. |
| `order_index` | Nej | Visningsposition inom kampanjen. Standardvärde är `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"]
```

**Svar**

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

---

## Uppdatera en FAQ

`PUT /faqs/{faqId}`

Uppdaterar en FAQ delvis. Endast de angivna skrivbara fälten ändras; allt annat behåller sitt nuvarande värde. Ändring av `question` eller `answer` uppdaterar automatiskt FAQ:ns sökdata i bakgrunden.

Om du skickar `question` eller `answer` måste de vara icke-tomma strängar. Om inga kända skrivbara fält skickas returneras ett `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()
```

**Svar**

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

---

## Ta bort en FAQ

`DELETE /faqs/{faqId}`

Tar permanent bort en FAQ. Skicka valfritt med `campaign_id` som en frågeparameter för att även ta bort FAQ:n från den kampanjens FAQ-lista.

**Frågeparametrar**

| Parameter | Krävs | Beskrivning |
|---|---|---|
| `campaign_id` | Nej | Ta även bort FAQ:n från den här kampanjens FAQ-lista. |

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

**Svar**

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

---

## Massradera FAQ:er

`POST /faqs/bulk-delete`

Raderar upp till 500 FAQ:er i en enda begäran. När `campaign_id` anges tas de raderade FAQ:erna även bort från den kampanjens FAQ-lista.

**Begäransfält**

| Fält | Krävs | Beskrivning |
|---|---|---|
| `faq_ids` | Ja | En icke-tom array med FAQ-ID:n som ska raderas (max 500). |
| `campaign_id` | Nej | Ta även bort de raderade FAQ:erna från den här kampanjens FAQ-lista. |

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

**Svar**

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

---

## Importera vanliga frågor (FAQ)

`POST /faqs/import`

Massimportera upp till 500 vanliga frågor och länka dem alla till en kampanj. Objekt vars `question` matchar en befintlig FAQ i ditt bibliotek (skiftlägesokänsligt) **uppdaterar** den FAQ:n istället för att skapa en dubblett.

> **Prestandatips:** Matchning av dubbletter genomsöker hela ditt FAQ-bibliotek, så mycket stora bibliotek gör importen långsammare. Föredra färre, större importer framför många små.

**Begäransfält**

| Fält | Krävs | Beskrivning |
|---|---|---|
| `campaign_id` | Ja | Kampanjen som alla importerade vanliga frågor länkas till. |
| `faqs` | Ja | En icke-tom array med FAQ-objekt (max 500). Varje objekt måste ha en icke-tom `question` och `answer`; det kan även inkludera `is_active`, `is_global`, `category`, `tags` och `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()
```

**Svar**

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

`faq_ids` är de skapade eller uppdaterade FAQ-ID:na, i den ordning du angav dem.

---

## Ändra ordning på vanliga frågor

`POST /faqs/reorder`

Ställer in visningsordningen för en kampanjs vanliga frågor. Ange den **fullständiga** listan med FAQ-ID:n i önskad ordning; varje FAQ:s position uppdateras för att matcha dess plats i arrayen.

**Begäransfält**

| Fält | Krävs | Beskrivning |
|---|---|---|
| `campaign_id` | Ja | Kampanjen vars FAQ:er ska sorteras om. |
| `ordered_faq_ids` | Ja | En icke-tom array med alla kampanjens FAQ-ID:n i önskad visningsordning (max 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()
```

**Svar**

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

Om kampanjen eller något av FAQ-ID:na inte hittas i ditt konto, returnerar begäran `404 One or more FAQs were not found`.

---

## Länka en FAQ till en kampanj

`POST /faqs/{faqId}/link`

Länkar en befintlig FAQ till en ytterligare kampanj. En FAQ kan delas av valfritt antal kampanjer, så samma svar behöver bara underhållas en gång.

**Begäransfält**

| Fält | Krävs | Beskrivning |
|---|---|---|
| `campaign_id` | Ja | Kampanjen som FAQ:n ska länkas till. |

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

**Svar**

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

---

## Koppla bort en FAQ från en kampanj

`POST /faqs/{faqId}/unlink`

Tar bort en FAQ från en kampanj utan att radera själva FAQ:n. FAQ:n finns kvar i ditt bibliotek och förblir kopplad till alla andra kampanjer.

**Begäransfält**

| Fält | Krävs | Beskrivning |
|---|---|---|
| `campaign_id` | Ja | Kampanjen som FAQ:n ska tas bort från. |

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

**Svar**

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

---

## Återskapa sökdata för en FAQ

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

Köar en återskapning av den data som AI-boten använder för att hitta denna FAQ (dess semantiska sökdata och sökordsdata). Detta är användbart om en FAQ inte visas i svar som förväntat. Återskapningen körs i bakgrunden och slutförs vanligtvis inom några sekunder; FAQ:n kan tillfälligt exkluderas från AI-svar medan den återskapas.

Denna slutpunkt returnerar `202 Accepted` eftersom arbetet fortsätter efter att svaret har skickats. `status` är alltid `"processing"` — hämta FAQ:n igen senare om du behöver bekräfta att den är klar.

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

**Svar**

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

---

## AI-assisterad FAQ-hantering

Slutpunkterna nedan går utöver vanlig CRUD: de anropar samma AI-assisterade verktyg som instrumentpanelens FAQ-redigerare använder — för att hitta dubbletter, generera poster från ett dokument och matcha FAQ-poster mot öppna kunskapsluckor. Begäranskroppar i denna uppsättning använder `camelCase`-fältnamn (`campaignId`, `taskId`, `sourceIds`...), vilket matchar appens egna begäransformat, snarare än `snake_case` som används på andra ställen på denna sida — kopiera exemplen nedan istället för att gissa ett fältnamn.

### Förgrena en FAQ till en kampanjspecifik kopia

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

Skapar en ny FAQ som är en kopia av en befintlig, begränsad till en enskild kampanj, och länkar om den kampanjen till den nya kopian istället för originalet. Använd detta när du vill anpassa ett svar för en kampanj utan att ändra det överallt där den ursprungliga FAQ-posten används. Den ursprungliga FAQ-posten lämnas kvar — den förlorar bara länken till denna kampanj.

**Begäransfält**

| Fält | Krävs | Beskrivning |
|---|---|---|
| `campaign_id` | Ja | Kampanjen som den nya kopian ska begränsas till, och som ska länkas om från den ursprungliga FAQ-posten. |
| `question` | Ja | Frågan för den nya, kampanjspecifika kopian. |
| `answer` | Ja | Svaret för den nya, kampanjspecifika kopian. |

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

**Svar** — `201 Created`

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

### Hitta nästan identiska FAQ-poster

`POST /faqs/dedupe`

Startar ett bakgrundsjobb som skannar ditt FAQ-bibliotek efter nästan identiska och överlappande poster och slår samman eller tar bort dem där systemet är säkert på sin sak. Användbart efter en massimport, eller efter flera omgångar av AI-genererade FAQ-poster som lämnat biblioteket med överlappningar. Endast ett dedupliceringsjobb kan köras per konto åt gången — att starta ett andra jobb medan ett redan körs returnerar `409`.

**Begäransfält**

| Fält | Krävs | Beskrivning |
|---|---|---|
| `sourceIds` | Nej | Array med käll-ID:n för kunskapsbasen för att begränsa dedupliceringen. Utelämna för att skanna hela ditt FAQ-bibliotek. |

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

**Svar** — `202 Accepted`

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

Jobbet körs i bakgrunden och tar vanligtvis några minuter för ett stort bibliotek. Det finns ingen separat status-slutpunkt — hämta [`GET /faqs`](#list-faqs) igen efter en kort väntan för att se vad som ändrats. När du är klar med att granska resultatet, anropa slutpunkten för att avfärda nedan för att rensa det.

### Avfärda ett resultat från dubblettkontroll

`POST /faqs/dedupe/dismiss`

Rensar det slutförda dedupliceringsjobbet så att det slutar visas som ett aktivt resultat. Idempotent — säkert att anropa även om det inte finns något att avfärda. Returnerar `409` om jobbet fortfarande är `queued` eller `processing` (du kan inte avfärda en körning som inte har slutförts).

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

**Svar**

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

### Generera vanliga frågor från uppladdade dokument

`POST /faqs/generate-from-documents`

Läser ett eller flera dokument som redan finns i ditt kontos fillagring och låter AI:n utkastförfatta vanliga frågor från deras innehåll. Utkasten kontrolleras mot ditt befintliga bibliotek så att poster återanvänds eller uppdateras istället för att skapa dubbletter. Resultaten skrivs **inte** omedelbart — de lagras som en väntande ändringsuppsättning i kampanjen för att du ska kunna granska dem, och tillämpas (eller förkastas) sedan med [Tillämpa granskade FAQ-ändringar](#apply-reviewed-faq-changes) nedan. Detta kostar krediter, eftersom det är en AI-genereringskörning över dokumenttexten.

Denna slutpunkt hanterar inte filen: `storagePath` måste peka på en fil som redan finns under din egen uppladdningsmapp (`users/{your user id}/uploads/`), samma konvention som [Importera ett uppladdat dokument](knowledge-base.md#import-an-uploaded-document) i Knowledge Base-API:et.

**Begäransfält**

| Fält | Krävs | Beskrivning |
|---|---|---|
| `campaignId` | Ja | Kampanjen som de genererade vanliga frågorna föreslås för. |
| `uploadedFiles` | Ja | Icke-tom array med filer att läsa, varje `{ storagePath, fileName, mimeType }`. `storagePath` måste börja med `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()
```

**Svar** — `202 Accepted`

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

`faqCount` är det totala antalet föreslagna ändringar som väntar på granskning; `reusedCount`, `modifiedCount` och `newCount` bryter ner detta i vanliga frågor som matchade en befintlig post oförändrad, de som AI:n föreslår redigering av, och helt nya. Uppladdade filer raderas från lagringen när bearbetningen är klar, oavsett om den lyckas eller inte.

### Tillämpa granskade FAQ-ändringar

`POST /faqs/apply-optimization`

Tillämpar (eller förkastar) en väntande uppsättning AI-föreslagna FAQ-ändringar — den typ som produceras av [Generera vanliga frågor från dokument](#generate-faqs-from-uploaded-documents) ovan, eller av instrumentpanelens granskning av FAQ-optimering. Du väljer exakt vilka föreslagna ändringar som ska accepteras; allt du inte nämner lämnas orört (en utelämnad ändring behandlas aldrig som ett avslag som raderar något).

**Begäransfält**

| Fält | Krävs | Beskrivning |
|---|---|---|
| `campaignId` | En av dessa två | Kampanjen vars väntande FAQ-ändringar tillämpas. |
| `agentId` | En av dessa två | AI-agenten vars väntande FAQ-ändringar tillämpas, på ett agent-native konto. Ange exakt en av `campaignId` / `agentId`, aldrig båda. |
| `acceptedChanges` | Ja | Array med de ändringar du accepterar, varje `{ action, faq_id?, faq_ref_path?, question?, answer?, edit_scope? }`. `action` är en av `keep`, `remove`, `add_from_library`, `create_new`, `modify`. Skicka en tom array för att förkasta den väntande uppsättningen utan att tillämpa något. |

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

**Svar**

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

`faq_count` är kampanjens (eller agentens) totala antal länkade vanliga frågor efter tillämpning. Om det inte fanns någon väntande ändringsuppsättning att tillämpa är svaret `{ "success": true, "message": "No pending FAQ changes to apply" }`.

### Hitta vanliga frågor som liknar en uppgift

`POST /faqs/similar-for-task`

Rangordnar ditt FAQ-bibliotek efter relevans för en kunskapslucka-uppgifts fråga — samma sökning som ligger bakom instrumentpanelens "Använd en befintlig FAQ"-väljare. Skrivskyddad. `taskId` måste peka på en uppgift av typen `faq_update`.

Denna slutpunkt svarar alltid `200`, även vid ett förväntat fel som en okänd uppgift — kontrollera `success` i brödtexten istället för HTTP-statusen.

**Begäransfält**

| Fält | Krävs | Beskrivning |
|---|---|---|
| `taskId` | Ja | `faq_update`-uppgiften att hitta matchningar för. |
| `limit` | Nej | Maximalt antal matchningar att returnera. Standard är 20, max 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()
```

**Svar**

```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
      }
    ]
  }
}
```

Matchningar sorteras efter `similarity` (semantisk matchning när tillgänglig, annars nyckelordsöverlappning), bäst först. Vid ett mjukt fel är formen `{ "success": false, "error": "...", "error_code": 404 }` — `error_code` speglar vad HTTP-statusen normalt skulle vara.

### Lös en uppgift med en befintlig FAQ

`POST /faqs/resolve-task`

Löser en kunskapslucka-uppgift genom att länka den till en FAQ du redan har (istället för att skriva en ny), skickar den FAQ:ns svar till kontakten som utlöste luckan och markerar uppgiften som slutförd. Använd detta efter att [Hitta FAQ:er som liknar en uppgift](#find-faqs-similar-to-a-task) har hittat en befintlig FAQ som redan täcker frågan.

Liksom slutpunkten ovan svarar denna alltid `200` — kontrollera `success` i brödtexten.

**Begäransfält**

| Fält | Krävs | Beskrivning |
|---|---|---|
| `taskId` | Ja | `faq_update`-uppgiften att lösa. |
| `faqId` | Ja | Den befintliga FAQ:n att länka och skicka som svar. |

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

**Svar**

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

`follow_up_status` berättar vad som hände med kontaktuppföljningen: `published` (skickades direkt), `queued` (AI:n var redan mitt uppe i ett svar till den kontakten, så det skickas härnäst), `skipped_no_contact` (uppgiften har ingen länkad kontakt), eller `skipped_no_campaign` (ingen kampanj att skicka det genom).

---

## Vanliga frågor om API-fel

Slutpunkter för vanliga frågor (FAQ) returnerar standardfelmeddelandet:

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

| Status | När det händer på en FAQ-slutpunkt |
|---|---|
| `400` | Ett obligatoriskt fält saknas eller är ogiltigt (till exempel ett tomt `question`, ett saknat `campaign_id` eller fler än 500 objekt i en massbegäran). |
| `404` | FAQ:n eller kampanjen hittades inte — antingen existerar den inte eller så tillhör den ett annat konto. |
| `409` | `POST /faqs/dedupe` anropades medan ett dedupliceringsjobb redan är `queued`/`processing`, eller så anropades `POST /faqs/dedupe/dismiss` medan jobbet inte har slutförts än. |

De delade koderna som alla slutpunkter kan returnera — `401`, `403` (din plan inkluderar inte API-åtkomst), `429` (hastighetsbegränsning) och `500` — listas med vägledning för återförsök i [Fel & Paginering](errors-and-pagination.md).

`POST /faqs/similar-for-task` och `POST /faqs/resolve-task` är de två undantagen på denna sida: de svarar `200` även för ett förväntat fel (okänd uppgift, fel uppgiftstyp) och placerar den verkliga statusen i brödtextens `error_code` istället — se respektive slutpunkt ovan.

---

## Relaterat

- [Kampanj-API](campaigns.md) — kampanjerna som dina FAQ:er är länkade till.
- [Kunskapsbas-API](knowledge-base.md) — importera webbplatser och dokument till FAQ:er automatiskt och bunta ihop FAQ:er till återanvändbara kunskapsgrupper.
- [API-åtkomst](../integrations/api-access.md) — generera din API-nyckel.
- [Autentisering](authentication.md) — alla sätt att skicka med din nyckel.
