
# キャンペーン API

キャンペーンは、AIボットが連絡先と対話するために必要なすべて（指示、実行するチャネル、稼働時間、フォローアップの動作など）をまとめたものです。キャンペーンAPIを使用すると、ダッシュボードではなく独自のコードからキャンペーンの一覧表示、作成、更新、複製、有効化、アーカイブ、微調整を行うことができます。

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

> **注意:** 一部の例ではシンプルな `?apiKey=YOUR_API_KEY` クエリ形式を使用し、他の例では `X-API-Key` ヘッダーを使用しています。どちらもどこでも機能します。設定に適したものを使用してください。

---

## キャンペーンタイプ

キャンペーンを作成する際は、以下のいずれかのタイプを選択する必要があります：

| タイプ | 用途 |
|---|---|
| `Incoming from Unknown Contacts` | 初めてメッセージを送ってきたユーザーに対してボットが返信します。 |
| `Outgoing` | キャンペーンに追加した連絡先に対してボットが会話を開始します。 |
| `Keywords` | **不活性 - 使用しないでください。** `Keywords` キャンペーンは不活性です。下位互換性のために受け入れられていますが、すべてのチャネルにおいてインバウンドルーティングからは認識されず、トリガーキーワードも読み込まれません。代わりに、AIエージェントの **キーワード** タイプの「エントリーポイント」を使用してください。 |
| `Combined` | インバウンドとアウトバウンドの動作を組み合わせたものです。 |

**大文字と小文字は区別されません。** `type`、`status`、`booking_provider`、`first_response_mode`、`bot.anthropic_model`、および`bot.ai_speed`はすべて大文字・小文字を区別せず、`"live"`、`"Live"`、`"LIVE"`はすべて同じものとして扱われます。値は正規化された形式で保存され、キャンペーンを読み取った際にその形式で返されます。唯一の例外は一時停止のペアです。`"Paused"`と`"paused"`は完全に異なる状態であるため、`"PAUSED"`のような曖昧な綴りは`400`で拒否され、どちらかを選択するよう求められます。

### 2つの停止状態

| ステータス | 書き込み元 | 意味 |
|---|---|---|
| `Paused` | プラットフォーム独自の安全チェック（エンゲージメントの低下、繰り返される送信エラー、制限到達）および新しいエージェントとブロードキャストのサーフェス | キャンペーンが保留されています。スケジュールされたスイープにより、理由が解消されれば安全のための停止が自動的に解除されることがあります。 |
| `paused` | ダッシュボードの「一時停止」ボタン、および再開時の `resumed` | 人の手によって一時停止されました。スケジュールされた送信は、再開時に破棄され、再構築されます。 |

どちらの状態でもキャンペーンは停止します。インバウンドルーティングは、ステータスが正確に `Live` である場合にのみ実行されます。**APIから一時停止するには `Paused` を、再開するには `Live` を使用してください**。小文字のペアはダッシュボードボタン用として存在しており、引き続き機能します。

これらは、1つの会話内でAIが返信を停止した場合の動作とは異なります。これは連絡先ごとのスイッチであり、連絡先上の `is_bot_active` です。人間が対応を引き継いだとき、連絡先がオプトアウトしたとき、またはAIがチャットを終了したときに設定されます。キャンペーン自体のステータスは影響を受けず、キャンペーン内の他のすべての会話は実行され続けます。[1つの連絡先に対してAIを一時停止または再開する](messages.md#pause-or-resume-the-ai-for-one-contact)を参照してください。

> **キャンペーンを作成しても、誰がチャネルに応答するかは決定されません。** ルーティングはキャンペーンではなく、AIエージェントの **エントリーポイント** によって処理されます。各チャネルには、そのチャネルで新規かつ未知の連絡先に応答するエージェントを指定するチャネルデフォルトのエントリーポイントが1つあります。設定は `PUT /entry-points/channel-defaults`、アカウントでラダーが有効かどうかを確認するには `GET /entry-points/routing-status`、クリアするには `DELETE /entry-points/channel-defaults` を使用します。`POST /channels/campaign` は引き続きレガシーなチャネルごとのキャンペーンルーティングマップを書き込みますが、そのマップはどのチャネルのインバウンドルーティングでも参照されなくなりました。これはロールバック目的でのみ保持されています。これに基づいた構築は行わないでください。両方のインターフェースを並べて確認するには、[チャネルをキャンペーンにルーティングする](channels.md#route-a-channel-to-a-campaign) を参照してください。

---

## キャンペーンの一覧表示

`GET /campaigns`

キャンペーンを新しい順に返します。`archived=true` を渡さない限り、アーカイブされたキャンペーンは除外されます。

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

| パラメータ | 必須 | 説明 |
|---|---|---|
| `limit` | いいえ | 返すキャンペーンの最大数。デフォルトは `50`、最大は `100` です。 |
| `cursor` | いいえ | ページネーションカーソル。次のページを取得するには、前回のレスポンスから `next_cursor` の値を渡します。 |
| `archived` | いいえ | アーカイブされたキャンペーンを含めるには `true` に設定します。 |

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/campaigns?limit=20&apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/campaigns?limit=20", {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
console.log(data.campaigns, data.next_cursor);
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/campaigns",
    params={"limit": 20},
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
print(data["campaigns"], data["next_cursor"])
```

**レスポンス**

```json
{
  "success": true,
  "campaigns": [
    {
      "id": "NBCXrhqGPSFsd6MV7pRo",
      "name": "Inbound WhatsApp Leads",
      "type": "Incoming from Unknown Contacts",
      "status": "Live",
      "enabled": true,
      "archived": false,
      "created_at": 1700000000000,
      "ai_mode": true,
      "language": "en",
      "enabled_channels": ["whatsapp", "instagram"]
    }
  ],
  "next_cursor": "NBCXrhqGPSFsd6MV7pRo"
}
```

`next_cursor` が `null` の場合、最後のページに到達しています。

---

## キャンペーンの取得

`GET /campaigns/{campaignId}`

ライブボット設定（`bot`）、フォローアップ設定、有効なチャネル、およびキーワードを含む、キャンペーンの完全なドキュメントを返します。タイムスタンプはエポックミリ秒で返されます。

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo?apiKey=YOUR_API_KEY"
```

**JavaScript**

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

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
campaign = res.json()["campaign"]
```

**レスポンス**

```json
{
  "success": true,
  "campaign": {
    "id": "NBCXrhqGPSFsd6MV7pRo",
    "name": "Inbound WhatsApp Leads",
    "type": "Incoming from Unknown Contacts",
    "status": "Live",
    "language": "en",
    "ai_mode": true,
    "enabled": true,
    "archived": false,
    "created_at": 1700000000000,
    "enabled_channels": ["whatsapp", "instagram"],
    "bot": {
      "instructions": "Greet warmly and ask about their goals.",
      "goal": "Book a discovery call.",
      "ai_speed": "balanced",
      "anthropic_model": "standard",
      "max_messages": 20
    }
  }
}
```

::: note
**注:** 別の所有アカウントのキャンペーンは `404 Campaign not found` を返します（`403` ではありません）。そのため、ID が別のアカウントに存在するかどうかを判別することはできません。
:::


---

## キャンペーンの作成

`POST /campaigns`

新しいキャンペーンを作成します。`name` と `type` は必須ですが、それ以外はすべて任意です。同じリクエストに他のキャンペーンフィールド（例：`language`、`ai_mode`、または完全な `bot` 設定オブジェクトなど）を含めることができ、それらは新しいキャンペーンとともに保存されます。所有者と作成時間は自動的に設定されます。

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

| フィールド | 必須 | 説明 |
|---|---|---|
| `name` | はい | キャンペーン名。 |
| `type` | はい | 上記4つのキャンペーンタイプのいずれか。 |
| `language` | いいえ | ボットが返信する言語（例: `"en"`）。 |
| `ai_mode` | いいえ | AIモードがオンかどうか（`true`/`false`）。AIエージェントが回答するキャンペーンでは、読み取り値は保存された値ではなく、エージェントの**アクティブ**トグルを返します。以下の更新に関する注記を参照してください。 |
| `bot` | いいえ | ボット設定オブジェクト（[ボット設定フィールド](#bot-configuration-fields)を参照）。 |
| `list_id` | いいえ | 関連付ける連絡先リストのID。 |
| `event_id` | いいえ | AIが予約可能なイベントタイプのID。 |
| `event_ids` | いいえ | イベントタイプIDの配列として、複数のイベントタイプを一度に指定します。最初のIDがデフォルトとなります。`event_id`または`event_ids`のいずれかを送信してください。両方を同時に送信することはできません。 |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/campaigns?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Spring Promo",
    "type": "Outgoing",
    "language": "en",
    "ai_mode": true,
    "bot": {
      "instructions": "Greet warmly and ask about their goals.",
      "goal": "Book a discovery call."
    }
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/campaigns", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    name: "Spring Promo",
    type: "Outgoing",
    language: "en",
    ai_mode: true,
    bot: {
      instructions: "Greet warmly and ask about their goals.",
      goal: "Book a discovery call.",
    },
  }),
});
const { campaign_id } = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/campaigns",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "name": "Spring Promo",
        "type": "Outgoing",
        "language": "en",
        "ai_mode": True,
        "bot": {
            "instructions": "Greet warmly and ask about their goals.",
            "goal": "Book a discovery call.",
        },
    },
)
campaign_id = res.json()["campaign_id"]
```

**レスポンス**

```json
{
  "success": true,
  "campaign_id": "NBCXrhqGPSFsd6MV7pRo"
}
```

---

## キャンペーンの更新

`PUT /campaigns/{campaignId}`

キャンペーンを部分的に更新します。変更したいフィールドのみを送信してください。これが唯一の一般的な更新用動詞です。`PATCH /campaigns/{campaignId}` は存在しません（2つの `PATCH` ルートは、限定的な [有効化](#enable-or-disable-a-campaign) および [アーカイブ](#archive-or-restore-a-campaign) の切り替えです）。

**変更可能なフィールド。** キャンペーンエディターが書き込むすべての項目（`name`、`status`、`type`、`language`、`ai_mode`、`enabled_channels`、トリガーおよびドリップ設定、予約およびフォローアップフラグ、Instagram/Facebook監視フィールド、および `bot` 設定全体を含む）が対象です。IDと所有権はキャンペーンの存続期間中ロックされます。`user`、`id`、`created_at` は拒否され、エンドポイントが認識しないフィールド名も同様です。拒否はフィールド単位ではなくリクエスト単位で行われます。1つでも不明なキーが含まれていると `400` が返され、そのリクエスト内の**何も**書き込まれません。

**エージェントがバックエンドにあるキャンペーンの`ai_mode`は、エージェントの状態を反映します。** キャンペーンがAIエージェントによって回答される場合、キャンペーンを読み取ると、そのエージェントの**有効**トグル（AIが応答するかどうかを実際に決定するスイッチ）から派生した`ai_mode`が返されます。そのようなキャンペーンに対して`ai_mode`を書き込むことは可能ですが、読み取り値は変更されません。代わりに（ダッシュボードまたはAgents APIを使用して）エージェントの有効トグルをオンまたはオフにしてください。エージェントのない従来のキャンペーンでは、`ai_mode`はこれまで通り保存された値を読み書きします。

**ボットフィールドは上書きではなくマージされます。** ボット設定は、ドット付きキー（`"bot.instructions": "..."`）またはネストされたオブジェクト（`"bot": { "instructions": "..." }`）として送信してください。どちらもリーフ単位で書き込まれるため、省略したフィールドは現在の値を保持します。`bot.instructions`、`bot.goal`、`bot.rules`、`bot.personality` はすべてこの方法で編集可能であり、[ボット設定フィールド](#bot-configuration-fields)にリストされている他のすべてのボット設定も同様です。`test_bot`、`frequency`、`follow_up_config` についても同様です。

ボット設定を全面的に置き換える（送信しなかったフィールドを削除する）には、完全なオブジェクトを指定して `bot_replace`（または `test_bot_replace`）を使用してください。同じリクエスト内で同じオブジェクトに対して置換とマージを組み合わせることはできません。それを行うと `400` が返されます。

::: note
**注意:** API経由で `bot.*` を書き込むと、ライブキャンペーンに**即座に**反映されます。ダッシュボードエディターの動作は異なり、そこでの編集は下書きとして保存され、クライアントが「公開」をクリックしたときにのみライブになります。そのため、クライアントが公開していないダッシュボードの変更がある場合、それらは `test_bot` に留まり、`bot` のAPI読み取りではAIが現在使用している内容が正しく表示されます。
:::


いくつかのフィールドは直接書き込むのではなく、専用のキーを通じて設定されます。`list_id`は連絡先リスト、`event_id`はイベントタイプ（またはAIが複数予約できるようにする`event_ids`、順序付きのイベントタイプID配列。最初のものがデフォルトとなり、空の配列はすべてリンク解除されます）、`contact_ids`（連絡先IDの配列）はキャンペーンの連絡先に使用します。ナレッジベースのエントリは、このエンドポイントではなく[FAQs API](faqs.md)を通じて管理されます。

**タグはマージされず、置き換えられます。** `tags` を完全な配列として送信すると、それがキャンペーンのタグセットになります。フィールドや単一のタグを追加・編集するエンドポイントについては、[キャンペーンタグ](#campaign-tags)を参照してください。

**cURL**

```bash
curl -X PUT "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Spring Promo v2", "enabled_channels": ["whatsapp"] }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo",
  {
    method: "PUT",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      name: "Spring Promo v2",
      enabled_channels: ["whatsapp"],
    }),
  }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.put(
    "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"name": "Spring Promo v2", "enabled_channels": ["whatsapp"]},
)
data = res.json()
```

**レスポンス**

```json
{
  "success": true,
  "campaign_id": "NBCXrhqGPSFsd6MV7pRo"
}
```

---

## キャンペーンの削除

`DELETE /campaigns/{campaignId}`

キャンペーンを完全に削除します。この操作は取り消せません。キャンペーンを後で必要になる可能性がある場合は、代わりに[アーカイブ](#archive-or-restore-a-campaign)してください。

**cURL**

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo?apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo",
  { 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/campaigns/NBCXrhqGPSFsd6MV7pRo",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

**レスポンス**

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

---

## キャンペーンを複製する

`POST /campaigns/{campaignId}/duplicate`

すべての設定を保持したままキャンペーンのコピーを作成します。コピーは**無効**な状態で作成され、名前に `(copy)` というサフィックスが付加されるため、明示的に有効化するまでメッセージが送信されることはありません。

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/duplicate?apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/duplicate",
  { method: "POST", headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const { campaign_id } = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/duplicate",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
new_campaign_id = res.json()["campaign_id"]
```

**レスポンス**

```json
{
  "success": true,
  "campaign_id": "aZ9plnewCopyId01234"
}
```

> **同一アカウント内**での重複コピー。

---


## キャンペーンを有効化または無効化する

`PATCH /campaigns/{campaignId}/enabled`

キャンペーンのオン/オフを切り替えます。無効化されたキャンペーンは連絡先への関与を停止しますが、すべての設定は保持されます。

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

| フィールド | 必須 | 説明 |
|---|---|---|
| `enabled` | はい | `true` で有効、`false` で無効にします。ブール値である必要があります。 |

**cURL**

```bash
curl -X PATCH "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/enabled?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "enabled": true }'
```

**JavaScript**

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

**Python**

```python
import requests

res = requests.patch(
    "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/enabled",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"enabled": True},
)
data = res.json()
```

**レスポンス**

```json
{
  "success": true,
  "campaign_id": "NBCXrhqGPSFsd6MV7pRo",
  "enabled": true
}
```

---

## キャンペーンのアーカイブまたは復元

`PATCH /campaigns/{campaignId}/archived`

キャンペーンをアーカイブまたは復元します。アーカイブされたキャンペーンはデフォルトのキャンペーン一覧には表示されませんが、すべてのデータは保持され、いつでも復元可能です。

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

| フィールド | 必須 | 説明 |
|---|---|---|
| `archived` | はい | `true` でアーカイブ、`false` で復元します。ブール値である必要があります。 |

**cURL**

```bash
curl -X PATCH "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/archived?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "archived": true }'
```

**JavaScript**

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

**Python**

```python
import requests

res = requests.patch(
    "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/archived",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"archived": True},
)
data = res.json()
```

**レスポンス**

```json
{
  "success": true,
  "campaign_id": "NBCXrhqGPSFsd6MV7pRo",
  "archived": true
}
```

---

## ボット設定の更新

`PUT /campaigns/{campaignId}/bot-config`

これは、個々のボット設定を変更するための安全な方法です。送信した各フィールドは既存のボット設定に**マージ**されるため、省略したフィールドはそのまま保持されます。ボットの一部のみを調整したい場合は、campaign-updateエンドポイントの代わりにこちらを使用してください。

フィールドキーには、英数字、アンダースコア、ハイフンのみを使用してください。

**cURL**

```bash
curl -X PUT "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/bot-config?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "instructions": "Always answer in a friendly, concise tone.",
    "ai_speed": "balanced"
  }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/bot-config",
  {
    method: "PUT",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      instructions: "Always answer in a friendly, concise tone.",
      ai_speed: "balanced",
    }),
  }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.put(
    "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/bot-config",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "instructions": "Always answer in a friendly, concise tone.",
        "ai_speed": "balanced",
    },
)
data = res.json()
```

**レスポンス**

```json
{
  "success": true,
  "campaign_id": "NBCXrhqGPSFsd6MV7pRo"
}
```

### ボット設定フィールド

すべてのボットフィールドは任意です。設定したいフィールドのみを送信してください。ここに記載されている以外の追加のボットフィールドも受け入れられ、そのまま保存されます。

| フィールド | 型 | 説明 |
|---|---|---|
| `instructions` | string | ボットが連絡先とどのように会話するかを制御する主要な指示です。 |
| `rules` | string | ボットが常に従わなければならない厳格なルールです。 |
| `goal` | string | 各会話においてボットが目指すべき成果です。 |
| `personality` | string | ボットの口調や性格の説明です。 |
| `ai_speed` | string | 返信する前にAIが適用する推論の度合いです。`fast`、`fast_thinker`、`balanced`、`thorough` のいずれかです。 |
| `anthropic_model` | string | このキャンペーンの返信に使用されるAI品質ティアです。`standard`、`economy`（非推奨）、`max`、`mini` のいずれかです。`max` および `mini` は、それらのティアを利用可能なアカウントでのみ有効になります。 |
| `max_messages` | integer | 1会話あたりのボットの最大メッセージ数です。 |
| `alert_human_when` | string | ボットが人間のチームメンバーに通知を送る条件です。 |
| `availability` | object | ボットの稼働時間スケジュールです。ここで設定するか、専用の [稼働時間エンドポイント](#set-the-bot-active-hours) を使用できます。 |
| `follow_up_config` | object | フォローアップ動作の設定であり、提供された通りに保存されます。 |

---

## ボットの稼働時間の設定

`PUT /campaigns/{campaignId}/active-hours`

ボットの利用可能スケジュールを設定します。設定された時間外では、ボットは自動的に返信しません。これはボット設定の `availability` フィールドを書き換えます。

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

| フィールド | 必須 | 説明 |
|---|---|---|
| `availability` | はい | 曜日をキーとするオブジェクト。許可されるキーは `monday` から `sunday` までです。それ以外のキーを指定すると `400` が返されます。省略した曜日の設定は変更されません。 |

各曜日には、単一の時間枠、または時間枠の配列を指定します。時間枠には、24時間形式の `HH:MM` で表される `start_time` と `end_time` が含まれます。

**cURL**

```bash
curl -X PUT "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/active-hours?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "availability": {
      "monday": { "start_time": "09:00", "end_time": "17:00" },
      "tuesday": [
        { "start_time": "09:00", "end_time": "12:00" },
        { "start_time": "13:00", "end_time": "17:00" }
      ]
    }
  }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/active-hours",
  {
    method: "PUT",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      availability: {
        monday: { start_time: "09:00", end_time: "17:00" },
        tuesday: [
          { start_time: "09:00", end_time: "12:00" },
          { start_time: "13:00", end_time: "17:00" },
        ],
      },
    }),
  }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.put(
    "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/active-hours",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "availability": {
            "monday": {"start_time": "09:00", "end_time": "17:00"},
            "tuesday": [
                {"start_time": "09:00", "end_time": "12:00"},
                {"start_time": "13:00", "end_time": "17:00"},
            ],
        }
    },
)
data = res.json()
```

**レスポンス**

```json
{
  "success": true,
  "campaign_id": "NBCXrhqGPSFsd6MV7pRo"
}
```

---

## キャンペーンのカスタム関数を一覧表示する

`GET /campaigns/{campaignId}/custom-functions`

このキャンペーンにリンクされているカスタム関数を、完全な定義に解決して返します。カスタム関数は、ボットが会話中に呼び出せる外部のHTTPアクションです（例：ストアの在庫確認やCRMでのレコード作成など）。

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/custom-functions?apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/custom-functions",
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const { custom_functions } = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/custom-functions",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
custom_functions = res.json()["custom_functions"]
```

**レスポンス**

```json
{
  "success": true,
  "custom_functions": [
    {
      "id": "fn_abc123",
      "name": "check_stock",
      "description": "Looks up whether a product is in stock.",
      "url": "https://example.com/api/stock",
      "method": "POST",
      "input": [
        { "name": "sku", "type": "string" }
      ],
      "ai_action": "Tell the customer whether the item is available.",
      "created_at": 1700000000000,
      "updated_at": 1700000500000
    }
  ]
}
```

---

## カスタム関数をキャンペーンにリンクする

`POST /campaigns/{campaignId}/custom-functions`

既存の[カスタム関数](../ai-automation/custom-functions.md)をこのキャンペーンにリンクし、ボットが会話中にその関数を呼び出せるようにします。すでにリンクされている関数をリンクしようとしても、何も起こりません。

| フィールド | 必須 | 説明 |
|---|---|---|
| `custom_function_id` | はい | リンクするカスタム関数のID。 |

```bash
curl -X POST "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/custom-functions?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "custom_function_id": "fn_abc123" }'
```

**レスポンス**

```json
{
  "success": true,
  "campaign_id": "NBCXrhqGPSFsd6MV7pRo",
  "custom_function_id": "fn_abc123"
}
```

---

## カスタム関数をキャンペーンからリンク解除する

`DELETE /campaigns/{campaignId}/custom-functions/{customFunctionId}`

リンクされていない関数をリンク解除しようとしても、何も起こりません。

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/custom-functions/fn_abc123?apiKey=YOUR_API_KEY"
```

**レスポンス**

```json
{
  "success": true,
  "campaign_id": "NBCXrhqGPSFsd6MV7pRo",
  "custom_function_id": "fn_abc123"
}
```

---

## ナレッジベースソースをキャンペーンにリンクする

`POST /campaigns/{campaignId}/kb-sources`

ナレッジベースソース（[FAQs API](faqs.md)経由で作成）をこのキャンペーンにリンクし、ボットが回答時にそれを参照できるようにします。すでにリンクされているソースをリンクしようとしても、何も起こりません。

| フィールド | 必須 | 説明 |
|---|---|---|
| `kb_source_id` | はい | リンクするナレッジベースソースのID。 |

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

**レスポンス**

```json
{
  "success": true,
  "campaign_id": "NBCXrhqGPSFsd6MV7pRo",
  "kb_source_id": "kb_abc123"
}
```

---

## ナレッジベースソースをキャンペーンからリンク解除する

`DELETE /campaigns/{campaignId}/kb-sources/{kbSourceId}`

リンクされていないソースをリンク解除しようとしても、何も起こりません。

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/kb-sources/kb_abc123?apiKey=YOUR_API_KEY"
```

**レスポンス**

```json
{
  "success": true,
  "campaign_id": "NBCXrhqGPSFsd6MV7pRo",
  "kb_source_id": "kb_abc123"
}
```

---

## MCPサーバーをキャンペーンにリンクする

`POST /campaigns/{campaignId}/mcp-servers`

MCPサーバーをこのキャンペーンにリンクし、会話中にボットがそのサーバーのツールにアクセスできるようにします。すでにリンクされているサーバーをリンクしようとしても、何も起こりません。

| フィールド | 必須 | 説明 |
|---|---|---|
| `mcp_server_id` | はい | リンクするMCPサーバーのID。 |

```bash
curl -X POST "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/mcp-servers?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "mcp_server_id": "mcp_abc123" }'
```

**レスポンス**

```json
{
  "success": true,
  "campaign_id": "NBCXrhqGPSFsd6MV7pRo",
  "mcp_server_id": "mcp_abc123"
}
```

---

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

`DELETE /campaigns/{campaignId}/mcp-servers/{mcpServerId}`

リンクされていないサーバーのリンクを解除しようとしても、何も起こりません。

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/mcp-servers/mcp_abc123?apiKey=YOUR_API_KEY"
```

**レスポンス**

```json
{
  "success": true,
  "campaign_id": "NBCXrhqGPSFsd6MV7pRo",
  "mcp_server_id": "mcp_abc123"
}
```

---

## キャンペーンメディアライブラリ

メディアライブラリには、会話中にボットが送信できる画像、動画、ドキュメント、音声メモが保持されます。

### キャンペーンのメディアライブラリを一覧表示する

`GET /campaigns/{campaignId}/media-library`

```bash
curl "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/media-library?apiKey=YOUR_API_KEY"
```

**レスポンス**

```json
{
  "success": true,
  "campaign_id": "NBCXrhqGPSFsd6MV7pRo",
  "media_items": [
    {
      "id": "media_abc123",
      "item_id": "media_abc123",
      "title": "Pricing sheet",
      "description": "Send when the contact asks about pricing.",
      "media_url": "https://example.com/pricing.pdf",
      "media_content_type": "application/pdf",
      "type": "document",
      "agent_id": "",
      "campaign_id": "NBCXrhqGPSFsd6MV7pRo",
      "media_home": "campaign"
    }
  ]
}
```

`media_url` はアップロード時に取得された署名付きURLです。読み取り時にはすでに期限切れになっている可能性があります。ダッシュボードは必要に応じて再署名を行います。

### メディアアイテムをアップロードする

`POST /campaigns/{campaignId}/media-library`

| フィールド | 必須 | 説明 |
|---|---|---|
| `base64Data` | はい | base64エンコードされたファイル（data-URLプレフィックスなし）。 |
| `mimeType` | はい | ファイルのMIMEタイプ（例: `image/png`）。 |
| `title` | はい | ライブラリおよびAIプロンプトに表示される短いラベル。 |
| `description` | はい | ボットがこのアイテムを送信する**タイミング**を指示する命令。 |
| `fileName` | いいえ | ストレージオブジェクト名の作成に使用される元のファイル名。 |
| `sendMessage` | いいえ | ボットがこのアイテムを送信する際に使用すべき推奨文言。 |
| `maxSendsPerConversation` | いいえ | 会話内でボットが1人の連絡先に対してこのアイテムを送信できる最大回数。デフォルトは `1` です。 |
| `sendAsVoiceNote` | いいえ | 音声アップロードの場合、WhatsAppの音声メモにトランスコードします。デフォルトは `false` （通常の音声ファイルとして保存）です。 |

```bash
curl -X POST "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/media-library?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "base64Data": "iVBORw0KGgoAAAANSUhEUgAA...",
    "mimeType": "image/png",
    "title": "Product photo",
    "description": "Send when the contact asks what the product looks like."
  }'
```

**レスポンス**

```json
{
  "success": true,
  "itemId": "media_abc123",
  "mediaUrl": "https://example.com/product.png",
  "storagePath": "ai_media/campaigns/NBCXrhqGPSFsd6MV7pRo/media_abc123.png",
  "mediaContentType": "image/png",
  "type": "image",
  "isVoiceNote": false
}
```

### メディアアイテムの更新

`PATCH /campaigns/{campaignId}/media-library/{itemId}`

アイテムのメタデータのみを編集します。ファイル自体を置き換えるには、アイテムを削除して新しいものをアップロードしてください。

| フィールド | 説明 |
|---|---|
| `title` | 短いラベル。 |
| `description` | 送信タイミングの指示。 |
| `send_message` | ボットが使用する推奨文言。 |
| `max_sends_per_conversation` | 負ではない整数、または上限を解除する場合は `null`。 |

```bash
curl -X PATCH "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/media-library/media_abc123?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "title": "Updated pricing sheet" }'
```

**レスポンス**

```json
{
  "success": true,
  "campaign_id": "NBCXrhqGPSFsd6MV7pRo",
  "item_id": "media_abc123"
}
```

### メディアアイテムの削除

`DELETE /campaigns/{campaignId}/media-library/{itemId}`

すでに削除されているアイテムを削除しようとしても、何も起こりません。

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/media-library/media_abc123?apiKey=YOUR_API_KEY"
```

**レスポンス**

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

---

## キャンペーンタグ

キャンペーンタグとは、会話中にボットが連絡先に適用するように設定するラベルのことです（例: `hot-lead`、`not-interested`、`booked-a-call`）。各タグには3つの要素があります。

| フィールド | 型 | 説明 |
|---|---|---|
| `name` | string, 必須 | ラベルそのものです。これはボットが連絡先に適用し、後で照合に使用するものであるため、短く固定したものにしてください。 |
| `description` | string | ボットにこのタグを適用する**タイミング**を指示する命令です。これが実際に機能する部分です。「ユーザーがコミュニティへの参加を確認した」といった具体的な内容を使用し、「ホットリード」のような抽象的なものは避けてください。 |
| `webhook` | string | タグが連絡先に適用された瞬間に `POST` を受け取るURLです。不要な場合は省略してください。 |
| `tag_id` | string | オプション。このエントリをアカウント内の既存のタグにリンクさせます（新規作成ではありません）。以下の単一タグ用エンドポイントを使用して後でこの特定のタグを操作したい場合に指定してください。 |

タグ名はキャンペーン内で一意である必要があります。ボットは**名前によって**タグを適用するため、同じ名前を持つエントリが2つある場合、どちらが適用されるかは定義されません。

### キャンペーンの全タグを設定する

`PUT /campaigns/{campaignId}` を `tags` 配列とともに使用します。

これにより、キャンペーンのタグが送信した内容に完全に置き換えられます。これは、ダッシュボードの「タグ」タブで保存したときと同じ動作です。**毎回完全な配列を送信してください**。送信しなかったタグは削除されます。`[]` を送信すると、すべてのタグがクリアされます。

**cURL**

```bash
curl -X PUT "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tags": [
      {
        "name": "hot-lead",
        "description": "The person confirms they want to buy, or asks how to get started right away.",
        "webhook": "https://example.com/hooks/campaign-events"
      },
      {
        "name": "not-interested",
        "description": "The person declines the offer or says they are not a fit."
      }
    ]
  }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo",
  {
    method: "PUT",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      tags: [
        {
          name: "hot-lead",
          description:
            "The person confirms they want to buy, or asks how to get started right away.",
          webhook: "https://example.com/hooks/campaign-events",
        },
        {
          name: "not-interested",
          description: "The person declines the offer or says they are not a fit.",
        },
      ],
    }),
  }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.put(
    "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "tags": [
            {
                "name": "hot-lead",
                "description": "The person confirms they want to buy, or asks how to get started right away.",
                "webhook": "https://example.com/hooks/campaign-events",
            },
            {
                "name": "not-interested",
                "description": "The person declines the offer or says they are not a fit.",
            },
        ]
    },
)
data = res.json()
```

**レスポンス**

```json
{
  "success": true,
  "campaign_id": "NBCXrhqGPSFsd6MV7pRo"
}
```

タグを読み取るには [`GET /campaigns/{campaignId}`](#get-a-campaign) を使用します。

### タグを1つ追加する

`POST /campaigns/{campaignId}/tags`

残りのタグを再送信することなく、タグを1つ追加します。このリクエストで構築していないセットに追加する場合に使用します。

```bash
curl -X POST "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/tags?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "tag": { "name": "booked-a-call", "description": "The person confirms a booked time." } }'
```

まったく同じタグを2回投稿しても、2回目は何も起こりません。同じ `tag_id` を異なる名前や説明で投稿すると、最初のエントリを編集するのではなく、**2番目の**エントリとして追加されます。その場で編集するには、以下のエンドポイントを使用してください。

### タグを1つ更新または削除する

`PUT /campaigns/{campaignId}/tags/{tagId}`
`DELETE /campaigns/{campaignId}/tags/{tagId}`

これらは`tag_id`によって1つのエントリを指定するため、それを使用して作成されたタグでのみ機能します。`tag_id`がないタグの場合は、上記の配列全体を対象とする`PUT /campaigns/{campaignId}`で変更してください。

```bash
curl -X PUT "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/tags/tag_abc123?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "tag": { "name": "hot-lead", "description": "Updated instruction." } }'
```

キャンペーンに含まれていない `tagId` は、`"Tag not found in campaign tags"` を伴う `404` を返します。

---

## キャンペーンのチャネルを切り替える

`POST /campaigns/{campaignId}/channels`

キャンペーンの `enabled_channels` 配列に対してチャネルの追加や削除を行います。配列全体を再送信するよりも安全で、他のプロセスが同時にキャンペーンを編集している可能性がある場合に [`PUT /campaigns/{campaignId}`](#update-a-campaign) よりも適しています。

単一の切り替え、またはバッチ処理のいずれかを送信してください。同じリクエスト内で両方を行うことはできません。

```json
{ "channel": "whatsapp", "action": "add" }
```

```json
{ "add": ["whatsapp", "instagram"], "remove": ["sms"] }
```

| フィールド | 説明 |
|---|---|
| `channel` | 切り替えるチャネルを1つ指定します。`action` と組み合わせて使用してください。 |
| `action` | `"add"` または `"remove"`。`channel` と組み合わせて使用してください。 |
| `add` | 追加するチャネルの配列。バッチ形式 — `channel`/`action` の代わりに使用してください。 |
| `remove` | 削除するチャネルの配列。バッチ形式。 |

有効なチャネル: `whatsapp`, `whatsapp_web`, `sms`, `instagram`, `messenger`, `facebook`, `chat_widget`, `custom_channel`, `imessage`, `telegram`, `instagram_private`, `line`, `viber`, `tiktok`, `email`, `linkedin`, `skool`。

```bash
curl -X POST "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/channels?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "channel": "whatsapp", "action": "add" }'
```

**レスポンス**

```json
{
  "success": true,
  "campaign_id": "NBCXrhqGPSFsd6MV7pRo",
  "added": ["whatsapp"],
  "removed": []
}
```

> これはキャンペーンが宣伝するチャネルを変更するだけであり、誰がチャネルに応答するかを決定するものではありません。その詳細については、上記の [キャンペーンタイプ](#campaign-types) および以下の [キャンペーンをインバウンドチャネルにルーティングする](#route-a-campaign-to-incoming-channels) を参照してください。

---

## コメントからDMへ (InstagramおよびFacebook)

「コメントからDMへ」機能は、投稿へのコメントをプライベートな会話へと変換します。ユーザーがコメントするとボットがDMを送信し、そこからキャンペーンが会話を引き継ぎます。これはすべてキャンペーンオブジェクトを通じて設定されるため、UIのみで完結する設定項目はありません。

まずFacebookページを接続してください（[チャネル接続](channels.md#instagram--messenger-meta)を参照）。その後、[`PUT /campaigns/{campaignId}`](#update-a-campaign)を使用して以下のフィールドを設定します。

> **キャンペーンは`Live`である必要があります。** コメント監視は、`status`が`Live`であるキャンペーンのみを対象とします（大文字・小文字は区別されません。[キャンペーンタイプ](#campaign-types)を参照してください）。その他のステータスではサイレントに無効化され、`"Active"`のような存在しないステータスは、保存されるのではなく`400`で拒否されるようになりました。有効なステータスには、`Draft`、`Pending Approval`、`Scheduled`、`Live`、`Paused`、`Completed`、`Sent`、`Failed`が含まれます。

**フィールド**

| フィールド | 型 | 説明 |
|---|---|---|
| `monitor_instagram_posts` | boolean | 接続されたページのすべてのInstagram投稿を監視します。 |
| `instagram_post_ids` | string[] | 指定したInstagram投稿のみを監視します。`monitor_instagram_posts`がオンの場合は設定しないでください。 |
| `instagram_comment_delay_minutes` | number | コメントからDM送信までの待機時間（分単位）。 |
| `monitor_facebook_posts` | boolean | 接続されたページのすべてのFacebook投稿を監視します。 |
| `facebook_post_ids` | string[] | 指定したFacebook投稿のみを監視します。 |
| `facebook_comment_delay_minutes` | number | DM送信までの遅延時間（分単位）。 |
| `public_comment_reply_instructions` | string | コメント欄に残す公開返信のガイダンス。デフォルトの「DMを確認してください」という文言を上書きします。 |
| `first_response_mode` | string | `"ai"`（デフォルト）は最初のDMと公開返信を生成します。`"exact_text"`はAI生成を行わず、クレジットも消費せずに、指定した文言をそのまま送信します。 |
| `first_response_exact_text` | string | `first_response_mode`が`"exact_text"`の場合に使用される、最初のDMのそのままの文言。そのモードを有効にするために必須です。 |
| `first_response_exact_text_variants` | string[] | 最初のDMの追加文言。送信ごとにランダムで1つ選択されるため、繰り返されるDMが完全に同一になることはありません。 |
| `public_comment_reply_exact_text` | string | `"exact_text"`モードにおける、公開返信のそのままの文言。空欄にすると公開返信をスキップし、DMのみを送信します。 |
| `public_comment_reply_exact_text_variants` | string[] | 公開返信の追加文言。 |
| `monitor_instagram_followers` | boolean | 新しいフォロワーをトリガーとして扱い、最初のDMを送信します（Instagram個人アカウント）。 |
| `follower_outreach_instructions` | string | 新規フォロワーへの最初のDMのガイダンス。 |
| `respond_to_instagram_story_replies` | boolean | AIがInstagramストーリーズへの返信に応答するかどうか。デフォルトは`true`です。`false`を設定すると、AIによる返信を行わずに、ストーリーズへの返信を（ストーリーズを添付した状態で）チャットに直接送信します。ライブ設定のため、ドラフトの一部ではなく、公開する必要はありません。 |

**フィールドのクリア**

これらのフィールドは、`null` を送信する際に `null` に設定するのではなく削除されるため、ボットはデフォルト値（`instagram_post_ids`、`facebook_post_ids`、`instagram_comment_delay_minutes`、`facebook_comment_delay_minutes`、`public_comment_reply_instructions`、`follower_outreach_instructions`、`first_response_exact_text`、`first_response_exact_text_variants`、`public_comment_reply_exact_text`、`public_comment_reply_exact_text_variants`）にフォールバックします。

> **不明なキーが1つでもあると、リクエスト全体が拒否されます。** `PUT /campaigns/{campaignId}` は、許可リストに基づいてリクエストボディ全体を検証します。認識されないキーが含まれている場合、リクエスト全体に対して `400` が返されます。暗黙的に無視されることはなく、そのボディ内の他のフィールドも書き込まれません。

**cURL**

```bash
curl -X PUT "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "Live",
    "monitor_instagram_posts": true,
    "instagram_comment_delay_minutes": 2,
    "first_response_mode": "exact_text",
    "first_response_exact_text": "Hey! Sending the details over now.",
    "first_response_exact_text_variants": [
      "Hi there, here are the details you asked for.",
      "Thanks for commenting, here is what you need."
    ],
    "public_comment_reply_exact_text": "Just sent you a DM."
  }'
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo",
  {
    method: "PUT",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      status: "Live",
      monitor_instagram_posts: true,
      instagram_comment_delay_minutes: 2,
      first_response_mode: "ai",
      public_comment_reply_instructions:
        "Tell them to check their message requests folder too.",
    }),
  }
);
const data = await res.json();
```

**Python**

```python
import requests

res = requests.put(
    "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "status": "Live",
        "monitor_facebook_posts": True,
        "facebook_post_ids": None,
        "facebook_comment_delay_minutes": 5,
    },
)
data = res.json()
```

**レスポンス**

```json
{
  "success": true,
  "campaign_id": "NBCXrhqGPSFsd6MV7pRo"
}
```

> コメントに残す公開返信には、プランの「コメント返信」機能が必要です。この機能がない場合、DMは送信されますが、公開返信はスキップされます。

---

## AIでキャンペーンを最適化する

`POST /campaigns/{campaignId}/optimize`

ダッシュボードの「最適化」および低評価フィードバックフローと同じAIリライトを実行します。フィードバックを受け取り、ボットの指示を書き換え、その結果をレビュー用の新しいドラフトリビジョンとしてステージングします。

| フィールド | 必須 | 説明 |
|---|---|---|
| `user_feedback` | この2つのうちいずれか1つが必須 | 改善点を説明する自由形式のフィードバック。 |
| `thumbs_down_feedback` | この2つのうちいずれか1つが必須 | ボットの特定の回答に対する低評価から取得されたフィードバック。 |
| `thumbs_down_message` | いいえ | 低評価フィードバックが参照するボットメッセージ。 |

```bash
curl -X POST "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/optimize?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "user_feedback": "Make the tone more casual and mention the free trial earlier." }'
```

**レスポンス** (`202` — リライトはバックグラウンドで実行されます)

```json
{ "success": true, "campaign_id": "NBCXrhqGPSFsd6MV7pRo" }
```

[`GET /campaigns/{campaignId}`](#get-a-campaign)をポーリングして`test_bot.status`を監視します。すぐに`"Optimizing"`に切り替わり、リライトが`test_bot`に反映されると`"Draft"`に戻ります。その後は通常のダッシュボードドラフトと同様に動作します。レビューを行い、ダッシュボードで公開して有効化してください。`409`は、このキャンペーンに対してすでに最適化が実行中であることを意味します。

> 最適化には、アカウント上の他のAI操作と同様にクレジットが消費されます。

---

## 連絡先をキャンペーンに割り当てる

`POST /campaigns/{campaignId}/contacts/{contactId}/assign`

既存の連絡先をキャンペーンに追加します。また、必要に応じてキャンペーンの開始メッセージをすぐに送信することもできます。これは、キャンペーンで承認されたWhatsAppテンプレートを1人の連絡先に送信する方法です。キャンペーンで承認されたテンプレートはそのキャンペーンに属しているため、[Templates API](templates.md)ライブラリには表示されず、`/whatsapp-templates/send`を通じて送信することはできません。

| フィールド | 必須 | 説明 |
|---|---|---|
| `sendOpeningMessage` | いいえ | `true`は、連絡先が割り当てられるとすぐにキャンペーンの開始メッセージ（WhatsAppキャンペーンで承認されたWhatsAppテンプレート）を送信します。デフォルトは`false`です。 |
| `triggerAIResponse` | いいえ | `true`は、代わりにAIが独自の最初のメッセージを作成できるようにします。デフォルトは`false`です。 |

```bash
curl -X POST "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/contacts/contact_abc123/assign?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "sendOpeningMessage": true }'
```

**レスポンス**

```json
{
  "success": true,
  "data": { "contactId": "contact_abc123", "campaignId": "NBCXrhqGPSFsd6MV7pRo" }
}
```

> **クレジット:** WhatsAppキャンペーンで開始メッセージを送信すると、テンプレート送信と同様に課金され、受信者の国とテンプレートのカテゴリに基づいて価格が決定されます。他のチャネルでは、開始メッセージは通常の送信メッセージとして扱われます。

---

## キャンペーンを受信チャネルにルーティングする

これらのエンドポイントは、チャネル上の新規かつ未知の連絡先にどのキャンペーンが応答するかを管理します。新しい統合には**エントリーポイント**の使用を推奨します（[キャンペーンタイプ](#campaign-types)の注記を参照）。これらは、古い方法でルーティングされるキャンペーンを操作する場合や、2つの受信キャンペーン間でのチャネル所有権の競合を解決する場合に引き続き役立ちます。

### キャンペーンを受信チャネルに割り当てる

`POST /campaigns/{campaignId}/incoming-routing`

| フィールド | 必須 | 説明 |
|---|---|---|
| `channels` | はい | このキャンペーンが新規かつ未知の連絡先に対して応答すべきチャネルの配列。 |

```bash
curl -X POST "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/incoming-routing?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "channels": ["whatsapp", "instagram"] }'
```

**レスポンス**

```json
{
  "success": true,
  "uid": "abc123",
  "campaignId": "NBCXrhqGPSFsd6MV7pRo",
  "channels": ["whatsapp", "instagram"],
  "failed": []
}
```

`channels`には実際にこのキャンペーンにルーティングされたチャネルのみがリストされ、`failed`にはルーティングされなかったチャネルがリストされます。要求されたすべてのチャネルで失敗した場合、リクエスト自体が失敗します。

### キャンペーンの受信ルーティングをクリアする

`DELETE /campaigns/{campaignId}/incoming-routing`

| フィールド | 必須 | 説明 |
|---|---|---|
| `channelToUnassign` | いいえ | この1つのチャネルのみのルーティングをクリアします。省略した場合は、このキャンペーンが現在応答しているすべてのチャネルをクリアします。 |

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/incoming-routing?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "channelToUnassign": "instagram" }'
```

**レスポンス**

```json
{
  "success": true,
  "uid": "abc123",
  "campaignId": "NBCXrhqGPSFsd6MV7pRo",
  "channelsRemoved": ["instagram"]
}
```

### 休止中のキャンペーンを再アクティブ化する

`POST /campaigns/{campaignId}/reactivate`

キャンペーンを `Ended`、`Completed`、`Paused`、または `Draft` から復帰させ、そのチャネルを再取得します。`Incoming from Unknown Contacts` または `Combined` キャンペーンでのみ機能します。すでに `Live` 状態のキャンペーンは成功とみなされ、何も行われません。

```bash
curl -X POST "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/reactivate?apiKey=YOUR_API_KEY"
```

**レスポンス**

```json
{
  "success": true,
  "data": {
    "success": true,
    "channelsReactivated": ["whatsapp"],
    "channelsBlockedByConflict": [],
    "campaignType": "Incoming from Unknown Contacts"
  }
}
```

別のキャンペーンのエージェントによってすでに取得されているチャネルは、呼び出し全体を失敗させるのではなく `channelsBlockedByConflict` に表示されます。このキャンペーンでチャネルを引き継ぎたい場合は、まず以下の [競合する着信キャンペーンを停止する](#stop-a-conflicting-incoming-campaign) を使用してチャネルを解放してください。再アクティブ化をサポートしていないキャンペーンタイプや、上記の休止状態以外のステータスに対しては `400` が返されます。

### 競合する着信キャンペーンを停止する

`POST /campaigns/{campaignId}/stop-incoming`

このキャンペーンのチャネルを、現在それらを保持している「他の」キャンペーンから解放し、このキャンペーンが次にそれらを取得できるようにします。これは、誰かがすでに応答しているチャネルに対して着信キャンペーンを開始したときに、ダッシュボードが自動的に行う処理の REST バージョンです。

```bash
curl -X POST "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/stop-incoming?apiKey=YOUR_API_KEY"
```

**レスポンス**

```json
{
  "success": true,
  "campaign_id": "NBCXrhqGPSFsd6MV7pRo",
  "ended_campaign_ids": [],
  "released_channels": ["whatsapp"],
  "cleared_entire_field": false
}
```

このキャンペーンが広告するすべてのチャネルをすでに所有している場合、`released_channels` は空で返されます。引き継ぐべきものはありません。

---

## 費用見積もり

キャンペーンを開始する前に、その費用を見積もります。

### WhatsApp テンプレートの費用見積もり

`GET /campaigns/{campaignId}/template-cost-estimate`

```bash
curl "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/template-cost-estimate?apiKey=YOUR_API_KEY"
```

**レスポンス**

```json
{
  "success": true,
  "billing_mode": "credits",
  "data": {
    "countries": [
      {
        "countryCode": "1",
        "name": "United States",
        "iso": "US",
        "flag": "🇺🇸",
        "contactCount": 120,
        "costPerContact": 2,
        "subtotal": 240
      }
    ],
    "totalContacts": 120,
    "totalTemplateCost": 240,
    "templateCategory": "marketing",
    "billing_mode": "credits",
    "service_messages_billable_soon": false
  }
}
```

`billing_mode` は管理対象の WhatsApp レーンでは `"credits"` です。Meta がお客様自身の WhatsApp Business アカウントに直接請求するレーンでは、`costPerContact`、`subtotal`、および `totalTemplateCost` は `null` として返されます。報告すべきクレジット数値がないため、無料と解釈される `0` になることはありません。

### SMS の費用見積もり

`GET /campaigns/{campaignId}/sms-cost-estimate`

```bash
curl "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/sms-cost-estimate?apiKey=YOUR_API_KEY"
```

**レスポンス**

```json
{
  "success": true,
  "billing_mode": "twilio_direct",
  "data": {
    "totalContacts": 120,
    "messageLength": 87,
    "segmentsPerMessage": 1,
    "totalSegments": 120,
    "estimatedCostUsd": 0.96,
    "priceUnit": "USD per segment",
    "billedByTwilio": true
  }
}
```

SMS は常に独自の Twilio アカウントを通じて送信されるため（[SMS プロバイダー](../settings/sms-provider.md) を参照）、常に Twilio から直接請求されます。`estimatedCostUsd` はその Twilio 請求額の見積もりであり、クレジット料金ではありません。

---

## 制限チェック

送信失敗で気づくのではなく、配信を開始する前に制限を確認します。

### キャンペーン単位のチェック

`GET /campaigns/{campaignId}/limits/ai-credit-messaging` — このキャンペーンを開始またはスケジュールすることで、アカウントのAIクレジットによるメッセージ送信制限を超えるかどうか。

`GET /campaigns/{campaignId}/limits/messaging` — アカウントの1日あたりのメッセージ送信制限を超えるかどうか。

```bash
curl "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/limits/messaging?apiKey=YOUR_API_KEY"
```

**レスポンス** (制限を超えていない場合)

```json
{
  "success": true,
  "data": "Campaign is within the daily messaging limit."
}
```

制限を超える場合は代わりに `400` が返され、その理由が `error` に示されます。

### アカウント単位のチェック

`GET /campaigns/limits/campaigns` — サブスクリプションの月間キャンペーン作成制限に達しているかどうか。

`GET /campaigns/limits/contacts` — サブスクリプションの連絡先制限に達しているかどうか。

```bash
curl "https://api.youraiconnector.com/v1/campaigns/limits/campaigns?apiKey=YOUR_API_KEY"
```

**レスポンス**

```json
{
  "success": true,
  "data": "You can create 3 more campaigns this month."
}
```

---

## キャンペーン統計の合計

`GET /campaigns/stats/totals`

アカウント内のすべてのキャンペーンおよびすべてのAIエージェントについて、直近の期間における送信数と返信数の合計を取得します。これはキャンペーン一覧ページで各行の横に表示される数値と同じもので、キャンペーンごとにリクエストを送るのではなく、1回の呼び出しで取得できます。

| クエリパラメータ | 説明 |
|---|---|
| `days` | 直近の期間（日数）、1〜365。デフォルトは90。 |

```bash
curl "https://api.youraiconnector.com/v1/campaigns/stats/totals?days=30&apiKey=YOUR_API_KEY"
```

**レスポンス**

```json
{
  "success": true,
  "byCampaign": {
    "NBCXrhqGPSFsd6MV7pRo": { "sent": 1204, "replied": 318 }
  },
  "byAgent": {
    "agent_abc123": { "sent": 1204, "replied": 318 }
  },
  "windowDays": 30
}
```

`byAgent` はそれ自体が集計結果であり、`byCampaign` の合計ではありません。AIエージェント専用アカウントのトラフィックにはキャンペーンが紐付かない場合があるため、その場合はここに含まれなくなってしまいます。

---

## プレイグラウンドでキャンペーンをテストする

プレイグラウンドでは、実際のチャネルや連絡先に触れることなく、キャンペーンのボットと会話を行うことができます。これはダッシュボードの試用パネルと同じサンドボックスであり、API経由で完全に利用可能です。

フローは次の通りです：非表示のテスト用連絡先を作成し、メッセージを送信し、ボットの返信をキャンペーンにポーリングします。返信は非同期で生成されるため、レスポンスボディではなく、キャンペーンの `test_messages` に到着します。

> **Playgroundの利用にはAPIコストクレジットが消費されます。** APIキーを使用して開始されたテスト会話は、実際の返信と同様に通常のAIメッセージ料金が課金され、利用履歴に通常の項目として表示されます。ダッシュボードからのテストは無料のままです。この違いは意図的なものです。テスト実行もライブ実行と同じAI処理を行うため、API Playgroundを無制限に利用できるようにすると、他人の費用で無制限にAIを実行できてしまうことになるからです。

### ステップ 1 - テスト用連絡先を作成する

`POST /campaigns/{campaignId}/try-out/contact`

非表示のテスト用連絡先を作成し、キャンペーンにリンクします。すべての本文フィールドは任意です。省略した項目は、組み込みのサンプルID（John Doe）が使用されます。

| フィールド | 必須 | 説明 |
|---|---|---|
| `first_name` | いいえ | テスト用連絡先の名。 |
| `last_name` | いいえ | テスト用連絡先の姓。 |
| `email` | いいえ | テスト用連絡先のメールアドレス。 |
| `phone` | いいえ | テスト用連絡先の電話番号。 |

```bash
curl -X POST "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/try-out/contact?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "first_name": "Maria", "last_name": "Lopez" }'
```

**レスポンス**

```json
{
  "success": true,
  "contactId": "8kQx1vNbA2fLpR7d"
}
```

### ステップ 2 - 受信メッセージを記録する

`POST /campaigns/{campaignId}/try-out/messages`

テストスレッドにメッセージを追加します。ボットが読み取る会話履歴に表示されるよう、まずは訪問者のメッセージをここに送信してください。

| フィールド | 必須 | 説明 |
|---|---|---|
| `messages` | はい | メッセージオブジェクトの配列（1リクエストにつき最大200件）。 |
| `messages[].body` | はい | メッセージのテキスト。 |
| `messages[].direction` | はい | 訪問者の場合は `"inbound"`、ボットの場合は `"outbound"`。 |
| `messages[].timestamp` | いいえ | ISO-8601形式の文字列またはエポックミリ秒。 |
| `messages[].role` | いいえ | オプションのロールラベル。 |
| `messages[].name` | No | オプションの表示名。 |
| `ignoreCounter` | いいえ | 整数。同じ書き込みでキャンペーンの無視カウンターをリセットします。 |

```bash
curl -X POST "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/try-out/messages?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      {
        "body": "Do you ship to Belgium?",
        "direction": "inbound",
        "timestamp": "2026-07-22T09:30:00Z"
      }
    ]
  }'
```

**レスポンス**

```json
{
  "success": true,
  "campaign_id": "NBCXrhqGPSFsd6MV7pRo",
  "appended": 1
}
```

### ステップ 3 - ボットに返信させる

`POST /campaigns/{campaignId}/try-out/test-message`

メッセージをAIパイプラインに送信します。この呼び出しによって、実際にボットの応答が生成されます。

| フィールド | 必須 | 説明 |
|---|---|---|
| `message` | はい | 訪問者の最新のメッセージテキスト。 |

```bash
curl -X POST "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/try-out/test-message?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "message": "Do you ship to Belgium?" }'
```

**レスポンス**

```json
{
  "success": true,
  "data": "Published"
}
```

`"Published"` はメッセージがAIパイプラインに送信されたことを意味します。`"Ignored"` は、より新しいテストメッセージがこのメッセージに取って代わったことを意味します。プレイグラウンドでは、実際の会話で相手が入力し終えるのを待つのと同様に、最後のメッセージから約4秒後に、連続したメッセージを1つの返信にまとめます。この折りたたみウィンドウがあるため、この呼び出しが完了するまで数秒かかります。

### ステップ 4 - 返信を読み取る

`GET /campaigns/{campaignId}`

ボットの返信は、キャンペーンの `test_messages` 配列に追加されます。新しい `outbound` エントリが表示されるまでキャンペーンをポーリングしてください。

```json
{
  "success": true,
  "campaign": {
    "id": "NBCXrhqGPSFsd6MV7pRo",
    "test_messages": [
      { "body": "Do you ship to Belgium?", "direction": "inbound" },
      { "body": "Yes, we ship across the EU.", "direction": "outbound" }
    ]
  }
}
```

### プレイグラウンドをリセットする

`POST /campaigns/{campaignId}/try-out/reset`

サンドボックス全体をクリアします。テスト用連絡先を削除し、`test_messages` をワイプし、ボットの応答ロックを解除します。テスト実行の合間に使用してください。

```bash
curl -X POST "https://api.youraiconnector.com/v1/campaigns/NBCXrhqGPSFsd6MV7pRo/try-out/reset?apiKey=YOUR_API_KEY"
```

**レスポンス**

```json
{
  "success": true,
  "campaign_id": "NBCXrhqGPSFsd6MV7pRo"
}
```

### その他のプレイグラウンドエンドポイント

| エンドポイント | 説明 |
|---|---|
| `DELETE /campaigns/{campaignId}/try-out/contact` | 現在のテスト用連絡先のみを削除してリンクを解除します。`test_messages` はそのまま残ります。連絡先がリンクされていない場合でも成功します。 |
| `POST /campaigns/{campaignId}/try-out/transfer` | 既存の会話をシードとして使用し、1回のリクエストで新しいプレイグラウンドを開始します。テスト用連絡先を置き換え、`test_messages` を上書きします。ボディには `first_name`、`last_name`、`messages`（空でも可）、および `ignoreCounter` を指定します。削除、作成、追加を個別に行うとレート制限の消費量が3倍になるため、こちらを優先してください。 |
| `POST /campaigns/{campaignId}/try-out/messages/replace` | `test_messages` を追加ではなく全体的に上書きします。スレッドの切り詰めや巻き戻しに使用してください。 |
| `POST /campaigns/{campaignId}/try-out/contact/reset-ignore-counter` | テスト用連絡先の無視カウンターのみをリセットします。送信後のやり直しや繰り返しフローに使用します。 |

---

## キャンペーンAPIエラー

キャンペーンエンドポイントは、標準のエラーエンベロープを返します：

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

| ステータス | キャンペーンエンドポイントで発生する場合 |
|---|---|
| `400` | 必須フィールドが欠落しているか、無効です（例: 不正な `type`、非ブール値の `enabled`、または不明な曜日のキー）。また、制限を超過する場合の [制限チェック](#limit-checks) エンドポイントや、サポートされていないキャンペーンタイプまたはステータスに対する [再アクティブ化](#reactivate-a-dormant-campaign) によって返されます。 |
| `404` | キャンペーンが見つかりませんでした。存在しないか、別のアカウントに属しています。 |
| `409` | このキャンペーンに対して [最適化](#optimize-a-campaign-with-ai) が既に実行されています。 |

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

---

## 関連情報

- [チャネルをキャンペーンにルーティングする](channels.md#route-a-channel-to-a-campaign) — エントリポイントを使用して、Instagram、WhatsApp、またはその他のチャネルを、それに応答すべきAIエージェントに向けます。
- [AIでフォローアップテンプレートを生成する](templates.md#generate-follow-up-templates-with-ai) — キャンペーンのWhatsAppフォローアップテンプレートを作成するバックグラウンドジョブを開始します。
- [FAQs API](faqs.md) — キャンペーンで使用する質問と回答のエントリを管理します。
- [APIアクセス](../integrations/api-access.md) — APIキーを生成します。
- [認証](authentication.md) — キーを渡すためのすべての方法です。
