
# Kampanjoiden API

Kampanja kokoaa yhteen kaiken, mitä tekoälybotti tarvitsee keskustellakseen yhteyshenkilöidesi kanssa: sen ohjeet, kanavat, joilla se toimii, sen aktiiviset tunnit ja sen jatkotoimenpiteet. Kampanjoiden API:n avulla voit listata, luoda, päivittää, kopioida, ottaa käyttöön, arkistoida ja hienosäätää kampanjoita omasta koodistasi kojelaudan sijaan.

Kaikki alla olevat päätepisteet ovat suhteessa perus-URL-osoitteeseen `https://api.youraiconnector.com/v1`. Jokainen pyyntö on todennettava — katso [API-käyttöoikeus](../integrations/api-access.md) ja [Todennus](authentication.md) saadaksesi selville, miten hankit ja välität API-avaimesi. API-käyttöoikeus on maksullinen ominaisuus; ilman sitä pyynnöt hylätään virheellä `403`.

> **Huomio:** Jotkin esimerkit näyttävät yksinkertaisen `?apiKey=YOUR_API_KEY`-kyselylomakkeen, toiset käyttävät `X-API-Key`-otsikkoa. Molemmat toimivat kaikkialla — käytä sitä, joka sopii asetuksiisi.

---

## Kampanjatyypit

Kun luot kampanjan, sinun on valittava yksi seuraavista tyypeistä:

| Tyyppi | Käyttötarkoitus |
|---|---|
| `Incoming from Unknown Contacts` | Botti vastaa ihmisille, jotka viestivät sinulle ensimmäistä kertaa. |
| `Outgoing` | Botti aloittaa keskustelut yhteystietojen kanssa, jotka lisäät kampanjaan. |
| `Keywords` | **Passiivinen – älä käytä.** `Keywords`-kampanja on passiivinen: se hyväksytään edelleen taaksepäin yhteensopivuuden vuoksi, mutta se on näkymätön saapuvalle reititykselle kaikissa kanavissa, eikä mikään lue sen käynnistysavainsanoja. Käytä sen sijaan tekoälyagentin **Avainsana**-tyyppistä sisääntulopistettä. |
| `Combined` | Yhdistelmä saapuvaa ja lähtevää toimintaa. |

**Kirjainkoolla ei ole merkitystä.** `type`, `status`, `booking_provider`, `first_response_mode`, `bot.anthropic_model` ja `bot.ai_speed` hyväksyvät kaikki minkä tahansa kirjainkoon — `"live"`, `"Live"` ja `"LIVE"` tarkoittavat samaa asiaa — ja arvo tallennetaan kanonisessa muodossaan, joka palautetaan, kun luet kampanjan. Yksi poikkeus on taukopari: `"Paused"` ja `"paused"` ovat kaksi aidosti eri tilaa, joten epäselvä kirjoitusasu, kuten `"PAUSED"`, hylätään `400`-virheellä, joka kehottaa valitsemaan toisen.

### Kaksi taukotilaa

| Tila | Kuka kirjoittaa | Mitä se tarkoittaa |
|---|---|---|
| `Paused` | Alustan omat turvatarkistukset (vähäinen sitoutuminen, toistuvat lähetysvirheet, rajan ylittyminen) sekä uudemmat Agentit ja Lähetykset-pinnat | Kampanja on pidossa. Ajastettu tarkistus voi poistaa turvatauon automaattisesti, kun syy poistuu. |
| `paused` | Hallintapaneelin Tauko-painike yhdessä `resumed`-painikkeen kanssa Jatka-toiminnossa | Henkilö keskeytti sen manuaalisesti. Ajastetut lähetykset puretaan ja rakennetaan uudelleen jatkamisen yhteydessä. |

Molemmat pysäyttävät kampanjan: saapuva reititys toimii vain, kun tila on täsmälleen `Live`. **Käytä API:sta `Paused`-komentoa tauottamiseen ja `Live`-komentoa jatkamiseen** — pienillä kirjaimilla kirjoitettu pari on olemassa hallintapaneelin painiketta varten ja se pidetään toiminnassa sitä varten.

Kumpikaan näistä ei ole se, mitä tapahtuu, kun tekoäly lakkaa vastaamasta yhden keskustelun sisällä. Se on yhteyskohtainen kytkin, `is_bot_active` yhteystiedossa — asetetaan, kun ihminen ottaa ohjat, kun yhteystieto kieltäytyy tai kun tekoäly päättää keskustelun. Kampanjan oma tila pysyy koskemattomana, ja kaikki muut siinä olevat keskustelut jatkuvat. Katso [tekoälyn tauottaminen tai jatkaminen yhdelle yhteystiedolle](messages.md#pause-or-resume-the-ai-for-one-contact).

> **Kampanjan luominen ei määritä, kuka vastaa kanavaan.** Reititystä hallitaan tekoälyagentin **sisääntulopisteiden** (Entry Points) kautta, ei kampanjoiden. Jokaisella kanavalla on yksi kanavakohtainen oletussisääntulopiste, joka nimeää agentin, joka vastaa uusiin, tuntemattomiin yhteystietoihin: aseta se `PUT /entry-points/channel-defaults`-toiminnolla, tarkista onko tikapuu käytössä tilillä `GET /entry-points/routing-status`-toiminnolla, tyhjennä se `DELETE /entry-points/channel-defaults`-toiminnolla. `POST /channels/campaign` kirjoittaa edelleen vanhan kanavakohtaisen kampanjareitityskartan, mutta kyseistä karttaa ei enää käytetä saapuvan liikenteen reititykseen millään tilillä; se säilytetään vain palautusta varten. Älä rakenna sen varaan. Katso [Reititä kanava kampanjaan](channels.md#route-a-channel-to-a-campaign) nähdäksesi molemmat tavat rinnakkain.

---

## Listaa kampanjat

`GET /campaigns`

Palauttaa kampanjasi, uusimmat ensin. Arkistoituja kampanjoita ei sisällytetä, ellet välitä arvoa `archived=true`.

**Kyselyparametrit**

| Parametri | Pakollinen | Kuvaus |
|---|---|---|
| `limit` | Ei | Palautettavien kampanjoiden enimmäismäärä. Oletus `50`, enimmäismäärä `100`. |
| `cursor` | Ei | Sivutuskursori. Välitä edellisen vastauksen `next_cursor`-arvo saadaksesi seuraavan sivun. |
| `archived` | Ei | Aseta arvoon `true` sisällyttääksesi arkistoidut kampanjat. |

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

**Vastaus**

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

Kun `next_cursor` on `null`, olet saavuttanut viimeisen sivun.

---

## Hae kampanja

`GET /campaigns/{campaignId}`

Palauttaa koko kampanjadokumentin, mukaan lukien live-bottikonfiguraation (`bot`), seuranta-asetukset, käytössä olevat kanavat ja mahdolliset avainsanat. Aikaleimat palautetaan epoch-millisekunteina.

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

**Vastaus**

```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
**Huomautus:** Toisen tilin omistama kampanja palauttaa `404 Campaign not found` (eikä `403`), joten et voi tietää, onko tunnus olemassa toisella tilillä.
:::


---

## Luo kampanja

`POST /campaigns`

Luo uuden kampanjan. `name` ja `type` ovat pakollisia; kaikki muu on valinnaista. Voit sisällyttää samaan pyyntöön minkä tahansa muun kampanjakentän — esimerkiksi `language`, `ai_mode` tai täydellisen `bot`-konfiguraatio-objektin — ja se tallennetaan uuden kampanjan yhteydessä. Omistaja ja luontiaika asetetaan automaattisesti.

**Pyynnön kentät**

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `name` | Kyllä | Kampanjan nimi. |
| `type` | Kyllä | Yksi neljästä yllä mainitusta kampanjatyypistä. |
| `language` | Ei | Kieli, jolla botti vastaa (esim. `"en"`). |
| `ai_mode` | Ei | Onko tekoälytila päällä (`true`/`false`). Kampanjassa, johon vastaa tekoälyagentti, luku palauttaa agentin **Aktiivinen**-valinnan tallennetun arvon sijaan – katso huomautus päivittämisestä alta. |
| `bot` | Ei | Botin konfiguraatio-objekti (katso [Botin konfiguraatiokentät](#bot-configuration-fields)). |
| `list_id` | Ei | Liitettävän yhteystietoluettelon ID. |
| `event_id` | Ei | Tapahtumatyypin ID, jonka tekoäly voi varata. |
| `event_ids` | Ei | Useita tapahtumatyyppejä kerralla tapahtumatyyppien ID-taulukkona – ensimmäinen on oletusarvo. Lähetä joko `event_id` tai `event_ids`, ei molempia. |

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

**Vastaus**

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

---

## Päivitä kampanja

`PUT /campaigns/{campaignId}`

Päivittää kampanjaa osittain — lähetä vain ne kentät, jotka haluat muuttaa. Tämä on ainoa yleinen päivityskomento; `PATCH /campaigns/{campaignId}`-komentoa ei ole (kaksi `PATCH`-reittiä ovat kapeat [ota käyttöön](#enable-or-disable-a-campaign) ja [arkistoi](#archive-or-restore-a-campaign) -kytkimet).

**Mitkä kentät voit muuttaa.** Kaikki, mitä kampanjaeditori kirjoittaa, mukaan lukien `name`, `status`, `type`, `language`, `ai_mode`, `enabled_channels`, liipaisin- ja tippumisasetukset, varaus- ja seurantaliput, Instagram/Facebook-valvontakentät sekä koko `bot`-kokoonpano. Identiteetti ja omistajuus on lukittu kampanjan eliniäksi: `user`, `id` ja `created_at` hylätään, samoin kuin mikä tahansa kentän nimi, jota päätepiste ei tunnista. Hylkääminen tapahtuu pyyntökohtaisesti, ei kenttäkohtaisesti — yksi tuntematon avain palauttaa `400`-virheen, eikä pyynnössä kirjoiteta **mitään**.

**`ai_mode` agenttipohjaisessa kampanjassa heijastaa agenttia.** Kun kampanjaan vastaa tekoälyagentti, kampanjan lukeminen palauttaa `ai_mode`-arvon, joka on johdettu kyseisen agentin **Aktiivinen**-valinnasta – se on ainoa kytkin, joka todellisuudessa päättää, vastaako tekoäly. `ai_mode`-arvon kirjoittaminen tällaiseen kampanjaan hyväksytään, mutta se ei muuta takaisin luettavaa arvoa; kytke sen sijaan agentin Aktiivinen-valinta päälle tai pois (hallintapaneelissa tai Agents API:n kautta). Perinteisissä kampanjoissa, joissa ei ole agenttia, `ai_mode` lukee ja kirjoittaa tallennetun arvon kuten ennenkin.

**Bottikentät yhdistetään, niitä ei korvata.** Lähetä bottiasetukset joko pisteellä erotettuina avaimina (`"bot.instructions": "..."`) tai sisäkkäisenä objektina (`"bot": { "instructions": "..." }`) — molemmat kirjoittavat lehti lehdeltä, joten pois jätetyt kentät säilyttävät nykyiset arvonsa. `bot.instructions`, `bot.goal`, `bot.rules` ja `bot.personality` ovat kaikki muokattavissa tällä tavalla, kuten myös kaikki muut [Bottiasetusten kentät](#bot-configuration-fields) -kohdassa luetellut bottiasetukset. Sama pätee kohtiin `test_bot`, `frequency` ja `follow_up_config`.

Jos haluat korvata bottikokoonpanon kokonaan — poistaen kaikki kentät, joita et lähetä — käytä `bot_replace`-komentoa (tai `test_bot_replace`-komentoa) koko objektin kanssa. Et voi yhdistää korvaamista ja yhdistämistä samalle objektille yhdessä pyynnössä; se palauttaa `400`-virheen.

::: note
**Huomautus:** `bot.*`-komennon kirjoittaminen API:n kautta astuu voimaan **välittömästi** live-kampanjassa. Hallintapaneelin editori toimii eri tavalla: siellä tehdyt muokkaukset tallennetaan luonnoksena ja ne tulevat voimaan vasta, kun asiakas napsauttaa Julkaise. Joten jos asiakkaalla on julkaisemattomia hallintapaneelimuutoksia, ne pysyvät `test_bot`-tilassa, ja API-luku `bot`-kohdasta näyttää oikein sen, mitä tekoäly käyttää juuri nyt.
:::


Muutamia kenttiä asetetaan erillisen avaimen kautta sen sijaan, että ne kirjoitettaisiin suoraan: käytä `list_id` yhteystietoluettelolle, `event_id` tapahtumatyypille (tai `event_ids`, järjestettyä tapahtumatyyppien ID-taulukkoa, jotta tekoäly voi varata useita – ensimmäinen on oletusarvo; tyhjä taulukko poistaa kaikkien linkityksen) ja `contact_ids` (yhteystietojen ID-taulukko) kampanjan yhteystiedoille. Tietokannan merkintöjä hallitaan [UKK-rajapinnan](faqs.md) kautta, ei tämän päätepisteen kautta.

**Tunnisteet korvaavat, ne eivät yhdisty.** Lähetä `tags` täydellisenä taulukkona, niin siitä tulee kampanjan tunnistejoukko – katso [Kampanjan tunnisteet](#campaign-tags) kenttiä ja yksittäisen tunnisteen lisäämiseen tai muokkaamiseen tarkoitettuja päätepisteitä varten.

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

**Vastaus**

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

---

## Poista kampanja

`DELETE /campaigns/{campaignId}`

Poistaa kampanjan pysyvästi. Tätä toimintoa ei voi kumota – jos saatat tarvita kampanjaa myöhemmin, [arkistoi se](#archive-or-restore-a-campaign) sen sijaan.

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

**Vastaus**

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

---

## Kampanjan kopioiminen

`POST /campaigns/{campaignId}/duplicate`

Luo kopion kampanjasta säilyttäen kaikki sen asetukset. Kopio on aluksi **pois käytöstä** ja sen nimeen lisätään `(copy)`-pääte, joten se ei lähetä viestejä ennen kuin otat sen erikseen käyttöön.

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

**Vastaus**

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

> Kaksoiskappaleet **yhden tilin sisällä**.

---


## Kampanjan ottaminen käyttöön tai poistaminen käytöstä

`PATCH /campaigns/{campaignId}/enabled`

Kytkee kampanjan päälle tai pois päältä. Pois käytöstä asetettu kampanja lakkaa ottamasta yhteyttä yhteystietoihin, mutta säilyttää kaikki konfiguraationsa.

**Pyynnön kentät**

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `enabled` | Kyllä | `true` ottaaksesi käyttöön, `false` poistaaksesi käytöstä. Tämän on oltava totuusarvo (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()
```

**Vastaus**

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

---

## Kampanjan arkistointi tai palauttaminen

`PATCH /campaigns/{campaignId}/archived`

Arkistoi tai palauttaa kampanjan. Arkistoidut kampanjat on piilotettu oletusarvoisesta kampanjaluettelosta, mutta ne säilyttävät kaikki tietonsa ja ne voidaan palauttaa milloin tahansa.

**Pyynnön kentät**

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `archived` | Kyllä | `true` arkistoidaksesi, `false` palauttaaksesi. Tämän on oltava totuusarvo (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()
```

**Vastaus**

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

---

## Päivitä botin asetukset

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

Tämä on turvallinen tapa muuttaa yksittäisiä botin asetuksia. Jokainen lähettämäsi kenttä **yhdistetään** olemassa olevaan botin konfiguraatioon, joten kaikki pois jättämäsi kentät säilyvät ennallaan. Käytä tätä kampanjan päivityspäätepisteen sijaan aina, kun haluat vain muokata botin osia.

Kenttien avainten on sisällettävä vain kirjaimia, numeroita, alaviivoja ja yhdysviivoja.

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

**Vastaus**

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

### Botin konfiguraatiokentät

Kaikki botin kentät ovat valinnaisia. Lähetä vain ne, jotka haluat asettaa. Kaikki muut tässä lueteltujen lisäksi lähetetyt botin kentät hyväksytään ja tallennetaan sellaisenaan.

| Kenttä | Tyyppi | Kuvaus |
|---|---|---|
| `instructions` | string | Ensisijaiset ohjeet, jotka ohjaavat botin keskustelutapaa yhteystietojen kanssa. |
| `rules` | string | Tiukat säännöt, joita botin on aina noudatettava. |
| `goal` | string | Lopputulos, jota botin tulee tavoitella jokaisessa keskustelussa. |
| `personality` | string | Botin äänensävy ja persoonallisuuden kuvaus. |
| `ai_speed` | string | Kuinka paljon päättelyä tekoäly soveltaa ennen vastaamista. Yksi seuraavista: `fast`, `fast_thinker`, `balanced`, `thorough`. |
| `anthropic_model` | string | Tämän kampanjan vastauksissa käytetty tekoälyn laatutaso. Yksi seuraavista: `standard`, `economy` (vanhentunut), `max`, `mini`. `max` ja `mini` tulevat voimaan vain tileillä, jotka ovat oikeutettuja kyseisiin tasoihin. |
| `max_messages` | integer | Botin viestien enimmäismäärä keskustelua kohden. |
| `alert_human_when` | string | Ehdot, joiden täyttyessä botin tulee hälyttää ihmistiimin jäsen. |
| `availability` | object | Botin aktiivisten tuntien aikataulu. Voit asettaa tämän tässä tai käyttää erillistä [aktiivisten tuntien päätepistettä](#set-the-bot-active-hours). |
| `follow_up_config` | object | Seurantatoimintojen konfiguraatio, tallennettuna sellaisenaan. |

---

## Aseta botin aukioloajat

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

Asettaa botin saatavuusaikataulun. Määritettyjen aikavälien ulkopuolella botti ei vastaa automaattisesti. Tämä kirjoittaa botin konfiguraation `availability`-kentän.

**Pyynnön kentät**

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `availability` | Kyllä | Objekti, jonka avaimina ovat viikonpäivät. Sallitut avaimet ovat `monday` – `sunday`; muut avaimet palauttavat virheen `400`. Pois jätetyt päivät pysyvät muuttumattomina. |

Jokainen viikonpäivä sisältää joko yksittäisen aikaikkunan tai taulukon ikkunoita. Ikkunassa on `start_time` ja `end_time` 24 tunnin `HH:MM`-muodossa.

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

**Vastaus**

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

---

## Listaa kampanjan mukautetut toiminnot

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

Palauttaa tähän kampanjaan linkitetyt mukautetut toiminnot täysinä määrityksinä. Mukautetut toiminnot ovat ulkoisia HTTP-toimintoja, joita botti voi kutsua keskustelun aikana – esimerkiksi varastotilanteen tarkistaminen kaupastasi tai tietueen luominen CRM-järjestelmääsi.

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

**Vastaus**

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

---

## Linkitä mukautettu funktio kampanjaan

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

Linkittää olemassa olevan [mukautetun funktion](../ai-automation/custom-functions.md) tähän kampanjaan, jotta botti voi kutsua sitä keskustelun aikana. Jo linkitetyn funktion linkittäminen uudelleen ei tee mitään.

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `custom_function_id` | Kyllä | Linkitettävän mukautetun funktion tunnus (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" }'
```

**Vastaus**

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

---

## Poista mukautetun funktion linkitys kampanjasta

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

Linkittämättömän funktion linkityksen poistaminen ei tee mitään.

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

**Vastaus**

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

---

## Linkitä tietokantalähde kampanjaan

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

Linkittää tietokantalähteen (luotu [FAQ-rajapinnan](faqs.md) kautta) tähän kampanjaan, jotta botti voi hyödyntää sitä vastatessaan. Jo linkitetyn lähteen linkittäminen uudelleen ei tee mitään.

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `kb_source_id` | Kyllä | Linkitettävän tietokantalähteen tunnus (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" }'
```

**Vastaus**

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

---

## Poista tietokantalähteen linkitys kampanjasta

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

Linkittämättömän lähteen linkityksen poistaminen ei tee mitään.

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

**Vastaus**

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

---

## Linkitä MCP-palvelin kampanjaan

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

Linkittää MCP-palvelimen tähän kampanjaan, jolloin botti saa pääsyn kyseisen palvelimen työkaluihin keskustelun aikana. Jo linkitetyn palvelimen linkittäminen uudelleen ei tee mitään.

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `mcp_server_id` | Kyllä | Linkitettävän MCP-palvelimen tunnus. |

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

**Vastaus**

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

---

## MCP-palvelimen linkityksen poistaminen kampanjasta

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

Linkityksen poistaminen palvelimelta, jota ei ole linkitetty, ei tee mitään.

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

**Vastaus**

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

---

## Kampanjan mediakirjasto

Mediakirjasto sisältää kuvia, videoita, asiakirjoja ja ääniviestejä, joita botti voi lähettää keskustelun aikana.

### Listaa kampanjan mediakirjasto

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

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

**Vastaus**

```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` on lataushetkellä luotu allekirjoitettu URL-osoite – se on saattanut vanhentua siihen mennessä, kun luet sen uudelleen; hallintapaneeli allekirjoittaa sen pyynnöstä uudelleen.

### Lataa mediatiedosto

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

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `base64Data` | Kyllä | Tiedosto base64-koodattuna (ei data-URL-etuliitettä). |
| `mimeType` | Kyllä | Tiedoston MIME-tyyppi (esim. `image/png`). |
| `title` | Kyllä | Lyhyt nimi, joka näkyy kirjastossa ja tekoälyn kehotteessa. |
| `description` | Kyllä | Ohje, joka kertoo botille, **milloin** tämä kohde lähetetään. |
| `fileName` | Ei | Alkuperäinen tiedostonimi, jota käytetään tallennusobjektin nimen muodostamiseen. |
| `sendMessage` | Ei | Suositeltu sanamuoto, jota botin tulisi käyttää lähettäessään tämän kohteen. |
| `maxSendsPerConversation` | Ei | Enimmäiskertojen määrä, jonka botti voi lähettää tämän kohteen yhdelle yhteyshenkilölle keskustelun aikana. Oletusarvo on `1`. |
| `sendAsVoiceNote` | Ei | Jos kyseessä on äänitiedosto, koodaa se WhatsApp-ääniviestiksi. Oletusarvo on `false` (tallennetaan tavallisena äänitiedostona). |

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

**Vastaus**

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

### Päivitä mediakohde

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

Muokkaa vain kohteen metatietoja — jos haluat korvata itse tiedoston, poista kohde ja lataa uusi tilalle.

| Kenttä | Kuvaus |
|---|---|
| `title` | Lyhyt nimi. |
| `description` | Lähetysajankohdan ohje. |
| `send_message` | Botin suositeltu sanamuoto. |
| `max_sends_per_conversation` | Ei-negatiivinen kokonaisluku tai `null` rajoituksen poistamiseksi. |

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

**Vastaus**

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

### Poista mediakohde

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

Jo poistetun kohteen poistaminen ei tee mitään.

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

**Vastaus**

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

---

## Kampanjan tunnisteet

Kampanjan tunniste on merkintä, jonka opetat botille käytettäväksi yhteyshenkilöön keskustelun aikana – `hot-lead`, `not-interested`, `booked-a-call`. Jokaisessa tunnisteessa on kolme osaa:

| Kenttä | Tyyppi | Kuvaus |
|---|---|---|
| `name` | merkkijono, pakollinen | Itse merkintä. Tämä on se, minkä botti liittää yhteyshenkilöön ja mitä käytät myöhemmin vastaavuuksien etsimiseen, joten pidä se lyhyenä ja pysyvänä. |
| `description` | merkkijono | Ohje, joka kertoo botille, **milloin** tämä tunniste lisätään. Tämä on se osa, joka tekee työn – "henkilö vahvistaa liittyneensä yhteisöön" toimii, "kuuma liidi" ei. |
| `webhook` | merkkijono | URL-osoite, joka vastaanottaa `POST`-kutsun heti, kun tunniste lisätään yhteyshenkilölle. Jätä tyhjäksi, jos et tarvitse tätä. |
| `tag_id` | merkkijono | Valinnainen. Linkittää tämän merkinnän olemassa olevaan tunnisteeseen tililläsi uuden sijaan. Anna tämä, jos haluat käsitellä tätä tiettyä tunnistetta myöhemmin alla olevilla yksittäisen tunnisteen päätepisteillä. |

Tunnisteiden nimien on oltava yksilöllisiä kampanjan sisällä. Botti lisää tunnisteet **nimen perusteella**, joten kahdella merkinnällä, joilla on sama nimi, ei ole määriteltyä voittajaa.

### Aseta kaikki kampanjan tunnisteet

`PUT /campaigns/{campaignId}` `tags`-taulukolla.

Tämä korvaa kampanjan tunnisteet täsmälleen sillä, mitä lähetät, mikä on sama asia kuin mitä hallintapaneelin Tunnisteet-välilehti tekee, kun tallennat sen. **Lähetä täydellinen taulukko joka kerta** – tunniste, jonka jätät pois, on tunniste, jonka poistit. `[]`-arvon lähettäminen tyhjentää ne kaikki.

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

**Vastaus**

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

Lue tunnisteet takaisin käyttämällä [`GET /campaigns/{campaignId}`](#get-a-campaign).

### Lisää yksi tunniste

`POST /campaigns/{campaignId}/tags`

Lisää yhden tunnisteen lähettämättä muuta uudelleen. Käytä tätä, kun lisäät tunnisteita joukkoon, jota et luonut tässä pyynnössä.

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

Täsmälleen saman tunnisteen lähettäminen kahdesti ei tee mitään toisella kerralla. Saman `tag_id`-arvon lähettäminen eri nimellä tai kuvauksella lisää **toisen** merkinnän sen sijaan, että se muokkaisi ensimmäistä – käytä alla olevaa päätepistettä muokataksesi olemassa olevaa.

### Päivitä tai poista yksi tunniste

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

Nämä käsittelevät yhtä merkintää sen `tag_id` perusteella, joten ne toimivat vain tunnisteilla, jotka on luotu sellaisella. Jos tunnisteella ei ole `tag_id`, muuta se yllä olevalla koko taulukon `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." } }'
```

Tunniste `tagId`, joka ei ole kampanjassa, palauttaa `404` arvolla `"Tag not found in campaign tags"`.

---

## Kampanjan kanavien vaihtaminen

`POST /campaigns/{campaignId}/channels`

Lisää tai poistaa kanavia kampanjan `enabled_channels`-taulukosta lähettämättä koko taulukkoa uudelleen — turvallisempi vaihtoehto kuin [`PUT /campaigns/{campaignId}`](#update-a-campaign), jos jokin muu prosessi saattaa muokata kampanjaa samanaikaisesti.

Lähetä joko yksittäinen vaihto tai erä — älä molempia samassa pyynnössä:

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

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

| Kenttä | Kuvaus |
|---|---|
| `channel` | Yksi kanava vaihdettavaksi. Käytä yhdessä `action`:n kanssa. |
| `action` | `"add"` tai `"remove"`. Käytä yhdessä `channel`:n kanssa. |
| `add` | Taulukko lisättävistä kanavista. Erämuoto — käytä `channel`/`action`-vaihtoehtojen sijaan. |
| `remove` | Taulukko poistettavista kanavista. Erämuoto. |

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

**Vastaus**

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

> Tämä muuttaa vain sitä, millä kanavilla kampanjaa mainostetaan — se ei päätä, kuka vastaa kanavaan. Katso lisätietoja kohdista [Kampanjatyypit](#campaign-types) yllä ja [Kampanjan reitittäminen saapuviin kanaviin](#route-a-campaign-to-incoming-channels) alla.

---

## Kommentista yksityisviestiksi (Instagram ja Facebook)

Kommentista yksityisviestiksi (Comment-to-DM) muuttaa julkaisuusi jätetyn kommentin yksityiseksi keskusteluksi: joku kommentoi, botti lähettää hänelle yksityisviestin (DM), ja kampanja jatkaa keskustelua siitä eteenpäin. Se määritetään kokonaan kampanjaobjektin kautta, joten siinä ei ole mitään, mikä olisi vain käyttöliittymässä.

Yhdistä ensin Facebook-sivu – katso [Kanavan yhdistäminen](channels.md#instagram--messenger-meta). Määritä sitten alla olevat kentät käyttämällä [`PUT /campaigns/{campaignId}`](#update-a-campaign).

> **Kampanjan on oltava `Live`.** Kommenttien seuranta poimii vain kampanjat, joiden `status` on `Live` (mikä tahansa kirjainkoko — katso [Kampanjatyypit](#campaign-types)). Mikä tahansa muu tila poistaa sen hiljaisesti käytöstä, ja keksitty tila, kuten `"Active"`, hylätään nyt `400`-virheellä sen sijaan, että se tallennettaisiin. Sallittuja tiloja ovat `Draft`, `Pending Approval`, `Scheduled`, `Live`, `Paused`, `Completed`, `Sent` ja `Failed`.

**Kentät**

| Kenttä | Tyyppi | Kuvaus |
|---|---|---|
| `monitor_instagram_posts` | boolean | Seuraa jokaista Instagram-julkaisua yhdistetyllä sivulla. |
| `instagram_post_ids` | string[] | Seuraa vain näitä Instagram-julkaisuja. Jätä tyhjäksi, kun `monitor_instagram_posts` on päällä. |
| `instagram_comment_delay_minutes` | number | Odota näin monta minuuttia kommentin jälkeen ennen yksityisviestin lähettämistä. |
| `monitor_facebook_posts` | boolean | Seuraa jokaista Facebook-julkaisua yhdistetyllä sivulla. |
| `facebook_post_ids` | string[] | Seuraa vain näitä Facebook-julkaisuja. |
| `facebook_comment_delay_minutes` | number | Viive ennen yksityisviestiä minuuteissa. |
| `public_comment_reply_instructions` | string | Ohjeistus julkiselle vastaukselle, joka jätetään itse kommenttiin. Korvaa oletusarvoisen "tarkista yksityisviestisi" -tekstin. |
| `first_response_mode` | string | `"ai"` (oletus) luo ensimmäisen yksityisviestin ja julkisen vastauksen. `"exact_text"` lähettää sanamuotosi sellaisenaan ilman tekoälyn luontia tai krediittien veloitusta. |
| `first_response_exact_text` | string | Sanatarkka ensimmäinen yksityisviesti, jota käytetään, kun `first_response_mode` on `"exact_text"`. Vaaditaan kyseisen tilan aktivoimiseksi. |
| `first_response_exact_text_variants` | string[] | Lisäsanamuotoja ensimmäiselle yksityisviestille. Yksi valitaan satunnaisesti lähetystä kohden, jotta toistuvat yksityisviestit eivät ole täysin identtisiä. |
| `public_comment_reply_exact_text` | string | Sanatarkka julkinen vastaus `"exact_text"`-tilassa. Jätä tyhjäksi, jos haluat ohittaa julkisen vastauksen ja lähettää vain yksityisviestin. |
| `public_comment_reply_exact_text_variants` | string[] | Lisäsanamuotoja julkiselle vastaukselle. |
| `monitor_instagram_followers` | boolean | Käsittele uutta seuraajaa liipaisimena ja lähetä aloitusviesti (Instagram-henkilökohtaiset tilit). |
| `follower_outreach_instructions` | string | Ohjeistus kyseiselle uuden seuraajan aloitusviestille. |
| `respond_to_instagram_story_replies` | boolean | Vastaako tekoäly Instagram Story -vastauksiin. Oletus `true`. Aseta `false`, jotta Story-vastaukset päätyvät keskusteluun (Storyn kera) ilman tekoälyn vastausta. Reaaliaikainen asetus – ei osa luonnosta, joten sitä ei tarvitse julkaista. |

**Kentän tyhjentäminen**

Nämä kentät poistetaan sen sijaan, että ne asetettaisiin arvoon `null`, kun lähetät `null`, jolloin botti palaa oletusarvoihinsa: `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`.

> **Yksikin tuntematon avain hylkää koko pyynnön.** `PUT /campaigns/{campaignId}` validoi koko rungon sallittujen luetteloa vasten. Avain, jota ei tunnisteta, palauttaa `400` koko pyynnölle – sitä ei ohiteta hiljaisesti, eikä mitään muita kyseisen rungon kenttiä kirjoiteta.

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

**Vastaus**

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

> Kommenttiin jätettävä näkyvä vastaus vaatii tilauspakettiisi kuuluvan kommenttivastausominaisuuden. Ilman sitä yksityisviesti lähetetään silti, mutta julkinen vastaus ohitetaan.

---

## Kampanjan optimointi tekoälyllä

`POST /campaigns/{campaignId}/optimize`

Suorittaa saman tekoälypohjaisen uudelleenkirjoituksen kuin hallintapaneelin Optimoi- ja peukalo alas -palautetoiminnot: ottaa palautteesi, kirjoittaa botin ohjeet uudelleen ja tallentaa tuloksen uutena luonnoksena tarkistettavaksi.

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `user_feedback` | Toinen näistä on pakollinen | Vapaamuotoinen palaute siitä, mitä parantaa. |
| `thumbs_down_feedback` | Toinen näistä on pakollinen | Palaute, joka on kerätty peukalo alas -toiminnolla tietystä botin vastauksesta. |
| `thumbs_down_message` | Ei | Bottiviesti, johon peukalo alas -palaute viittaa. |

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

**Vastaus** (`202` — uudelleenkirjoitus suoritetaan taustalla)

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

Kysy [`GET /campaigns/{campaignId}`](#get-a-campaign) ja seuraa `test_bot.status`: se vaihtuu heti tilaan `"Optimizing"` ja palaa tilaan `"Draft"`, kun uudelleenkirjoitus on valmis kohdassa `test_bot`. Sen jälkeen se toimii kuten mikä tahansa hallintapaneelin luonnos – tarkista se ja julkaise se hallintapaneelissa, jotta se tulee käyttöön. `409` tarkoittaa, että optimointi on jo käynnissä tälle kampanjalle.

> Optimointi kuluttaa krediittejä, aivan kuten muutkin tilisi tekoälytoiminnot.

---

## Määritä yhteyshenkilö kampanjaan

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

Lisää olemassa olevan yhteyshenkilön kampanjaan ja lähettää pyydettäessä kampanjan aloitusviestin välittömästi. Tämä on tapa lähettää kampanjan hyväksytty WhatsApp-malli yhdelle yhteyshenkilölle: malli, jolla kampanja hyväksyttiin, kuuluu kyseiseen kampanjaan, joten se ei näy [Templates API](templates.md) -kirjastossa eikä sitä voi lähettää `/whatsapp-templates/send` kautta.

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `sendOpeningMessage` | Ei | `true` lähettää kampanjan aloitusviestin (hyväksytty WhatsApp-malli WhatsApp-kampanjassa) heti, kun yhteyshenkilö on määritetty. Oletusarvo on `false`. |
| `triggerAIResponse` | Ei | `true` antaa tekoälyn kirjoittaa oman ensimmäisen viestinsä sen sijaan. Oletusarvo on `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 }'
```

**Vastaus**

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

> **Krediitit:** Aloitusviestin lähettäminen WhatsApp-kampanjassa veloitetaan kuten mikä tahansa malliviestin lähetys, ja hinta määräytyy vastaanottajan maan ja mallin kategorian mukaan. Muissa kanavissa aloitusviesti on tavallinen lähtevä viesti.

---

## Kampanjan reitittäminen saapuviin kanaviin

Nämä päätepisteet hallitsevat sitä, mikä kampanja vastaa uusiin, tuntemattomiin yhteyshenkilöihin kanavassa. **Suosi Entry Points -toimintoa** uusissa integraatioissa (katso huomautus kohdasta [Kampanjatyypit](#campaign-types)) – nämä pysyvät hyödyllisinä vanhemmalla tavalla reititettävien kampanjoiden kanssa työskenneltäessä sekä kanavan omistajuusristiriitojen ratkaisemisessa kahden saapuvan kampanjan välillä.

### Kampanjan määrittäminen saapuviin kanaviin

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

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `channels` | Kyllä | Taulukko kanavista, joihin tämän kampanjan tulisi vastata uusien, tuntemattomien yhteyshenkilöiden kohdalla. |

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

**Vastaus**

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

`channels` listaa vain ne kanavat, jotka todella reititettiin tähän kampanjaan; `failed` listaa ne, joita ei reititetty. Jos jokainen pyydetty kanava epäonnistuu, itse pyyntö epäonnistuu.

### Kampanjan saapuvan reitityksen tyhjentäminen

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

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `channelToUnassign` | Ei | Tyhjennä reititys vain tältä yhdeltä kanavalta. Jätä pois, jos haluat tyhjentää kaikki kanavat, joihin tämä kampanja tällä hetkellä vastaa. |

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

**Vastaus**

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

### Lepotilassa olevan kampanjan aktivointi uudelleen

`POST /campaigns/{campaignId}/reactivate`

Palauttaa kampanjan `Ended`-, `Completed`-, `Paused`- tai `Draft`-tilasta ja vapauttaa sen kanavat. Toimii vain `Incoming from Unknown Contacts`- tai `Combined`-kampanjoille – kampanja, joka on jo `Live`, käsitellään onnistuneena, eikä sille tarvitse tehdä mitään.

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

**Vastaus**

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

Kanava, jonka toisen kampanjan agentti on jo varannut, näkyy `channelsBlockedByConflict`-tilassa sen sijaan, että koko kutsu epäonnistuisi – käytä alla olevaa [pysäytä ristiriitainen saapuva kampanja](#stop-a-conflicting-incoming-campaign) -toimintoa vapauttaaksesi sen ensin, jos haluat tämän kampanjan ottavan sen haltuunsa. `400` palautetaan kampanjatyypille, joka ei tue uudelleenaktivointia, tai tilalle, joka ei ole jokin yllä mainituista lepotiloista.

### Pysäytä ristiriitainen saapuva kampanja

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

Vapauttaa tämän kampanjan kanavat siltä TOISELTA kampanjalta, joka niitä parhaillaan hallitsee, jotta tämä kampanja voi varata ne seuraavaksi. Tämä on REST-versio siitä, mitä hallintapaneeli tekee automaattisesti, kun käynnistät saapuvan kampanjan kanavalle, johon joku muu vastaa jo.

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

**Vastaus**

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

`released_channels` palautuu tyhjänä, kun tämä kampanja omistaa jo jokaisen mainostamansa kanavan – mitään ei tarvitse ottaa haltuun.

---

## Kustannusarviot

Arvioi kampanjan käynnistämisen kustannukset ennen sen lähettämistä.

### WhatsApp-mallin kustannusarvio

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

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

**Vastaus**

```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` on `"credits"` hallinnoidulla WhatsApp-kaistalla. Kaistalla, jossa Meta laskuttaa WhatsApp Business -tiliäsi suoraan, `costPerContact`, `subtotal` ja `totalTemplateCost` palautuvat `null` – ei koskaan `0`, mikä tulkittaisiin ilmaiseksi – koska raportoitavaa luottosummaa ei ole.

### SMS-kustannusarvio

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

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

**Vastaus**

```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 lähetetään aina oman Twilio-tilisi kautta (katso [SMS-palveluntarjoaja](../settings/sms-provider.md)), joten Twilio laskuttaa tämän aina suoraan – `estimatedCostUsd` on arvio kyseisestä Twilio-laskusta, ei luottoveloitus.

---

## Rajatarkistukset

Tarkista raja ennen lähettämistä sen sijaan, että huomaisit sen epäonnistuneen lähetyksen jälkeen.

### Kampanjakohtaiset tarkistukset

`GET /campaigns/{campaignId}/limits/ai-credit-messaging` — ylittäisikö tämän kampanjan käynnistäminen tai ajastaminen tilisi tekoälypohjaisen viestinnän luottorajan.

`GET /campaigns/{campaignId}/limits/messaging` — ylittäisikö se tilisi päivittäisen viestintärajan.

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

**Vastaus** (rajaa ei ylitetty)

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

Sen sijaan palautetaan `400`, jos raja ylittyy, ja syy löytyy kohdasta `error`.

### Tilikohtaiset tarkistukset

`GET /campaigns/limits/campaigns` — oletko saavuttanut tilauksesi kuukausittaisen kampanjoiden luontirajan.

`GET /campaigns/limits/contacts` — oletko saavuttanut tilauksesi yhteystietorajan.

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

**Vastaus**

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

---

## Kampanjoiden tilastojen yhteenveto

`GET /campaigns/stats/totals`

Lähetettyjen ja vastattujen viestien kokonaismäärät jokaiselle tilisi kampanjalle JA jokaiselle tekoälyagentille liukuvan ikkunan ajalta — samat luvut, jotka kampanjaluettelosivu näyttää jokaisen rivin vieressä, yhdellä kutsulla sen sijaan, että tekisit yhden pyynnön per kampanja.

| Kyselyparametri | Kuvaus |
|---|---|
| `days` | Liukuvan ikkunan koko, 1-365. Oletusarvo on 90. |

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

**Vastaus**

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

`byAgent` on oma koosteensa, ei summa `byCampaign`-kohdasta — tekoälyagentteja käyttävän tilin liikenne ei välttämättä liity mihinkään kampanjaan, joten se jäisi muuten näkymättömäksi tässä.

---

## Testaa kampanjaa hiekkalaatikossa

Hiekkalaatikon avulla voit käydä keskustelua kampanjan botin kanssa koskematta oikeaan kanavaan tai oikeaan yhteystietoon. Se on sama hiekkalaatikko kuin hallintapaneelin kokeilupaneeli, ja se on täysin käytettävissä API:n kautta.

Kulkusuunta on: luo piilotettu testiyhteystieto, lähetä viesti ja kysy sitten kampanjalta botin vastausta. Vastaukset luodaan asynkronisesti, joten ne saapuvat kampanjan `test_messages`-kohtaan eivätkä vastausrunkoon.

> **Playground käyttää API-kustannushyvityksiä.** API-avaimella aloitettu testikeskustelu veloitetaan normaalin tekoälyviestihinnaston mukaisesti, samalla tavalla kuin todellinen vastaus, ja se näkyy käyttöhistoriassasi tavallisena merkintänä. Hallintapaneelista tehtävä testaus pysyy maksuttomana. Ero on harkittu: testiajo tekee saman tekoälytyön kuin live-ajo, joten mittaamaton API-playground olisi tapa käyttää rajattomasti tekoälyä jonkun toisen laskuun.

### Vaihe 1 - Luo testiyhteystieto

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

Luo piilotetun testiyhteyshenkilön ja linkittää sen kampanjaan. Kaikki runkokentät ovat valinnaisia; jos jätät jotain pois, järjestelmä käyttää sisäänrakennettua malli-identiteettiä (John Doe).

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `first_name` | Ei | Testiyhteyshenkilön etunimi. |
| `last_name` | Ei | Testiyhteyshenkilön sukunimi. |
| `email` | Ei | Testiyhteyshenkilön sähköpostiosoite. |
| `phone` | Ei | Testiyhteyshenkilön puhelinnumero. |

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

**Vastaus**

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

### Vaihe 2 - Tallenna saapuva viesti

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

Lisää viestejä testiketjuun. Lähetä vierailijan viesti ensin tänne, jotta se näkyy keskusteluhistoriassa, jonka botti lukee.

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `messages` | Kyllä | Taulukko viestiobjekteja, enintään 200 per pyyntö. |
| `messages[].body` | Kyllä | Viestin teksti. |
| `messages[].direction` | Kyllä | `"inbound"` vierailijalle, `"outbound"` botille. |
| `messages[].timestamp` | Ei | ISO-8601-merkkijono tai epoch-millisekunnit. |
| `messages[].role` | Ei | Valinnainen roolimerkintä. |
| `messages[].name` | Ei | Valinnainen näyttönimi. |
| `ignoreCounter` | Ei | Kokonaisluku. Nollaa kampanjan ohituslaskurin samalla kirjoituksella. |

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

**Vastaus**

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

### Vaihe 3 - Pyydä bottia vastaamaan

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

Lähettää viestin tekoälyputkeen. Tämä kutsu tuottaa varsinaisen bottivastauksen.

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `message` | Kyllä | Vierailijan uusin viestiteksti. |

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

**Vastaus**

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

`"Published"` tarkoittaa, että viesti meni tekoälyputkeen. `"Ignored"` tarkoittaa, että uudempi testiviesti korvasi tämän – leikkikenttä yhdistää nopean viestipurskeen yhdeksi vastaukseksi noin neljä sekuntia viimeisen viestin jälkeen, samalla tavalla kuin todellisessa keskustelussa odotetaan, että toinen lopettaa kirjoittamisen. Tämän yhdistämisikkunan vuoksi tämän kutsun palautuminen kestää muutaman sekunnin.

### Vaihe 4 - Lue vastaus

`GET /campaigns/{campaignId}`

Botin vastaus lisätään kampanjan `test_messages`-taulukkoon. Kyselyä kampanjasta, kunnes uusi `outbound`-merkintä ilmestyy.

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

### Nollaa leikkikenttä

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

Tyhjentää koko hiekkalaatikon: poistaa testiyhteystiedon, tyhjentää `test_messages`-kohdan ja vapauttaa botin vastauslukot. Käytä tätä testiajojen välillä.

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

**Vastaus**

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

### Muut leikkikentän päätepisteet

| Päätepiste | Mitä se tekee |
|---|---|
| `DELETE /campaigns/{campaignId}/try-out/contact` | Poistaa vain nykyisen testiyhteystiedon ja poistaa sen linkityksen, jättäen `test_messages`-kohdan ennalleen. Onnistuu, vaikka yhtään yhteystietoa ei olisi linkitetty. |
| `POST /campaigns/{campaignId}/try-out/transfer` | Käynnistää uuden leikkikentän, joka on alustettu olemassa olevalla keskustelulla, yhdellä pyynnöllä: korvaa testiyhteystiedon ja ylikirjoittaa `test_messages`-kohdan. Runko hyväksyy `first_name`, `last_name`, `messages` (voi olla tyhjä) ja `ignoreCounter`. Suosi tätä poista-sitten-luo-sitten-lisää-menetelmän sijaan, joka kolminkertaistaa nopeusrajoituksen kulutuksen. |
| `POST /campaigns/{campaignId}/try-out/messages/replace` | Ylikirjoittaa `test_messages`-kohdan kokonaisuudessaan lisäämisen sijaan. Käytä säikeen katkaisemiseen tai kelaamiseen. |
| `POST /campaigns/{campaignId}/try-out/contact/reset-ignore-counter` | Nollaa vain testiyhteystiedon ohituslaskurin, uudelleenyrityksiä ja toistuvia työnkulkuja varten lähetyksen jälkeen. |

---

## Kampanjoiden API-virheet

Kampanjoiden päätepisteet palauttavat vakioituun virhemuotoon:

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

| Tila | Milloin se tapahtuu kampanjan päätepisteessä |
|---|---|
| `400` | Pakollinen kenttä puuttuu tai on virheellinen (esimerkiksi virheellinen `type`, ei-totuusarvoinen `enabled` tai tuntematon viikonpäiväavain). Palautetaan myös [rajatarkistuksen](#limit-checks) päätepisteestä, kun raja ylittyisi, sekä [uudelleenaktivoinnista](#reactivate-a-dormant-campaign), jos kampanjatyyppi tai tila ei tue sitä. |
| `404` | Kampanjaa ei löytynyt — joko sitä ei ole olemassa tai se kuuluu toiselle tilille. |
| `409` | [Optimointi](#optimize-a-campaign-with-ai) on jo käynnissä tälle kampanjalle. |

Jaetut koodit, joita jokainen päätepiste voi palauttaa — `401`, `403` (tilauksesi ei sisällä API-käyttöoikeutta), `429` (nopeusrajoitus) ja `500` — on lueteltu uudelleenyritysohjeiden kera kohdassa [Virheet ja sivutus](errors-and-pagination.md).

---

## Aiheeseen liittyvää

- [Ohjaa kanava kampanjaan](channels.md#route-a-channel-to-a-campaign) — määritä Instagram, WhatsApp tai mikä tahansa muu kanava vastaamaan tekoälyagentille sisääntulopisteiden (Entry Points) avulla.
- [Luo jatkotoimenpidemalleja tekoälyllä](templates.md#generate-follow-up-templates-with-ai) — käynnistä taustaprosessi, joka kirjoittaa kampanjan WhatsApp-jatkotoimenpidemallit.
- [UKK-rajapinta (FAQs API)](faqs.md) — hallitse kampanjoidesi käyttämiä kysymys-vastaus-tietoja.
- [API-käyttöoikeus](../integrations/api-access.md) — luo API-avaimesi.
- [Todennus](authentication.md) — kaikki tavat välittää avaimesi.
