
# API kampanii

Kampania łączy w sobie wszystko, czego bot AI potrzebuje do rozmowy z Twoimi kontaktami: instrukcje, kanały, na których działa, godziny aktywności oraz zachowanie w ramach działań następczych. API kampanii umożliwia wyświetlanie, tworzenie, aktualizowanie, duplikowanie, włączanie, archiwizowanie i dostrajanie kampanii bezpośrednio z poziomu Twojego kodu, zamiast korzystać z pulpitu nawigacyjnego.

Wszystkie poniższe punkty końcowe są relatywne względem bazowego adresu URL `https://api.youraiconnector.com/v1`. Każde żądanie musi być uwierzytelnione — zobacz [Dostęp do API](../integrations/api-access.md) oraz [Uwierzytelnianie](authentication.md), aby dowiedzieć się, jak uzyskać i przekazać klucz API. Dostęp do API jest funkcją płatną; bez niego żądania są odrzucane z błędem `403`.

> **Uwaga:** Niektóre przykłady pokazują prosty formularz zapytań `?apiKey=YOUR_API_KEY`, inne używają nagłówka `X-API-Key`. Oba działają wszędzie — użyj tego, który lepiej pasuje do Twojej konfiguracji.

---

## Typy kampanii

Podczas tworzenia kampanii musisz wybrać jeden z poniższych typów:

| Typ | Przeznaczenie |
|---|---|
| `Incoming from Unknown Contacts` | Bot odpowiada osobom, które piszą do Ciebie po raz pierwszy. |
| `Outgoing` | Bot rozpoczyna rozmowy z kontaktami dodanymi do kampanii. |
| `Keywords` | **Nieaktywny – nie używaj.** Kampania typu `Keywords` jest nieaktywna: jest nadal akceptowana ze względu na wsteczną kompatybilność, ale jest niewidoczna dla routingu przychodzącego na każdym kanale i żadne słowa kluczowe wyzwalające nie są przez nią odczytywane. Zamiast tego użyj punktu wejścia (Entry Point) typu **Słowo kluczowe** (Keyword) w agencie AI. |
| `Combined` | Mieszanka zachowań przychodzących i wychodzących. |

**Wielkość liter nie ma znaczenia.** `type`, `status`, `booking_provider`, `first_response_mode`, `bot.anthropic_model` oraz `bot.ai_speed` akceptują dowolną wielkość liter — `"live"`, `"Live"` oraz `"LIVE"` oznaczają to samo — a wartość jest przechowywana w swojej kanonicznej formie, która jest zwracana podczas odczytu kampanii. Jedynym wyjątkiem jest para wstrzymania: `"Paused"` oraz `"paused"` to dwa faktycznie różne stany, więc niejednoznaczna pisownia, taka jak `"PAUSED"`, jest odrzucana z błędem `400`, informującym o konieczności wyboru jednej z nich.

### Dwa stany wstrzymania

| Status | Kto go ustawia | Co oznacza |
|---|---|---|
| `Paused` | Własne mechanizmy bezpieczeństwa platformy (niskie zaangażowanie, powtarzające się błędy wysyłania, osiągnięcie limitu) oraz nowsze interfejsy Agentów i Transmisji | Kampania jest wstrzymana. Zaplanowane sprawdzenie może automatycznie cofnąć wstrzymanie bezpieczeństwa, gdy przyczyna ustąpi. |
| `paused` | Przycisk Wstrzymaj na pulpicie nawigacyjnym, w parze z `resumed` przy Wznów | Osoba wstrzymała kampanię ręcznie. Zaplanowane wysyłki są usuwane i tworzone ponownie po wznowieniu. |

Oba stany zatrzymują kampanię: routing przychodzący działa tylko wtedy, gdy status jest dokładnie równy `Live`. **Z poziomu API użyj `Paused`, aby wstrzymać, oraz `Live`, aby wznowić** — para pisana małymi literami istnieje dla przycisku na pulpicie nawigacyjnym i jest utrzymywana w celu jego poprawnego działania.

Żaden z tych stanów nie jest tym, co dzieje się, gdy AI przestaje odpowiadać w ramach jednej rozmowy. Jest to przełącznik dla konkretnego kontaktu, `is_bot_active` przy kontakcie — ustawiany, gdy kontrolę przejmuje człowiek, gdy kontakt rezygnuje z subskrypcji lub gdy AI kończy czat. Status samej kampanii pozostaje nienaruszony, a wszystkie inne rozmowy w jej ramach działają dalej. Zobacz [wstrzymywanie lub wznawianie AI dla jednego kontaktu](messages.md#pause-or-resume-the-ai-for-one-contact).

> **Utworzenie kampanii nie decyduje o tym, kto odpowiada na kanale.** Routing jest obsługiwany przez **punkty wejścia** (Entry Points) w agencie AI, a nie przez kampanie. Każdy kanał ma jeden domyślny punkt wejścia wskazujący agenta, który odpowiada na nowe, nieznane kontakty: ustaw go za pomocą `PUT /entry-points/channel-defaults`, sprawdź, czy drabinka jest aktywna dla konta za pomocą `GET /entry-points/routing-status`, wyczyść go za pomocą `DELETE /entry-points/channel-defaults`. `POST /channels/campaign` nadal zapisuje starszą mapę routingu kampanii dla poszczególnych kanałów, ale mapa ta nie jest już używana do routingu przychodzącego na żadnym koncie; jest zachowana wyłącznie w celu wycofania zmian. Nie opieraj na niej żadnych rozwiązań. Zobacz [Skieruj kanał do kampanii](channels.md#route-a-channel-to-a-campaign), aby porównać oba podejścia.

---

## Wyświetlanie kampanii

`GET /campaigns`

Zwraca Twoje kampanie, zaczynając od najnowszych. Zarchiwizowane kampanie są wykluczone, chyba że przekażesz `archived=true`.

**Parametry zapytania**

| Parametr | Wymagany | Opis |
|---|---|---|
| `limit` | Nie | Maksymalna liczba zwracanych kampanii. Domyślnie `50`, maksimum `100`. |
| `cursor` | Nie | Kursor stronicowania. Przekaż wartość `next_cursor` z poprzedniej odpowiedzi, aby pobrać następną stronę. |
| `archived` | Nie | Ustaw na `true`, aby uwzględnić zarchiwizowane kampanie. |

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

**Odpowiedź**

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

Gdy `next_cursor` ma wartość `null`, oznacza to, że dotarłeś do ostatniej strony.

---

## Pobierz kampanię

`GET /campaigns/{campaignId}`

Zwraca pełny dokument kampanii, w tym konfigurację aktywnego bota (`bot`), ustawienia działań następczych, włączone kanały oraz wszelkie słowa kluczowe. Sygnatury czasowe są zwracane w milisekundach czasu epoch.

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

**Odpowiedź**

```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
**Uwaga:** Kampania należąca do innego konta zwraca `404 Campaign not found` (nie `403`), więc nie można stwierdzić, czy dany identyfikator istnieje na innym koncie.
:::


---

## Utwórz kampanię

`POST /campaigns`

Tworzy nową kampanię. `name` oraz `type` są wymagane; wszystko inne jest opcjonalne. Możesz dołączyć dowolne inne pole kampanii w tym samym żądaniu — na przykład `language`, `ai_mode` lub pełny obiekt konfiguracji `bot` — a zostanie ono zapisane wraz z nową kampanią. Właściciel i czas utworzenia są ustawiane automatycznie.

**Pola żądania**

| Pole | Wymagane | Opis |
|---|---|---|
| `name` | Tak | Nazwa kampanii. |
| `type` | Tak | Jeden z czterech powyższych typów kampanii. |
| `language` | Nie | Język, w którym odpowiada bot (np. `"en"`). |
| `ai_mode` | Nie | Czy tryb AI jest włączony (`true`/`false`). W przypadku kampanii obsługiwanej przez agenta AI, odczyty zwracają przełącznik **Aktywny** agenta, a nie zapisaną wartość — zobacz uwagę poniżej dotyczącą aktualizacji. |
| `bot` | Nie | Obiekt konfiguracji bota (zobacz [Pola konfiguracji bota](#bot-configuration-fields)). |
| `list_id` | Nie | ID listy kontaktów do dołączenia. |
| `event_id` | Nie | ID typu wydarzenia, które AI może zarezerwować. |
| `event_ids` | Nie | Kilka typów wydarzeń jednocześnie, jako tablica ID typów wydarzeń — pierwszy z nich jest domyślny. Wyślij `event_id` lub `event_ids`, nie oba jednocześnie. |

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

**Odpowiedź**

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

---

## Aktualizacja kampanii

`PUT /campaigns/{campaignId}`

Częściowo aktualizuje kampanię — wyślij tylko te pola, które chcesz zmienić. Jest to jedyna ogólna metoda aktualizacji; nie istnieje `PATCH /campaigns/{campaignId}` (dwie trasy `PATCH` to wąskie przełączniki [włącz](#enable-or-disable-a-campaign) i [archiwizuj](#archive-or-restore-a-campaign)).

**Pola, które możesz zmienić.** Wszystko, co zapisuje edytor kampanii, w tym `name`, `status`, `type`, `language`, `ai_mode`, `enabled_channels`, ustawienia wyzwalacza i sekwencji (drip), flagi rezerwacji i działań następczych, pola monitorowania Instagrama/Facebooka oraz cała konfiguracja `bot`. Tożsamość i własność są zablokowane na czas trwania kampanii: `user`, `id` oraz `created_at` są odrzucane, podobnie jak każda nazwa pola, której punkt końcowy nie rozpoznaje. Odrzucenie dotyczy całego żądania, a nie poszczególnych pól — jeden nieznany klucz zwraca `400` i **nic** w tym żądaniu nie zostaje zapisane.

**`ai_mode` w kampanii obsługiwanej przez agenta odzwierciedla stan agenta.** Gdy na kampanię odpowiada agent AI, odczyt kampanii zwraca `ai_mode` pochodzące z przełącznika **Aktywny** tego agenta — jest to jedyny przełącznik, który faktycznie decyduje o tym, czy AI odpowiada. Zapisanie `ai_mode` w takiej kampanii jest akceptowane, ale nie zmieni wartości zwracanej przy odczycie; zamiast tego należy włączyć lub wyłączyć przełącznik Aktywny agenta (w panelu nawigacyjnym lub za pośrednictwem API agentów). W klasycznych kampaniach bez agenta, `ai_mode` odczytuje i zapisuje przechowywaną wartość tak jak dotychczas.

**Pola bota są scalane, a nie nadpisywane.** Wysyłaj ustawienia bota jako klucze kropkowe (`"bot.instructions": "..."`) lub jako zagnieżdżony obiekt (`"bot": { "instructions": "..." }`) — oba sposoby zapisują dane element po elemencie, więc pola, których nie wyślesz, zachowują swoje bieżące wartości. `bot.instructions`, `bot.goal`, `bot.rules` oraz `bot.personality` można edytować w ten sposób, podobnie jak każde inne ustawienie bota wymienione w sekcji [Pola konfiguracji bota](#bot-configuration-fields). To samo dotyczy `test_bot`, `frequency` oraz `follow_up_config`.

Aby całkowicie zastąpić konfigurację bota — usuwając każde pole, którego nie wyślesz — użyj `bot_replace` (lub `test_bot_replace`) z pełnym obiektem. Nie można łączyć zastępowania i scalania dla tego samego obiektu w jednym żądaniu; zwraca to `400`.

::: note
**Uwaga:** Zapisywanie `bot.*` przez API odnosi skutek **natychmiast** w aktywnej kampanii. Edytor w panelu działa inaczej: zmiany są tam zapisywane jako wersja robocza i stają się aktywne dopiero po kliknięciu przez klienta przycisku Opublikuj. Jeśli więc klient ma nieopublikowane zmiany w panelu, pozostają one w `test_bot`, a odczyt API `bot` poprawnie pokazuje to, czego AI używa w tej chwili.
:::


Kilka pól ustawia się za pomocą dedykowanego klucza, zamiast zapisywać je bezpośrednio: użyj `list_id` dla listy kontaktów, `event_id` dla typu wydarzenia (lub `event_ids`, uporządkowanej tablicy ID typów wydarzeń, aby pozwolić AI na rezerwację kilku — pierwszy jest domyślny; pusta tablica usuwa powiązania ze wszystkimi), oraz `contact_ids` (tablicy ID kontaktów) dla kontaktów kampanii. Wpisy w bazie wiedzy są zarządzane przez [API FAQ](faqs.md), a nie przez ten punkt końcowy.

**Tagi zastępują, nie scalają.** Wyślij `tags` jako kompletną tablicę, a stanie się ona zestawem tagów kampanii — zobacz [Tagi kampanii](#campaign-tags), aby poznać pola oraz punkty końcowe służące do dodawania lub edycji pojedynczego tagu.

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

**Odpowiedź**

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

---

## Usuwanie kampanii

`DELETE /campaigns/{campaignId}`

Trwale usuwa kampanię. Tej operacji nie można cofnąć — jeśli kampania może być jeszcze potrzebna, [zarchiwizuj ją](#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()
```

**Odpowiedź**

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

---

## Duplikowanie kampanii

`POST /campaigns/{campaignId}/duplicate`

Tworzy kopię kampanii z zachowaniem wszystkich jej ustawień. Kopia jest domyślnie **wyłączona**, a jej nazwa otrzymuje przyrostek `(copy)`, dzięki czemu nie wysyła żadnych wiadomości, dopóki jej wyraźnie nie włączysz.

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

**Odpowiedź**

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

> Zduplikowane kopie **w ramach jednego konta**.

---


## Włączanie lub wyłączanie kampanii

`PATCH /campaigns/{campaignId}/enabled`

Włącza lub wyłącza kampanię. Wyłączona kampania przestaje angażować kontakty, ale zachowuje całą swoją konfigurację.

**Pola żądania**

| Pole | Wymagane | Opis |
|---|---|---|
| `enabled` | Tak | `true` aby włączyć, `false` aby wyłączyć. Musi być wartością logiczną (boolean). |

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

**Odpowiedź**

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

---

## Archiwizowanie lub przywracanie kampanii

`PATCH /campaigns/{campaignId}/archived`

Archiwizuje lub przywraca kampanię. Zarchiwizowane kampanie są ukryte na domyślnej liście kampanii, ale zachowują wszystkie swoje dane i można je przywrócić w dowolnym momencie.

**Pola żądania**

| Pole | Wymagane | Opis |
|---|---|---|
| `archived` | Tak | `true` aby zarchiwizować, `false` aby przywrócić. Musi być wartością logiczną (boolean). |

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

**Odpowiedź**

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

---

## Aktualizacja konfiguracji bota

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

To bezpieczny sposób na zmianę poszczególnych ustawień bota. Każde wysłane pole jest **scalane** z istniejącą konfiguracją bota, więc wszystkie pominięte pola zostają zachowane. Używaj tego zamiast punktu końcowego aktualizacji kampanii, gdy chcesz jedynie zmodyfikować część bota.

Klucze pól mogą zawierać tylko litery, cyfry, podkreślniki i myślniki.

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

**Odpowiedź**

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

### Pola konfiguracji bota

Wszystkie pola bota są opcjonalne. Wyślij tylko te, które chcesz ustawić. Wszelkie dodatkowe pola bota wykraczające poza wymienione tutaj są akceptowane i przechowywane w niezmienionej formie.

| Pole | Typ | Opis |
|---|---|---|
| `instructions` | string | Główne instrukcje sterujące sposobem, w jaki bot rozmawia z kontaktami. |
| `rules` | string | Sztywne zasady, których bot musi zawsze przestrzegać. |
| `goal` | string | Cel, do którego bot powinien dążyć w każdej rozmowie. |
| `personality` | string | Opis tonu głosu i osobowości bota. |
| `ai_speed` | string | Poziom rozumowania stosowany przez AI przed udzieleniem odpowiedzi. Jeden z `fast`, `fast_thinker`, `balanced`, `thorough`. |
| `anthropic_model` | string | Poziom jakości AI używany do odpowiedzi w tej kampanii. Jeden z `standard`, `economy` (przestarzałe), `max`, `mini`. `max` i `mini` działają tylko na kontach uprawnionych do korzystania z tych poziomów. |
| `max_messages` | integer | Maksymalna liczba wiadomości bota w jednej rozmowie. |
| `alert_human_when` | string | Warunki, w których bot powinien powiadomić członka zespołu. |
| `availability` | object | Harmonogram godzin aktywności bota. Możesz ustawić go tutaj lub użyć dedykowanego [punktu końcowego godzin aktywności](#set-the-bot-active-hours). |
| `follow_up_config` | object | Konfiguracja zachowania po zakończeniu rozmowy, przechowywana w podanej formie. |

---

## Ustaw godziny aktywności bota

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

Ustawia harmonogram dostępności bota. Poza skonfigurowanymi oknami czasowymi bot nie odpowiada automatycznie. Zapisuje to pole `availability` w konfiguracji bota.

**Pola żądania**

| Pole | Wymagane | Opis |
|---|---|---|
| `availability` | Tak | Obiekt z kluczami odpowiadającymi dniom tygodnia. Dozwolone klucze to `monday` do `sunday`; każdy inny klucz zwróci `400`. Dni, które pominiesz, pozostaną bez zmian. |

Każdy dzień tygodnia zawiera pojedyncze okno czasowe lub tablicę okien. Okno posiada `start_time` i `end_time` w 24-godzinnym formacie `HH:MM`.

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

**Odpowiedź**

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

---

## Wyświetl listę niestandardowych funkcji kampanii

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

Zwraca funkcje niestandardowe powiązane z tą kampanią, rozwiązane do pełnych definicji. Funkcje niestandardowe to zewnętrzne akcje HTTP, które bot może wywołać podczas rozmowy — na przykład sprawdzenie stanu magazynowego w Twoim sklepie lub utworzenie rekordu w systemie 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"]
```

**Odpowiedź**

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

---

## Powiąż funkcję niestandardową z kampanią

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

Powiązuje istniejącą [funkcję niestandardową](../ai-automation/custom-functions.md) z tą kampanią, aby bot mógł ją wywoływać podczas rozmowy. Powiązanie funkcji, która jest już powiązana, nie powoduje żadnej akcji.

| Pole | Wymagane | Opis |
|---|---|---|
| `custom_function_id` | Tak | Identyfikator funkcji niestandardowej do powiązania. |

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

**Odpowiedź**

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

---

## Odwiąż funkcję niestandardową od kampanii

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

Odwiązanie funkcji, która nie jest powiązana, nie powoduje żadnej akcji.

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

**Odpowiedź**

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

---

## Powiąż źródło bazy wiedzy z kampanią

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

Powiązuje źródło bazy wiedzy (utworzone za pomocą [interfejsu API FAQ](faqs.md)) z tą kampanią, aby bot mógł z niego korzystać podczas udzielania odpowiedzi. Powiązanie źródła, które jest już powiązane, nie powoduje żadnej akcji.

| Pole | Wymagane | Opis |
|---|---|---|
| `kb_source_id` | Tak | Identyfikator źródła bazy wiedzy do powiązania. |

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

**Odpowiedź**

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

---

## Odwiąż źródło bazy wiedzy od kampanii

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

Odwiązanie źródła, które nie jest powiązane, nie powoduje żadnej akcji.

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

**Odpowiedź**

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

---

## Powiąż serwer MCP z kampanią

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

Łączy serwer MCP z tą kampanią, dając botowi dostęp do narzędzi tego serwera podczas rozmowy. Połączenie serwera, który jest już połączony, nie powoduje żadnej akcji.

| Pole | Wymagane | Opis |
|---|---|---|
| `mcp_server_id` | Tak | Identyfikator serwera MCP do połączenia. |

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

**Odpowiedź**

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

---

## Odłącz serwer MCP od kampanii

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

Odłączenie serwera, który nie jest połączony, nie powoduje żadnej akcji.

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

**Odpowiedź**

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

---

## Biblioteka mediów kampanii

Biblioteka mediów przechowuje obrazy, filmy, dokumenty i notatki głosowe, które bot może wysyłać podczas rozmowy.

### Wyświetl bibliotekę mediów kampanii

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

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

**Odpowiedź**

```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` to podpisany adres URL przechwycony w momencie przesyłania — może być już nieważny w momencie odczytu; pulpit nawigacyjny podpisuje go ponownie na żądanie.

### Prześlij element multimedialny

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

| Pole | Wymagane | Opis |
|---|---|---|
| `base64Data` | Tak | Plik zakodowany w formacie base64 (bez prefiksu data-URL). |
| `mimeType` | Tak | Typ MIME pliku (np. `image/png`). |
| `title` | Tak | Krótka etykieta wyświetlana w bibliotece i w monicie AI. |
| `description` | Tak | Instrukcja informująca bota, **kiedy** wysłać ten element. |
| `fileName` | Nie | Oryginalna nazwa pliku, używana do utworzenia nazwy obiektu w pamięci masowej. |
| `sendMessage` | Nie | Preferowane sformułowanie, którego bot powinien użyć podczas wysyłania tego elementu. |
| `maxSendsPerConversation` | Nie | Maksymalna liczba wysłania tego elementu przez bota do jednego kontaktu w ramach rozmowy. Wartość domyślna to `1`. |
| `sendAsVoiceNote` | Nie | W przypadku przesłania dźwięku, przekoduj go na notatkę głosową WhatsApp. Wartość domyślna to `false` (zapisywany jako zwykły plik audio). |

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

**Odpowiedź**

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

### Aktualizacja elementu multimedialnego

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

Edytuje tylko metadane elementu — aby zastąpić sam plik, usuń element i prześlij nowy.

| Pole | Opis |
|---|---|
| `title` | Krótka etykieta. |
| `description` | Instrukcja dotycząca czasu wysyłki. |
| `send_message` | Preferowane sformułowanie, którego ma używać bot. |
| `max_sends_per_conversation` | Nieujemna liczba całkowita lub `null`, aby usunąć limit. |

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

**Odpowiedź**

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

### Usuwanie elementu multimedialnego

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

Usunięcie elementu, który już nie istnieje, jest operacją bez efektu (no-op).

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

**Odpowiedź**

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

---

## Tagi kampanii

Tag kampanii to etykieta, której uczysz bota, aby przypisywał ją do kontaktu podczas rozmowy — `hot-lead`, `not-interested`, `booked-a-call`. Każdy tag składa się z trzech części:

| Pole | Typ | Opis |
|---|---|---|
| `name` | ciąg znaków, wymagane | Sama etykieta. To właśnie ją bot przypisuje do kontaktu i to na jej podstawie dokonujesz późniejszego dopasowania, więc dbaj o to, by była krótka i stała. |
| `description` | ciąg znaków | Instrukcja mówiąca botowi, **kiedy** przypisać ten tag. To ta część wykonuje pracę — "osoba potwierdza dołączenie do społeczności" zostanie użyte, "gorący lead" nie. |
| `webhook` | ciąg znaków | Adres URL, który otrzymuje `POST` w momencie przypisania tagu do kontaktu. Pozostaw puste, jeśli go nie potrzebujesz. |
| `tag_id` | ciąg znaków | Opcjonalne. Łączy ten wpis z istniejącym tagiem na Twoim koncie zamiast tworzyć nowy. Podaj go, jeśli chcesz później odwołać się do tego konkretnego tagu za pomocą poniższych punktów końcowych dla pojedynczych tagów. |

Nazwy tagów muszą być unikalne w ramach kampanii. Bot przypisuje tagi **według nazwy**, więc w przypadku dwóch wpisów o tej samej nazwie wynik nie jest określony.

### Ustaw wszystkie tagi kampanii

`PUT /campaigns/{campaignId}` z tablicą `tags`.

To zastępuje tagi kampanii dokładnie tym, co wyślesz, co jest tym samym, co robi karta Tagi w panelu nawigacyjnym po zapisaniu zmian. **Za każdym razem wysyłaj kompletną tablicę** — tag, który pominiesz, zostanie usunięty. Wysłanie `[]` usuwa je wszystkie.

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

**Odpowiedź**

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

Odczytaj tagi za pomocą [`GET /campaigns/{campaignId}`](#get-a-campaign).

### Dodaj jeden tag

`POST /campaigns/{campaignId}/tags`

Dodaje pojedynczy tag bez konieczności ponownego wysyłania reszty. Użyj tego, gdy dodajesz tagi do zestawu, którego nie utworzyłeś w tym żądaniu.

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

Wysłanie dokładnie tego samego tagu dwukrotnie nie powoduje żadnego efektu za drugim razem. Wysłanie tego samego `tag_id` z inną nazwą lub opisem spowoduje dodanie **drugiego** wpisu zamiast edycji pierwszego — użyj poniższego punktu końcowego, aby edytować istniejący tag.

### Zaktualizuj lub usuń jeden tag

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

Adresują one jeden wpis za pomocą jego `tag_id`, więc działają tylko na tagach, które zostały z nim utworzone. Jeśli tag nie ma `tag_id`, zmień go za pomocą powyższego `PUT /campaigns/{campaignId}` dla całej tablicy.

```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`, którego nie ma w kampanii, zwraca `404` z `"Tag not found in campaign tags"`.

---

## Przełączanie kanałów kampanii

`POST /campaigns/{campaignId}/channels`

Dodaje lub usuwa kanały z tablicy `enabled_channels` kampanii bez konieczności ponownego przesyłania całej tablicy — jest to bezpieczniejsze niż [`PUT /campaigns/{campaignId}`](#update-a-campaign), gdy w tym samym czasie kampanię może edytować ktoś inny.

Wyślij pojedyncze przełączenie lub partię — nie oba w tym samym żądaniu:

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

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

| Pole | Opis |
|---|---|
| `channel` | Jeden kanał do przełączenia. Użyj w parze z `action`. |
| `action` | `"add"` lub `"remove"`. Użyj w parze z `channel`. |
| `add` | Tablica kanałów do dodania. Format wsadowy — użyj zamiast `channel`/`action`. |
| `remove` | Tablica kanałów do usunięcia. Format wsadowy. |

Prawidłowe kanały: `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" }'
```

**Odpowiedź**

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

> To zmienia tylko kanały, w których kampania jest reklamowana — nie decyduje o tym, kto odpowiada na dany kanał. Zobacz [Typy kampanii](#campaign-types) powyżej oraz [Kierowanie kampanii do kanałów przychodzących](#route-a-campaign-to-incoming-channels) poniżej, aby uzyskać więcej informacji.

---

## Komentarz do wiadomości prywatnej (Instagram i Facebook)

Funkcja „Komentarz do wiadomości prywatnej” zamienia komentarz pod Twoim postem w prywatną rozmowę: ktoś dodaje komentarz, bot wysyła mu wiadomość prywatną (DM), a kampania przejmuje dalszą część konwersacji. Jest ona konfigurowana w całości za pomocą obiektu kampanii, więc nie ma w niej żadnych elementów dostępnych wyłącznie w interfejsie użytkownika.

Najpierw połącz stronę na Facebooku — zobacz [Połączenie kanału](channels.md#instagram--messenger-meta). Następnie ustaw poniższe pola za pomocą [`PUT /campaigns/{campaignId}`](#update-a-campaign).

> **Kampania musi być `Live`.** Monitorowanie komentarzy wykrywa tylko te kampanie, których `status` to `Live` (wielkość liter nie ma znaczenia — zobacz [Typy kampanii](#campaign-types)). Każdy inny status wyłącza tę funkcję bez powiadomienia, a wymyślony status, taki jak `"Active"`, jest teraz odrzucany z błędem `400` zamiast zapisywany. Prawidłowe statusy to `Draft`, `Pending Approval`, `Scheduled`, `Live`, `Paused`, `Completed`, `Sent` oraz `Failed`.

**Pola**

| Pole | Typ | Opis |
|---|---|---|
| `monitor_instagram_posts` | boolean | Obserwuj każdy post na Instagramie na połączonej stronie. |
| `instagram_post_ids` | string[] | Obserwuj tylko te posty na Instagramie. Pozostaw puste, gdy `monitor_instagram_posts` jest włączone. |
| `instagram_comment_delay_minutes` | number | Odczekaj tyle minut po komentarzu przed wysłaniem wiadomości DM. |
| `monitor_facebook_posts` | boolean | Obserwuj każdy post na Facebooku na połączonej stronie. |
| `facebook_post_ids` | string[] | Obserwuj tylko te posty na Facebooku. |
| `facebook_comment_delay_minutes` | number | Opóźnienie przed wysłaniem wiadomości DM, w minutach. |
| `public_comment_reply_instructions` | string | Wskazówki dotyczące widocznej odpowiedzi pozostawionej pod samym komentarzem. Zastępuje domyślne sformułowanie „sprawdź swoje wiadomości DM”. |
| `first_response_mode` | string | `"ai"` (domyślnie) generuje pierwszą wiadomość DM i odpowiedź publiczną. `"exact_text"` wysyła Twoje sformułowanie dosłownie, bez generowania przez AI i bez pobierania kredytów. |
| `first_response_exact_text` | string | Dosłowna pierwsza wiadomość DM, używana, gdy `first_response_mode` to `"exact_text"`. Wymagane, aby ten tryb zadziałał. |
| `first_response_exact_text_variants` | string[] | Dodatkowe sformułowania dla pierwszej wiadomości DM. Jedno jest wybierane losowo przy każdej wysyłce, więc powtarzające się wiadomości DM nie są identyczne. |
| `public_comment_reply_exact_text` | string | Dosłowna odpowiedź publiczna w trybie `"exact_text"`. Pozostaw puste, aby pominąć odpowiedź publiczną i wysłać tylko wiadomość DM. |
| `public_comment_reply_exact_text_variants` | string[] | Dodatkowe sformułowania dla odpowiedzi publicznej. |
| `monitor_instagram_followers` | boolean | Traktuj nowego obserwującego jako wyzwalacz i wyślij powitalną wiadomość DM (konta osobiste na Instagramie). |
| `follower_outreach_instructions` | string | Wskazówki dotyczące tej powitalnej wiadomości DM dla nowego obserwującego. |
| `respond_to_instagram_story_replies` | boolean | Czy AI odpowiada na odpowiedzi do Twoich relacji na Instagramie. Domyślnie `true`. Ustaw `false`, aby odpowiedzi do relacji trafiały na czat (z załączoną relacją) bez odpowiedzi AI. Ustawienie na żywo — nie jest częścią wersji roboczej, więc nie wymaga publikacji. |

**Czyszczenie pola**

Te pola są usuwane, a nie ustawiane na `null`, gdy wysyłasz `null`, dzięki czemu bot przywraca ustawienia domyślne: `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`.

> **Jeden nieznany klucz odrzuca całe żądanie.** `PUT /campaigns/{campaignId}` weryfikuje całą treść względem listy dozwolonych elementów. Klucz, który nie zostanie rozpoznany, zwraca `400` dla całego żądania — nie jest on ignorowany bez powiadomienia, a żadne inne pola w tej treści nie zostają zapisane.

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

**Odpowiedź**

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

> Widoczna odpowiedź pozostawiona pod komentarzem wymaga funkcji odpowiedzi na komentarze w Twoim planie. Bez niej wiadomość prywatna nadal jest wysyłana, a odpowiedź publiczna jest pomijana.

---

## Optymalizacja kampanii za pomocą AI

`POST /campaigns/{campaignId}/optimize`

Uruchamia to samo przepisywanie przez AI, co funkcje „Optymalizuj” i przesyłanie opinii po kliknięciu łapki w dół w panelu nawigacyjnym: pobiera Twoją opinię, przepisuje instrukcje bota i przygotowuje wynik jako nową wersję roboczą do sprawdzenia.

| Pole | Wymagane | Opis |
|---|---|---|
| `user_feedback` | Wymagane jedno z dwóch | Dowolna opinia opisująca, co należy poprawić. |
| `thumbs_down_feedback` | Wymagane jedno z dwóch | Opinia zebrana po kliknięciu łapki w dół przy konkretnej odpowiedzi bota. |
| `thumbs_down_message` | Nie | Wiadomość bota, której dotyczy opinia z łapką w dół. |

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

**Odpowiedź** (`202` — przepisywanie odbywa się w tle)

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

Odpytuj [`GET /campaigns/{campaignId}`](#get-a-campaign) i obserwuj `test_bot.status`: zmienia się na `"Optimizing"` natychmiast, a następnie z powrotem na `"Draft"`, gdy wynik przepisywania trafi do `test_bot`. Od tego momentu zachowuje się jak każda wersja robocza w panelu — przejrzyj ją, a następnie opublikuj w panelu, aby zaczęła działać. `409` oznacza, że optymalizacja dla tej kampanii jest już w toku.

> Optymalizacja kosztuje kredyty, tak samo jak każda inna operacja AI na Twoim koncie.

---

## Przypisz kontakt do kampanii

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

Dodaje istniejący kontakt do kampanii i, jeśli o to poprosisz, natychmiast wysyła wiadomość powitalną kampanii. Jest to sposób na wysłanie zatwierdzonego szablonu WhatsApp kampanii do jednego kontaktu: szablon, z którym kampania została zatwierdzona, należy do tej kampanii, więc nie pojawia się w bibliotece [Templates API](templates.md) i nie może zostać wysłany przez `/whatsapp-templates/send`.

| Pole | Wymagane | Opis |
|---|---|---|
| `sendOpeningMessage` | Nie | `true` wysyła wiadomość powitalną kampanii (zatwierdzony szablon WhatsApp w kampanii WhatsApp) natychmiast po przypisaniu kontaktu. Domyślnie `false`. |
| `triggerAIResponse` | Nie | `true` pozwala sztucznej inteligencji na napisanie własnej pierwszej wiadomości. Domyślnie `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 }'
```

**Odpowiedź**

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

> **Kredyty:** Wysłanie wiadomości powitalnej w kampanii WhatsApp jest rozliczane tak samo jak wysyłka szablonu, wyceniane według kraju odbiorcy i kategorii szablonu. W innych kanałach wiadomość powitalna jest zwykłą wiadomością wychodzącą.

---

## Kierowanie kampanii do kanałów przychodzących

Te punkty końcowe zarządzają tym, która kampania odpowiada nowym, nieznanym kontaktom w danym kanale. **Preferuj punkty wejścia (Entry Points)** dla nowych integracji (zobacz notatkę w sekcji [Typy kampanii](#campaign-types)) — pozostają one przydatne do pracy z kampaniami, które korzystają ze starszego sposobu kierowania, oraz do rozwiązywania konfliktów własności kanału między dwiema kampaniami przychodzącymi.

### Przypisywanie kampanii do kanałów przychodzących

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

| Pole | Wymagane | Opis |
|---|---|---|
| `channels` | Tak | Tablica kanałów, które ta kampania powinna obsługiwać dla nowych, nieznanych kontaktów. |

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

**Odpowiedź**

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

`channels` wyświetla tylko te kanały, które faktycznie zostały skierowane do tej kampanii; `failed` wyświetla te, które nie zostały skierowane. Jeśli wszystkie żądane kanały zawiodą, samo żądanie również zakończy się niepowodzeniem.

### Usuwanie kierowania przychodzącego kampanii

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

| Pole | Wymagane | Opis |
|---|---|---|
| `channelToUnassign` | Nie | Usuń kierowanie tylko dla tego jednego kanału. Pomiń, aby usunąć wszystkie kanały, które ta kampania obecnie obsługuje. |

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

**Odpowiedź**

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

### Reaktywacja uśpionej kampanii

`POST /campaigns/{campaignId}/reactivate`

Przywraca kampanię ze stanu `Ended`, `Completed`, `Paused` lub `Draft` i odzyskuje jej kanały. Działa tylko w przypadku kampanii `Incoming from Unknown Contacts` lub `Combined` — kampania, która jest już `Live`, jest traktowana jako zakończona sukcesem i nie wymaga żadnych działań.

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

**Odpowiedź**

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

Kanał zajęty już przez agenta innej kampanii pojawi się w `channelsBlockedByConflict` zamiast powodować niepowodzenie całego wywołania — użyj [zatrzymania kolidującej kampanii przychodzącej](#stop-a-conflicting-incoming-campaign) poniżej, aby najpierw go zwolnić, jeśli chcesz, aby ta kampania go przejęła. Zwracany jest `400` dla typu kampanii, który nie obsługuje reaktywacji, lub statusu, który nie jest jednym z powyższych stanów uśpienia.

### Zatrzymaj kolidującą kampanię przychodzącą

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

Zwalnia kanały tej kampanii z INNEJ kampanii, która obecnie je zajmuje, dzięki czemu ta kampania może je przejąć jako następna. Jest to wersja REST tego, co pulpit nawigacyjny robi automatycznie, gdy uruchamiasz kampanię przychodzącą w kanale, który ktoś inny już obsługuje.

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

**Odpowiedź**

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

`released_channels` zwraca pustą wartość, gdy ta kampania posiada już wszystkie kanały, które reklamuje — nie ma nic do przejęcia.

---

## Szacunkowe koszty

Oszacuj koszt uruchomienia kampanii przed jej wysłaniem.

### Szacunkowy koszt szablonu WhatsApp

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

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

**Odpowiedź**

```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` wynosi `"credits"` w zarządzanym kanale WhatsApp. W kanale, w którym Meta obciąża bezpośrednio Twoje własne konto WhatsApp Business, `costPerContact`, `subtotal` oraz `totalTemplateCost` zwracają `null` — nigdy `0`, co byłoby odczytane jako bezpłatne — ponieważ nie ma kwoty kredytu do raportowania.

### Szacunkowy koszt SMS

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

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

**Odpowiedź**

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

Wiadomości SMS są zawsze wysyłane za pośrednictwem Twojego własnego konta Twilio (zobacz [dostawca SMS](../settings/sms-provider.md)), więc są one zawsze rozliczane bezpośrednio przez Twilio — `estimatedCostUsd` to szacunkowa wartość tego rachunku Twilio, a nie opłata kredytowa.

---

## Sprawdzanie limitów

Sprawdź limit przed uruchomieniem, zamiast dowiadywać się o nim po nieudanej wysyłce.

### Sprawdzanie w zakresie kampanii

`GET /campaigns/{campaignId}/limits/ai-credit-messaging` — czy uruchomienie lub zaplanowanie tej kampanii przekroczyłoby limit wiadomości AI-credit Twojego konta.

`GET /campaigns/{campaignId}/limits/messaging` — czy przekroczyłoby to dzienny limit wiadomości Twojego konta.

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

**Odpowiedź** (limit nieprzekroczony)

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

W przypadku przekroczenia limitu zwracany jest `400`, a powód znajduje się w `error`.

### Sprawdzanie w zakresie konta

`GET /campaigns/limits/campaigns` — czy osiągnięto miesięczny limit tworzenia kampanii w ramach subskrypcji.

`GET /campaigns/limits/contacts` — czy osiągnięto limit kontaktów w ramach subskrypcji.

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

**Odpowiedź**

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

---

## Sumy statystyk kampanii

`GET /campaigns/stats/totals`

Suma wysłanych i otrzymanych odpowiedzi dla każdej kampanii ORAZ każdego agenta AI na Twoim koncie w określonym oknie czasowym — te same liczby, które strona listy kampanii pokazuje obok każdego wiersza, dostępne w jednym wywołaniu zamiast jednego żądania na kampanię.

| Parametr zapytania | Opis |
|---|---|
| `days` | Rozmiar okna czasowego, 1-365. Domyślnie 90. |

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

**Odpowiedź**

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

`byAgent` stanowi własne podsumowanie, a nie sumę `byCampaign` — ruch na koncie natywnym dla agenta AI może w ogóle nie dotyczyć żadnej kampanii, więc w przeciwnym razie byłby tutaj niewidoczny.

---

## Testowanie kampanii w środowisku testowym (playground)

Plac zabaw pozwala na prowadzenie rozmowy z botem kampanii bez korzystania z rzeczywistego kanału lub kontaktu. Jest to ten sam piaskownica, co panel testowy w pulpicie nawigacyjnym, i jest w pełni dostępny przez API.

Przebieg jest następujący: utwórz ukryty kontakt testowy, wyślij wiadomość, a następnie odpytaj kampanię o odpowiedź bota. Odpowiedzi są generowane asynchronicznie, więc trafiają do `test_messages` w kampanii, a nie w treści odpowiedzi.

> **Działanie placu zabaw przez API wiąże się z kosztami kredytów.** Rozmowa testowa rozpoczęta przy użyciu klucza API jest rozliczana według standardowej stawki za wiadomość AI, tak samo jak rzeczywista odpowiedź, i pojawia się w historii użycia jako zwykły wpis. Testowanie z poziomu pulpitu nawigacyjnego pozostaje bezpłatne. Różnica jest zamierzona: test wykonuje tę samą pracę AI, co działanie na żywo, więc nielimitowany plac zabaw API byłby sposobem na korzystanie z nieograniczonej liczby operacji AI na koszt kogoś innego.

### Krok 1 - Utwórz kontakt testowy

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

Tworzy ukryty kontakt testowy i łączy go z kampanią. Wszystkie pola treści są opcjonalne; wszystko, co pominiesz, zostanie zastąpione wbudowaną przykładową tożsamością (John Doe).

| Pole | Wymagane | Opis |
|---|---|---|
| `first_name` | Nie | Imię kontaktu testowego. |
| `last_name` | Nie | Nazwisko kontaktu testowego. |
| `email` | Nie | Adres e-mail kontaktu testowego. |
| `phone` | Nie | Numer telefonu kontaktu testowego. |

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

**Odpowiedź**

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

### Krok 2 - Zarejestruj przychodzącą wiadomość

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

Dodaje wiadomości do wątku testowego. Wyślij tutaj najpierw wiadomość odwiedzającego, aby pojawiła się w historii rozmowy, którą czyta bot.

| Pole | Wymagane | Opis |
|---|---|---|
| `messages` | Tak | Tablica obiektów wiadomości, maks. 200 na żądanie. |
| `messages[].body` | Tak | Treść wiadomości. |
| `messages[].direction` | Tak | `"inbound"` dla odwiedzającego, `"outbound"` dla bota. |
| `messages[].timestamp` | Nie | Ciąg znaków ISO-8601 lub milisekundy epoki. |
| `messages[].role` | Nie | Opcjonalna etykieta roli. |
| `messages[].name` | Nie | Opcjonalna nazwa wyświetlana. |
| `ignoreCounter` | Nie | Liczba całkowita. Resetuje licznik ignorowania kampanii w tym samym zapisie. |

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

**Odpowiedź**

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

### Krok 3 - Poproś bota o odpowiedź

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

Wysyła wiadomość do potoku AI. Jest to wywołanie, które faktycznie generuje odpowiedź bota.

| Pole | Wymagane | Opis |
|---|---|---|
| `message` | Tak | Tekst najnowszej wiadomości odwiedzającego. |

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

**Odpowiedź**

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

`"Published"` oznacza, że wiadomość trafiła do potoku AI. `"Ignored"` oznacza, że nowsza wiadomość testowa zastąpiła tę poprzednią — środowisko testowe łączy szybką serię wiadomości w jedną odpowiedź, mniej więcej cztery sekundy po ostatniej wiadomości, podobnie jak w prawdziwej rozmowie czeka się, aż ktoś skończy pisać. Ze względu na to okno łączenia, to wywołanie zwraca wynik po kilku sekundach.

### Krok 4 - Odczytanie odpowiedzi

`GET /campaigns/{campaignId}`

Odpowiedź bota jest dodawana do tablicy `test_messages` kampanii. Odpytuj kampanię, aż pojawi się nowy wpis `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" }
    ]
  }
}
```

### Resetowanie środowiska testowego

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

Czyści całą piaskownicę: usuwa kontakt testowy, czyści `test_messages` i zwalnia blokady odpowiedzi bota. Używaj tego między uruchomieniami testów.

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

**Odpowiedź**

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

### Inne punkty końcowe środowiska testowego

| Punkt końcowy | Co robi |
|---|---|
| `DELETE /campaigns/{campaignId}/try-out/contact` | Usuwa tylko bieżący kontakt testowy i odłącza go, pozostawiając `test_messages` nienaruszone. Działa nawet wtedy, gdy żaden kontakt nie jest powiązany. |
| `POST /campaigns/{campaignId}/try-out/transfer` | Uruchamia nowe środowisko testowe z istniejącą rozmową w jednym żądaniu: zastępuje kontakt testowy i nadpisuje `test_messages`. Treść przyjmuje `first_name`, `last_name`, `messages` (może być puste) oraz `ignoreCounter`. Preferuj to rozwiązanie zamiast usuwania, tworzenia i dodawania, co trzykrotnie zwiększa zużycie limitu zapytań. |
| `POST /campaigns/{campaignId}/try-out/messages/replace` | Nadpisuje `test_messages` w całości zamiast dodawać do niej. Używaj do skracania lub przewijania wątku. |
| `POST /campaigns/{campaignId}/try-out/contact/reset-ignore-counter` | Resetuje tylko licznik ignorowania kontaktu testowego, dla przepływów ponownego wykonania i powtórzeń po wysłaniu. |

---

## Błędy API kampanii

Punkty końcowe kampanii zwracają standardową kopertę błędu:

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

| Status | Kiedy występuje w punkcie końcowym kampanii |
|---|---|
| `400` | Wymagane pole jest brakujące lub nieprawidłowe (na przykład błędny `type`, wartość niebędąca wartością logiczną `enabled` lub nieznany klucz dnia tygodnia). Zwracane również przez punkt końcowy [sprawdzania limitu](#limit-checks), gdy limit zostałby przekroczony, oraz przez [reaktywację](#reactivate-a-dormant-campaign) dla typu lub statusu kampanii, który tego nie obsługuje. |
| `404` | Nie znaleziono kampanii — albo nie istnieje, albo należy do innego konta. |
| `409` | [Optymalizacja](#optimize-a-campaign-with-ai) jest już uruchomiona dla tej kampanii. |

Wspólne kody, które może zwrócić każdy punkt końcowy — `401`, `403` (Twój plan nie obejmuje dostępu do API), `429` (limit szybkości) oraz `500` — zostały wymienione wraz ze wskazówkami dotyczącymi ponawiania prób w sekcji [Błędy i stronicowanie](errors-and-pagination.md).

---

## Powiązane

- [Skieruj kanał do kampanii](channels.md#route-a-channel-to-a-campaign) — przypisz Instagram, WhatsApp lub dowolny inny kanał do Agenta AI, który ma go obsługiwać, korzystając z Punktów Wejścia (Entry Points).
- [Generuj szablony wiadomości uzupełniających za pomocą AI](templates.md#generate-follow-up-templates-with-ai) — uruchom zadanie w tle, które przygotuje szablony wiadomości uzupełniających dla kampanii w WhatsApp.
- [API FAQ](faqs.md) — zarządzaj wpisami pytań i odpowiedzi używanymi w Twoich kampaniach.
- [Dostęp do API](../integrations/api-access.md) — wygeneruj swój klucz API.
- [Uwierzytelnianie](authentication.md) — wszystkie sposoby przekazywania klucza.
