
# FAQs API

FAQは、AIボットが顧客に返信する際に参照する質問と回答の項目です。各FAQはアカウントに紐付いており、1つ以上のキャンペーンにリンクできるため、関連するあらゆる場所で同じ回答を再利用できます。FAQs APIを使用すると、独自のコードからFAQの作成、更新、一括インポート、並べ替え、キャンペーンへのリンクといったライブラリ管理をプログラムで行うことができます。

以下のすべてのエンドポイントは、ベースURL `https://api.youraiconnector.com/v1` に対する相対パスです。すべてのリクエストには認証が必要です。[APIアクセス](../integrations/api-access.md)および[認証](authentication.md)を参照してください。APIアクセスは有料機能です。有効でない場合、リクエストは `403` で拒否されます。

> **ボットによるFAQの使用方法:** FAQを作成または変更すると、プラットフォームはバックグラウンドで検索データ（FAQと受信した質問を照合するために使用）を準備します。通常、これは数秒以内に完了し、その後ボットは自動的にその項目を使用し始めます。


---

## FAQオブジェクト

APIから返されるすべてのFAQは、以下の形式になります。

| フィールド | 型 | 説明 |
|---|---|---|
| `id` | string | FAQの一意の識別子。 |
| `question` | string | このエントリが回答する顧客の質問。 |
| `answer` | string | AIボットが提供する回答。 |
| `category` | string \| null | 任意の自由形式のカテゴリラベル。 |
| `tags` | string[] | FAQを整理するための任意のラベル。 |
| `is_active` | boolean | ボットがこのFAQを使用できるかどうか。デフォルトは `true`。 |
| `is_global` | boolean | 特定のキャンペーンやエージェントに紐付いていないFAQであることを示します。これが設定されていてもFAQがどこでも適用されるわけではありません。FAQは、リンクされているキャンペーンやエージェントによってのみ使用されます。デフォルトは `false`。 |
| `usage_count` | integer | このFAQがAIの回答で使用された回数。 |
| `order_index` | integer | キャンペーン内でのこのFAQの表示位置。 |
| `campaign_ids` | string[] | このFAQがリンクされているキャンペーンのID。 |
| `created_at` | string \| null | FAQが作成された日時のISO 8601タイムスタンプ。 |
| `updated_at` | string \| null | 最後に変更された日時のISO 8601タイムスタンプ。 |

**設定**可能なフィールドは、`question`、`answer`、`is_active`、`is_global`、`category`、`tags`、および `order_index` です。その他の項目（検索データ、使用回数、タイムスタンプ）はプラットフォームが管理します。リクエストボディに含まれるその他のフィールドは無視されます。

---

## FAQの一覧取得

`GET /faqs`

アカウント内のFAQを新しい順に返します。オプションで、特定のキャンペーンやアクティブ状態によるフィルタリングが可能です。

**クエリパラメータ**

| パラメータ | 必須 | 説明 |
|---|---|---|
| `campaign_id` | いいえ | このキャンペーンにリンクされたFAQのみを返します。 |
| `is_active` | いいえ | このアクティブ状態（`true` または `false`）のFAQのみを返します。このフィルタはページごとに適用されるため、ページに含まれる項目数が `limit` より少なくなる場合があります。 |
| `limit` | いいえ | 1ページあたりの最大FAQ数。デフォルトは `50`、最大は `100` です。 |
| `cursor` | いいえ | 続きを取得するためのFAQ ID。前のページの `next_cursor` 値を渡してください。 |

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

**レスポンス**

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

`next_cursor` が `null` の場合、これ以上結果はありません。

---

## FAQを取得する

`GET /faqs/{faqId}`

IDを指定して単一のFAQを返します。

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

**レスポンス**

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

---

## FAQを作成する

`POST /faqs`

新しいFAQを作成し、キャンペーンにリンクします。

**リクエストフィールド**

| フィールド | 必須 | 説明 |
|---|---|---|
| `campaign_id` | はい | 新しいFAQをリンクするキャンペーン。 |
| `question` | はい | このエントリが回答する顧客の質問。 |
| `answer` | はい | ボットが回答すべき内容。 |
| `is_active` | いいえ | ボットがこのFAQを使用できるかどうか。デフォルトは `true` です。 |
| `is_global` | いいえ | FAQがすべてのキャンペーンに適用されるかどうか。デフォルトは `false` です。 |
| `category` | いいえ | 自由形式のカテゴリラベル。 |
| `tags` | いいえ | ラベルの配列。 |
| `order_index` | いいえ | キャンペーン内での表示位置。デフォルトは `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"]
```

**レスポンス**

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

---

## FAQの更新

`PUT /faqs/{faqId}`

FAQを部分的に更新します。指定された書き込み可能なフィールドのみが変更され、それ以外の値は現在のまま保持されます。`question` または `answer` を変更すると、バックグラウンドでFAQの検索データが自動的に更新されます。

`question` または `answer` を送信する場合、それらは空ではない文字列である必要があります。書き込み可能なフィールドが何も送信されなかった場合、`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()
```

**レスポンス**

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

---

## FAQの削除

`DELETE /faqs/{faqId}`

FAQを完全に削除します。オプションで `campaign_id` をクエリパラメータとして渡すことで、そのキャンペーンのFAQリストからもFAQを削除できます。

**クエリパラメータ**

| パラメータ | 必須 | 説明 |
|---|---|---|
| `campaign_id` | いいえ | このキャンペーンのFAQリストからもFAQを削除します。 |

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

**レスポンス**

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

---

## FAQの一括削除

`POST /faqs/bulk-delete`

1回のリクエストで最大500件のFAQを削除します。`campaign_id`が指定された場合、削除されたFAQはそのキャンペーンのFAQリストからも削除されます。

**リクエストフィールド**

| フィールド | 必須 | 説明 |
|---|---|---|
| `faq_ids` | はい | 削除するFAQ IDの空ではない配列（最大500件）。 |
| `campaign_id` | いいえ | 削除されたFAQをこのキャンペーンのFAQリストからも削除します。 |

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

**レスポンス**

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

---

## FAQのインポート

`POST /faqs/import`

最大500件のFAQを一括インポートし、すべて1つのキャンペーンに紐付けます。ライブラリ内の既存のFAQと `question` が一致する（大文字と小文字を区別しない）項目は、重複を作成するのではなく、そのFAQを**更新**します。

> **パフォーマンスに関するヒント:** 重複チェックはFAQライブラリ全体をスキャンするため、ライブラリが非常に大きいとインポートが遅くなります。小規模なインポートを繰り返すよりも、大規模なインポートをまとめて行うことを推奨します。

**リクエストフィールド**

| フィールド | 必須 | 説明 |
|---|---|---|
| `campaign_id` | はい | インポートされたすべてのFAQが紐付けられるキャンペーン。 |
| `faqs` | はい | 空ではないFAQ項目の配列（最大500件）。各項目には空ではない `question` と `answer` が必要です。また、`is_active`、`is_global`、`category`、`tags`、および `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()
```

**レスポンス**

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

`faq_ids` は、作成または更新されたFAQ IDであり、指定した順序で返されます。

---

## FAQの並び替え

`POST /faqs/reorder`

キャンペーンのFAQの表示順序を設定します。希望する順序でFAQ IDの**完全な**リストを指定してください。各FAQの位置は、配列内での順序に合わせて更新されます。

**リクエストフィールド**

| フィールド | 必須 | 説明 |
|---|---|---|
| `campaign_id` | はい | FAQの順序を変更するキャンペーン。 |
| `ordered_faq_ids` | はい | 希望する表示順序で並べた、キャンペーンのすべてのFAQ IDを含む空ではない配列（最大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()
```

**レスポンス**

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

キャンペーンまたはFAQ IDのいずれかがアカウント内に見つからない場合、リクエストは `404 One or more FAQs were not found` を返します。

---

## FAQをキャンペーンにリンクする

`POST /faqs/{faqId}/link`

既存のFAQを別のキャンペーンにリンクします。FAQは任意の数のキャンペーンで共有できるため、同じ回答を一度管理するだけで済みます。

**リクエストフィールド**

| フィールド | 必須 | 説明 |
|---|---|---|
| `campaign_id` | はい | FAQをリンクするキャンペーン。 |

**cURL**

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

**JavaScript**

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

**Python**

```python
import requests

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

**レスポンス**

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

---

## キャンペーンからFAQのリンクを解除する

`POST /faqs/{faqId}/unlink`

FAQ自体を削除することなく、キャンペーンからFAQを削除します。FAQはライブラリ内に残り、他のキャンペーンとのリンクも維持されます。

**リクエストフィールド**

| フィールド | 必須 | 説明 |
|---|---|---|
| `campaign_id` | はい | FAQを削除する対象のキャンペーン。 |

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

**レスポンス**

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

---

## FAQの検索データを再構築する

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

AIボットがこのFAQを見つけるために使用するデータ（セマンティック検索およびキーワード検索データ）の再構築をキューに入れます。これは、FAQが期待通りに回答で取得されない場合に役立ちます。再構築はバックグラウンドで実行され、通常数秒以内に完了します。再構築中は、FAQが一時的にAIの回答から除外される場合があります。

このエンドポイントは、レスポンス送信後も処理が継続されるため、`202 Accepted` を返します。`status` は常に `"processing"` となります。完了を確認する必要がある場合は、後ほどFAQを再取得してください。

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

**レスポンス**

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

---

## AI支援によるFAQ管理

以下のエンドポイントは単なるCRUDを超えた機能を提供します。ダッシュボードのFAQエディタで使用されているものと同じAI支援ツールを呼び出し、重複の検出、ドキュメントからのエントリ生成、FAQと未解決のナレッジギャップタスクの照合を行います。このセットのリクエストボディでは、このページの他の場所で使用されている `snake_case` ではなく、アプリ独自のリクエスト形式に合わせた `camelCase` フィールド名（`campaignId`、`taskId`、`sourceIds`...）を使用します。フィールド名を推測するのではなく、以下の例をコピーしてください。

### FAQをキャンペーン専用のコピーとしてフォークする

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

既存のFAQのコピーである新しいFAQを作成し、単一のキャンペーンにスコープを限定した上で、元のFAQの代わりにそのキャンペーンを新しいコピーに再リンクします。元のFAQが使用されている他の場所を変更せずに、特定のキャンペーン用に回答をカスタマイズしたい場合に使用します。元のFAQはそのまま残りますが、このキャンペーンとのリンクのみが解除されます。

**リクエストフィールド**

| フィールド | 必須 | 説明 |
|---|---|---|
| `campaign_id` | はい | 新しいコピーのスコープ対象とし、元のFAQから再リンクするキャンペーン。 |
| `question` | はい | 新しいキャンペーン固有のコピーに対する質問。 |
| `answer` | はい | 新しいキャンペーン固有のコピーに対する回答。 |

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

**レスポンス** — `201 Created`

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

### 類似したFAQを検索する

`POST /faqs/dedupe`

FAQライブラリをスキャンして、類似または重複しているエントリを検索し、確信度が高い場合にそれらを統合または削除するバックグラウンドジョブを開始します。一括インポート後や、AI生成によるFAQを繰り返した結果ライブラリに重複が生じた場合に便利です。アカウントごとに一度に実行できる重複排除ジョブは1つだけです。ジョブの実行中に2つ目を開始しようとすると `409` が返されます。

**リクエストフィールド**

| フィールド | 必須 | 説明 |
|---|---|---|
| `sourceIds` | いいえ | 重複排除のスコープ対象とするナレッジベースソースIDの配列。省略した場合はFAQライブラリ全体がスキャンされます。 |

**cURL**

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

**JavaScript**

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

**Python**

```python
import requests

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

**応答** — `202 Accepted`

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

ジョブはバックグラウンドで実行され、大規模なライブラリでは通常数分かかります。個別のステータスエンドポイントはありません。少し待ってから [`GET /faqs`](#list-faqs) を再取得し、変更内容を確認してください。結果の確認が完了したら、以下の破棄エンドポイントを呼び出して結果をクリアします。

### 重複チェック結果を破棄する

`POST /faqs/dedupe/dismiss`

完了した重複排除ジョブをクリアし、アクティブな結果として表示されないようにします。べき等であるため、破棄するものがない場合でも安全に呼び出せます。ジョブがまだ `queued` または `processing` の状態である場合は `409` を返します（完了していない実行を破棄することはできません）。

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

**レスポンス**

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

### アップロードされたドキュメントからFAQを生成する

`POST /faqs/generate-from-documents`

アカウントのファイルストレージに既に存在する1つ以上のドキュメントを読み込み、その内容に基づいてAIにFAQのドラフトを作成させます。既存のライブラリと照合し、重複を作成する代わりに既存のエントリを再利用または更新します。結果はすぐには書き込まれず、キャンペーン上の保留中の変更セットとして保存されます。これを確認し、以下の[レビュー済みFAQ変更の適用](#apply-reviewed-faq-changes)で適用（または破棄）します。これはドキュメントテキストに対するAI生成処理であるため、クレジットを消費します。

このエンドポイントはファイルを直接送信しません。`storagePath`は、ナレッジベースAPIの[アップロード済みドキュメントのインポート](knowledge-base.md#import-an-uploaded-document)と同じ慣例に従い、自身のアップロードフォルダ(`users/{your user id}/uploads/`)内に既に存在するファイルを指定する必要があります。

**リクエストフィールド**

| フィールド | 必須 | 説明 |
|---|---|---|
| `campaignId` | はい | 生成されたFAQの提案先となるキャンペーン。 |
| `uploadedFiles` | はい | 読み込むファイルの空でない配列。各要素は`{ storagePath, fileName, mimeType }`。 `storagePath`は`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()
```

**応答** — `202 Accepted`

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

`faqCount`はレビュー待ちの提案された変更の合計数です。`reusedCount`、`modifiedCount`、`newCount`は、既存のエントリと一致して変更なしとなったFAQ、AIが編集を提案しているFAQ、および完全に新規のFAQに分類されます。アップロードされたファイルは、処理の成否にかかわらず、完了後にストレージから削除されます。

### レビュー済みFAQ変更の適用

`POST /faqs/apply-optimization`

AIが提案した保留中のFAQ変更セット（上記の[ドキュメントからFAQを生成](#generate-faqs-from-uploaded-documents)や、ダッシュボードのFAQ最適化レビューによって作成されたもの）を適用（または破棄）します。どの提案された変更を受け入れるかを正確に選択します。指定しなかったものは変更されません（省略された変更は、削除を意味する拒否としては扱われません）。

**リクエストフィールド**

| フィールド | 必須 | 説明 |
|---|---|---|
| `campaignId` | どちらか一方 | 保留中のFAQ変更を適用するキャンペーン。 |
| `agentId` | どちらか一方 | エージェントネイティブアカウントにおいて、保留中のFAQ変更を適用するAIエージェント。`campaignId` / `agentId`のいずれか一方のみを指定してください。両方は指定できません。 |
| `acceptedChanges` | はい | 受け入れる変更の配列。各要素は`{ action, faq_id?, faq_ref_path?, question?, answer?, edit_scope? }`。`action`は`keep`、`remove`、`add_from_library`、`create_new`、`modify`のいずれかです。何も適用せずに保留中のセットを破棄するには、空の配列を送信してください。 |

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

**レスポンス**

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

`faq_count`は、適用後のキャンペーン（またはエージェント）のリンクされたFAQの合計数です。適用すべき保留中の変更セットがない場合、レスポンスは`{ "success": true, "message": "No pending FAQ changes to apply" }`となります。

### タスクに類似したFAQを検索する

`POST /faqs/similar-for-task`

ナレッジギャップタスクの質問に対する関連度に基づいてFAQライブラリをランク付けします。これはダッシュボードの「既存のFAQを使用」ピッカーの背後にある検索機能と同じです。読み取り専用です。`taskId`は`faq_update`タイプのタスクを指定する必要があります。

このエンドポイントは、不明なタスクのような予期された失敗であっても、常に `200` を返します。HTTPステータスではなく、ボディ内の `success` を確認してください。

**リクエストフィールド**

| フィールド | 必須 | 説明 |
|---|---|---|
| `taskId` | はい | 一致するものを検索する `faq_update` タスク。 |
| `limit` | いいえ | 返される最大一致数。デフォルトは20で、上限は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()
```

**レスポンス**

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

一致するものは `similarity` （利用可能な場合はセマンティックマッチ、それ以外はキーワードの重複）でソートされ、最適なものが最初に来ます。ソフトな失敗の場合、形状は `{ "success": false, "error": "...", "error_code": 404 }` となり、`error_code` は通常HTTPステータスが示す内容を反映します。

### 既存のFAQでタスクを解決する

`POST /faqs/resolve-task`

知識ギャップタスクを、すでに持っているFAQにリンクさせることで解決します（新しく作成する代わりに）。そのFAQの回答をギャップを引き起こした連絡先に送信し、タスクを完了としてマークします。[タスクに類似したFAQを検索](#find-faqs-similar-to-a-task)した結果、すでにその質問をカバーしている既存のFAQが見つかった場合に使用してください。

上記のエンドポイントと同様に、これは常に `200` を返します。ボディ内の `success` を確認してください。

**リクエストフィールド**

| フィールド | 必須 | 説明 |
|---|---|---|
| `taskId` | はい | 解決する `faq_update` タスク。 |
| `faqId` | はい | リンクして回答として送信する既存のFAQ。 |

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

**レスポンス**

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

`follow_up_status` は、連絡先へのフォローアップがどうなったかを伝えます。`published`（すぐに送信済み）、`queued`（AIがその連絡先への返信の途中だったため、次に出力されます）、`skipped_no_contact`（タスクにリンクされた連絡先がない）、または `skipped_no_campaign`（送信するキャンペーンがない）。

---

## FAQs API エラー

FAQ エンドポイントは、標準的なエラーエンベロープを返します。

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

| ステータス | FAQエンドポイントで発生する場合 |
|---|---|
| `400` | 必須フィールドが欠落しているか無効です（例：空の `question`、欠落している `campaign_id`、または一括リクエストで500項目を超えているなど）。 |
| `404` | FAQまたはキャンペーンが見つかりませんでした。存在しないか、別のアカウントに属しています。 |
| `409` | 重複排除ジョブがすでに `queued`/`processing` の間に `POST /faqs/dedupe` が呼び出されたか、ジョブが完了していない間に `POST /faqs/dedupe/dismiss` が呼び出されました。 |

すべてのエンドポイントが返す共通コード（`401`、`403`（プランにAPIアクセスが含まれていない）、`429`（レート制限）、`500`）については、再試行のガイダンスと共に[エラーとページネーション](errors-and-pagination.md)に記載されています。

`POST /faqs/similar-for-task` と `POST /faqs/resolve-task` は、このページにおける2つの例外です。これらは予期された失敗（不明なタスク、間違ったタスクタイプ）であっても `200` を返し、代わりに実際のステータスをボディの `error_code` に格納します。各エンドポイントの説明を参照してください。

---

## 関連情報

- [キャンペーンAPI](campaigns.md) — FAQがリンクされているキャンペーン。
- [ナレッジベースAPI](knowledge-base.md) — ウェブサイトやドキュメントを自動的にFAQにインポートし、FAQを再利用可能なナレッジグループにまとめます。
- [APIアクセス](../integrations/api-access.md) — APIキーを生成します。
- [認証](authentication.md) — キーを渡すためのすべての方法。
