
# API FAQ

FAQ adalah entri tanya jawab yang digunakan bot AI Anda saat membalas pelanggan. Setiap FAQ menjadi milik akun Anda dan dapat ditautkan ke satu atau beberapa kampanye, sehingga jawaban yang sama dapat digunakan kembali di mana pun yang relevan. API FAQ memungkinkan Anda mengelola pustaka tersebut secara terprogram — membuat, memperbarui, mengimpor massal, menyusun ulang, dan menautkan FAQ ke kampanye dari kode Anda sendiri.

Semua endpoint di bawah ini bersifat relatif terhadap URL dasar `https://api.youraiconnector.com/v1`. Setiap permintaan harus diautentikasi — lihat [Akses API](../integrations/api-access.md) dan [Autentikasi](authentication.md). Akses API adalah fitur berbayar; tanpanya, permintaan akan ditolak dengan `403`.

> **Bagaimana bot menggunakan FAQ:** Saat Anda membuat atau mengubah FAQ, platform akan menyiapkan data pencariannya (yang digunakan untuk mencocokkan FAQ dengan pertanyaan masuk) di latar belakang. Proses ini biasanya selesai dalam beberapa detik, setelah itu bot akan mulai menggunakan entri tersebut secara otomatis.


---

## Objek FAQ

Setiap FAQ yang dikembalikan dari API memiliki bentuk berikut:

| Bidang | Tipe | Deskripsi |
|---|---|---|
| `id` | string | Pengidentifikasi unik FAQ. |
| `question` | string | Pertanyaan pelanggan yang dijawab oleh entri ini. |
| `answer` | string | Jawaban yang diberikan oleh bot AI. |
| `category` | string \| null | Label kategori bentuk bebas opsional. |
| `tags` | string[] | Label opsional untuk mengatur FAQ. |
| `is_active` | boolean | Apakah bot diizinkan menggunakan FAQ ini. Default ke `true`. |
| `is_global` | boolean | Menandai FAQ sebagai tidak terikat pada satu kampanye atau Agen tertentu. Ini tidak membuat FAQ berlaku di mana saja: FAQ hanya digunakan oleh kampanye dan Agen yang ditautkan dengannya. Default ke `false`. |
| `usage_count` | integer | Berapa kali FAQ ini telah digunakan dalam balasan AI. |
| `order_index` | integer | Posisi tampilan FAQ ini dalam kampanyenya. |
| `campaign_ids` | string[] | ID kampanye yang ditautkan dengan FAQ ini. |
| `created_at` | string \| null | Stempel waktu ISO 8601 kapan FAQ dibuat. |
| `updated_at` | string \| null | Stempel waktu ISO 8601 dari perubahan terakhir. |

Bidang yang dapat Anda **atur** adalah: `question`, `answer`, `is_active`, `is_global`, `category`, `tags`, dan `order_index`. Platform mengelola semua hal lainnya (data pencarian, jumlah penggunaan, stempel waktu); bidang lain apa pun dalam isi permintaan Anda akan diabaikan.

---

## Daftar FAQ

`GET /faqs`

Mengembalikan FAQ di akun Anda, yang terbaru ditampilkan lebih dulu. Secara opsional, filter berdasarkan satu kampanye atau berdasarkan status aktif.

**Parameter kueri**

| Parameter | Wajib | Deskripsi |
|---|---|---|
| `campaign_id` | Tidak | Hanya mengembalikan FAQ yang ditautkan ke kampanye ini. |
| `is_active` | Tidak | Hanya mengembalikan FAQ dengan status aktif ini (`true` atau `false`). Filter ini diterapkan per halaman, sehingga satu halaman mungkin berisi lebih sedikit item daripada `limit`. |
| `limit` | Tidak | FAQ maksimum per halaman. Default `50`, maksimum `100`. |
| `cursor` | Tidak | ID FAQ untuk melanjutkan setelahnya. Teruskan nilai `next_cursor` dari halaman sebelumnya. |

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

**Respons**

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

Ketika `next_cursor` adalah `null`, tidak ada lagi hasil yang ditemukan.

---

## Mendapatkan FAQ

`GET /faqs/{faqId}`

Mengembalikan satu FAQ berdasarkan ID-nya.

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

**Respons**

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

---

## Membuat FAQ

`POST /faqs`

Membuat FAQ baru dan menautkannya ke sebuah kampanye.

**Bidang permintaan**

| Bidang | Wajib | Deskripsi |
|---|---|---|
| `campaign_id` | Ya | Kampanye untuk menautkan FAQ baru. |
| `question` | Ya | Pertanyaan pelanggan yang dijawab oleh entri ini. |
| `answer` | Ya | Jawaban yang harus diberikan oleh bot. |
| `is_active` | Tidak | Apakah bot boleh menggunakan FAQ ini. Default-nya adalah `true`. |
| `is_global` | Tidak | Apakah FAQ berlaku untuk semua kampanye. Default-nya adalah `false`. |
| `category` | Tidak | Label kategori bentuk bebas. |
| `tags` | Tidak | Larik label. |
| `order_index` | Tidak | Posisi tampilan dalam kampanye. Default-nya adalah `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"]
```

**Respons**

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

---

## Memperbarui FAQ

`PUT /faqs/{faqId}`

Memperbarui FAQ sebagian. Hanya kolom yang dapat ditulis yang disediakan yang akan diubah; kolom lainnya tetap mempertahankan nilai saat ini. Mengubah `question` atau `answer` akan secara otomatis menyegarkan data pencarian FAQ di latar belakang.

Jika Anda mengirim `question` atau `answer`, keduanya harus berupa string yang tidak kosong. Mengirim tanpa kolom yang dapat ditulis yang dikenali akan mengembalikan `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()
```

**Respons**

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

---

## Menghapus FAQ

`DELETE /faqs/{faqId}`

Menghapus FAQ secara permanen. Secara opsional, teruskan `campaign_id` sebagai parameter kueri untuk juga menghapus FAQ dari daftar FAQ kampanye tersebut.

**Parameter kueri**

| Parameter | Wajib | Deskripsi |
|---|---|---|
| `campaign_id` | Tidak | Hapus juga FAQ dari daftar FAQ kampanye ini. |

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

**Respons**

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

---

## Hapus massal FAQ

`POST /faqs/bulk-delete`

Menghapus hingga 500 FAQ dalam satu permintaan. Saat `campaign_id` disertakan, FAQ yang dihapus juga akan dihapus dari daftar FAQ kampanye tersebut.

**Bidang permintaan**

| Bidang | Wajib | Deskripsi |
|---|---|---|
| `faq_ids` | Ya | Larik ID FAQ yang tidak kosong untuk dihapus (maks 500). |
| `campaign_id` | Tidak | Hapus juga FAQ yang dihapus dari daftar FAQ kampanye ini. |

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

**Respons**

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

---

## FAQ Impor

`POST /faqs/import`

Impor massal hingga 500 FAQ dan tautkan semuanya ke satu kampanye. Item yang `question`-nya cocok dengan FAQ yang sudah ada di pustaka Anda (tidak peka huruf besar/kecil) akan **memperbarui** FAQ tersebut alih-alih membuat duplikat.

> **Tips performa:** Pencocokan duplikat memindai seluruh pustaka FAQ Anda, jadi pustaka yang sangat besar akan membuat proses impor lebih lambat. Lebih baik lakukan impor dalam jumlah sedikit namun besar daripada banyak impor kecil.

**Bidang permintaan**

| Bidang | Wajib | Deskripsi |
|---|---|---|
| `campaign_id` | Ya | Kampanye tempat semua FAQ yang diimpor ditautkan. |
| `faqs` | Ya | Larik item FAQ yang tidak kosong (maks 500). Setiap item harus memiliki `question` dan `answer` yang tidak kosong; item tersebut juga dapat menyertakan `is_active`, `is_global`, `category`, `tags`, dan `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()
```

**Respons**

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

`faq_ids` adalah ID FAQ yang dibuat atau diperbarui, sesuai urutan yang Anda berikan.

---

## Mengurutkan Ulang FAQ

`POST /faqs/reorder`

Mengatur urutan tampilan FAQ kampanye. Berikan daftar **lengkap** ID FAQ sesuai urutan yang diinginkan; posisi setiap FAQ akan diperbarui agar sesuai dengan tempatnya di dalam larik.

**Bidang permintaan**

| Bidang | Wajib | Deskripsi |
|---|---|---|
| `campaign_id` | Ya | Kampanye yang FAQ-nya sedang diurutkan ulang. |
| `ordered_faq_ids` | Ya | Array tidak kosong yang berisi semua ID FAQ kampanye dalam urutan tampilan yang diinginkan (maks 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()
```

**Respons**

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

Jika kampanye atau salah satu ID FAQ tidak ditemukan di akun Anda, permintaan akan mengembalikan `404 One or more FAQs were not found`.

---

## Menautkan FAQ ke kampanye

`POST /faqs/{faqId}/link`

Menautkan FAQ yang sudah ada ke kampanye tambahan. Sebuah FAQ dapat dibagikan oleh sejumlah kampanye, sehingga jawaban yang sama hanya perlu dikelola satu kali.

**Bidang permintaan**

| Bidang | Wajib | Deskripsi |
|---|---|---|
| `campaign_id` | Ya | Kampanye untuk menautkan FAQ tersebut. |

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

**Respons**

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

---

## Memutuskan tautan FAQ dari kampanye

`POST /faqs/{faqId}/unlink`

Menghapus FAQ dari kampanye tanpa menghapus FAQ itu sendiri. FAQ tersebut tetap ada di pustaka Anda dan tetap tertaut ke kampanye lainnya.

**Bidang permintaan**

| Bidang | Wajib | Deskripsi |
|---|---|---|
| `campaign_id` | Ya | Kampanye untuk menghapus FAQ dari. |

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

**Respons**

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

---

## Membangun ulang data pencarian FAQ

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

Mengantrekan pembangunan ulang data yang digunakan bot AI untuk menemukan FAQ ini (data pencarian semantik dan kata kuncinya). Ini berguna jika FAQ tidak muncul dalam balasan seperti yang diharapkan. Pembangunan ulang berjalan di latar belakang dan biasanya selesai dalam beberapa detik; FAQ mungkin untuk sementara tidak disertakan dalam balasan AI saat sedang dibangun ulang.

Titik akhir ini mengembalikan `202 Accepted` karena pekerjaan berlanjut setelah respons dikirim. `status` selalu `"processing"` — ambil kembali FAQ nanti jika Anda perlu mengonfirmasi penyelesaiannya.

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

**Respons**

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

---

## Manajemen FAQ dengan bantuan AI

Endpoint di bawah ini melampaui CRUD biasa: endpoint tersebut memanggil alat bantu AI yang sama dengan yang digunakan editor FAQ di dasbor — menemukan duplikat, membuat entri dari dokumen, dan mencocokkan FAQ dengan tugas kesenjangan pengetahuan yang terbuka. Badan permintaan pada set ini menggunakan nama bidang `camelCase` (`campaignId`, `taskId`, `sourceIds`...), yang cocok dengan bentuk permintaan aplikasi itu sendiri, alih-alih `snake_case` yang digunakan di tempat lain di halaman ini — salin contoh di bawah ini daripada menebak nama bidang.

### Cabangkan FAQ menjadi salinan khusus kampanye

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

Membuat FAQ baru yang merupakan salinan dari FAQ yang sudah ada, dicakup ke satu kampanye, dan menautkan ulang kampanye tersebut ke salinan baru alih-alih yang asli. Gunakan ini saat Anda ingin menyesuaikan jawaban untuk satu kampanye tanpa mengubahnya di tempat lain di mana FAQ asli digunakan. FAQ asli tetap di tempatnya — hanya kehilangan tautan kampanye ini.

**Bidang permintaan**

| Bidang | Wajib | Deskripsi |
|---|---|---|
| `campaign_id` | Ya | Kampanye untuk mencakup salinan baru, dan untuk menautkan ulang dari FAQ asli. |
| `question` | Ya | Pertanyaan untuk salinan baru yang khusus kampanye. |
| `answer` | Ya | Jawaban untuk salinan baru yang khusus kampanye. |

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

**Respons** — `201 Created`

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

### Temukan FAQ yang hampir duplikat

`POST /faqs/dedupe`

Memulai pekerjaan latar belakang yang memindai pustaka FAQ Anda untuk mencari entri yang hampir duplikat dan tumpang tindih, lalu menggabungkan atau menghapusnya jika sistem yakin. Berguna setelah impor massal, atau setelah beberapa putaran FAQ yang dibuat AI meninggalkan pustaka dengan tumpang tindih. Hanya satu pekerjaan deduplikasi yang dapat berjalan per akun dalam satu waktu — memulai pekerjaan kedua saat pekerjaan lain masih berjalan akan mengembalikan `409`.

**Bidang permintaan**

| Bidang | Wajib | Deskripsi |
|---|---|---|
| `sourceIds` | Tidak | Larik ID sumber basis pengetahuan untuk mencakup deduplikasi. Abaikan untuk memindai seluruh pustaka FAQ Anda. |

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

**Respons** — `202 Accepted`

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

Pekerjaan berjalan di latar belakang dan biasanya memakan waktu beberapa menit pada pustaka yang besar. Tidak ada endpoint status terpisah — ambil ulang [`GET /faqs`](#list-faqs) setelah menunggu sebentar untuk melihat apa yang berubah. Setelah Anda selesai meninjau hasilnya, panggil endpoint dismiss di bawah ini untuk menghapusnya.

### Hapus hasil pemeriksaan duplikat

`POST /faqs/dedupe/dismiss`

Menghapus pekerjaan deduplikasi yang sudah selesai agar tidak lagi muncul sebagai hasil aktif. Idempoten — aman untuk dipanggil meskipun tidak ada yang perlu dihapus. Mengembalikan `409` jika pekerjaan masih `queued` atau `processing` (Anda tidak dapat menghapus proses yang belum selesai).

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

**Respons**

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

### Menghasilkan FAQ dari dokumen yang diunggah

`POST /faqs/generate-from-documents`

Membaca satu atau lebih dokumen yang sudah ada di penyimpanan file akun Anda dan meminta AI untuk menyusun draf FAQ dari kontennya, memeriksa draf tersebut terhadap pustaka Anda yang sudah ada agar dapat menggunakan kembali atau memperbarui entri alih-alih membuat duplikat. Hasilnya **tidak** langsung ditulis — hasil tersebut disimpan sebagai kumpulan perubahan tertunda pada kampanye untuk Anda tinjau, lalu diterapkan (atau dibuang) dengan [Terapkan perubahan FAQ yang ditinjau](#apply-reviewed-faq-changes) di bawah. Ini memerlukan kredit, karena ini adalah proses pembuatan AI atas teks dokumen.

Endpoint ini tidak membawa file: `storagePath` harus mengarah ke file yang sudah ada di folder unggahan Anda sendiri (`users/{your user id}/uploads/`), konvensi yang sama seperti [Impor dokumen yang diunggah](knowledge-base.md#import-an-uploaded-document) pada API Basis Pengetahuan.

**Bidang permintaan**

| Bidang | Wajib | Deskripsi |
|---|---|---|
| `campaignId` | Ya | Kampanye yang diusulkan untuk FAQ yang dihasilkan. |
| `uploadedFiles` | Ya | Array file yang tidak kosong untuk dibaca, masing-masing `{ storagePath, fileName, mimeType }`. `storagePath` harus dimulai dengan `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()
```

**Respons** — `202 Accepted`

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

`faqCount` adalah jumlah total perubahan yang diusulkan yang menunggu peninjauan; `reusedCount`, `modifiedCount`, dan `newCount` memecahnya menjadi FAQ yang cocok dengan entri yang ada tanpa perubahan, yang diusulkan untuk diedit oleh AI, dan yang benar-benar baru. File yang diunggah dihapus dari penyimpanan setelah pemrosesan selesai, terlepas dari apakah proses tersebut berhasil atau tidak.

### Terapkan perubahan FAQ yang ditinjau

`POST /faqs/apply-optimization`

Menerapkan (atau membuang) kumpulan perubahan FAQ yang diusulkan AI yang tertunda — jenis yang dihasilkan oleh [Hasilkan FAQ dari dokumen](#generate-faqs-from-uploaded-documents) di atas, atau oleh tinjauan pengoptimalan FAQ dasbor. Anda memilih dengan tepat perubahan yang diusulkan mana yang akan diterima; apa pun yang tidak Anda sebutkan akan dibiarkan tidak tersentuh (perubahan yang dihilangkan tidak pernah dianggap sebagai penolakan yang menghapus sesuatu).

**Bidang permintaan**

| Bidang | Wajib | Deskripsi |
|---|---|---|
| `campaignId` | Salah satu dari dua ini | Kampanye yang perubahan FAQ tertundanya sedang diterapkan. |
| `agentId` | Salah satu dari dua ini | Agen AI yang perubahan FAQ tertundanya sedang diterapkan, pada akun asli agen. Berikan tepat satu dari `campaignId` / `agentId`, jangan pernah keduanya. |
| `acceptedChanges` | Ya | Array perubahan yang Anda terima, masing-masing `{ action, faq_id?, faq_ref_path?, question?, answer?, edit_scope? }`. `action` adalah salah satu dari `keep`, `remove`, `add_from_library`, `create_new`, `modify`. Kirim array kosong untuk membuang kumpulan tertunda tanpa menerapkan apa pun. |

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

**Respons**

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

`faq_count` adalah jumlah total FAQ yang ditautkan kampanye (atau Agen) setelah diterapkan. Jika tidak ada kumpulan perubahan tertunda untuk diterapkan, responsnya adalah `{ "success": true, "message": "No pending FAQ changes to apply" }`.

### Temukan FAQ yang mirip dengan tugas

`POST /faqs/similar-for-task`

Memeringkat pustaka FAQ Anda berdasarkan relevansi dengan pertanyaan tugas kesenjangan pengetahuan — pencarian yang sama di balik pemilih "Gunakan FAQ yang ada" di dasbor. Hanya baca. `taskId` harus mengarah ke tugas bertipe `faq_update`.

Endpoint ini selalu menjawab `200`, bahkan pada kegagalan yang diharapkan seperti tugas yang tidak dikenal — periksa `success` di dalam body alih-alih status HTTP.

**Bidang permintaan**

| Bidang | Wajib | Deskripsi |
|---|---|---|
| `taskId` | Ya | Tugas `faq_update` untuk menemukan kecocokan. |
| `limit` | Tidak | Jumlah kecocokan maksimum yang akan dikembalikan. Defaultnya adalah 20, dibatasi hingga 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()
```

**Respons**

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

Kecocokan diurutkan berdasarkan `similarity` (kecocokan semantik jika tersedia, jika tidak maka tumpang tindih kata kunci), yang terbaik di urutan pertama. Pada kegagalan ringan, bentuknya adalah `{ "success": false, "error": "...", "error_code": 404 }` — `error_code` mencerminkan status HTTP yang seharusnya. 

### Menyelesaikan tugas dengan FAQ yang sudah ada

`POST /faqs/resolve-task`

Menyelesaikan tugas kesenjangan pengetahuan dengan menautkannya ke FAQ yang sudah Anda miliki (alih-alih menulis yang baru), mengirimkan jawaban FAQ tersebut ke kontak yang memicu kesenjangan, dan menandai tugas sebagai selesai. Gunakan ini setelah [Temukan FAQ yang mirip dengan tugas](#find-faqs-similar-to-a-task) menampilkan FAQ yang sudah ada yang mencakup pertanyaan tersebut.

Seperti endpoint di atas, ini selalu menjawab `200` — periksa `success` di dalam body.

**Bidang permintaan**

| Bidang | Wajib | Deskripsi |
|---|---|---|
| `taskId` | Ya | Tugas `faq_update` yang akan diselesaikan. |
| `faqId` | Ya | FAQ yang sudah ada untuk ditautkan dan dikirim sebagai jawaban. |

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

**Respons**

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

`follow_up_status` memberi tahu Anda apa yang terjadi pada tindak lanjut kontak: `published` (dikirim segera), `queued` (AI sudah di tengah-tengah membalas kontak tersebut, jadi akan dikirim berikutnya), `skipped_no_contact` (tugas tidak memiliki kontak yang ditautkan), atau `skipped_no_campaign` (tidak ada kampanye untuk mengirimnya).

---

## FAQ kesalahan API

Endpoint FAQ mengembalikan amplop kesalahan standar:

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

| Status | Kapan ini terjadi pada endpoint FAQ |
|---|---|
| `400` | Bidang wajib hilang atau tidak valid (misalnya `question` kosong, `campaign_id` hilang, atau lebih dari 500 item dalam permintaan massal). |
| `404` | FAQ atau kampanye tidak ditemukan — entah tidak ada atau milik akun lain. |
| `409` | `POST /faqs/dedupe` dipanggil saat pekerjaan dedupe sudah `queued`/`processing`, atau `POST /faqs/dedupe/dismiss` dipanggil saat pekerjaan belum selesai. |

Kode bersama yang dapat dikembalikan oleh setiap endpoint — `401`, `403` (paket Anda tidak menyertakan akses API), `429` (batas kecepatan) dan `500` — tercantum beserta panduan percobaan ulang di [Kesalahan & Penomoran Halaman](errors-and-pagination.md).

`POST /faqs/similar-for-task` dan `POST /faqs/resolve-task` adalah dua pengecualian di halaman ini: keduanya menjawab `200` bahkan untuk kegagalan yang diharapkan (tugas tidak dikenal, jenis tugas salah) dan menempatkan status sebenarnya di `error_code` dalam body sebagai gantinya — lihat masing-masing endpoint di atas.

---

## Terkait

- [API Kampanye](campaigns.md) — kampanye tempat FAQ Anda ditautkan.
- [API Basis Pengetahuan](knowledge-base.md) — impor situs web dan dokumen ke dalam FAQ secara otomatis, dan gabungkan FAQ ke dalam grup pengetahuan yang dapat digunakan kembali.
- [Akses API](../integrations/api-access.md) — buat kunci API Anda.
- [Autentikasi](authentication.md) — semua cara untuk memberikan kunci Anda.
