
# Kanavayhteys-API

Tämä opas näyttää, kuinka viestintäkanavat yhdistetään tiliin API:n avulla. Se on kirjoitettu integraatiota tai käärettä rakentavalle kehittäjälle, joten se keskittyy tarkkoihin pyyntöihin, niiden tekemisjärjestykseen ja saataviin vastauksiin.

On yksi malli, joka sinun on ymmärrettävä heti alussa, koska se pätee lähes jokaiseen tässä olevaan kanavaan.

## Yhdistä-ja-kysely-malli (connect-then-poll)

Useimpia kanavia ei voi yhdistää yhdellä API-kutsulla. WhatsAppin, Instagramin tai Messengerin yhdistäminen tarkoittaa, että tilinhaltijan on kirjauduttava omalle palveluntarjoajan tililleen ja hyväksyttävä käyttöoikeus. Tälle hyväksynnälle **ei ole headless-polkua (täysin automatisoitua)** – oikean henkilön on avattava URL-osoite selaimessa tai skannattava QR-koodi puhelimellaan.

Joten kulku on aina seuraava:

1. **Aloita yhteys** käyttämällä `POST`. Vastaus antaa sinulle joko avattavan URL-osoitteen tai näytettävän QR-koodin.
2. **Anna se loppukäyttäjälle** – avaa URL-osoite hänen selaimessaan tai näytä QR-koodi ruudulla skannausta varten.
3. **Kysy tilan päätepistettä** käyttämällä `GET` lyhyin väliajoin (muutaman sekunnin välein), kunnes tila saavuttaa yhdistetyn tilan.

Integraatiosi tehtävä on ohjata tätä silmukkaa: näytä URL-osoite tai QR-koodi ja kysy sitten tilaa, kunnes se on valmis. Suunnittele käyttöliittymäsi kyselyn ympärille – latausympyrä ja viesti "odotetaan, että viimeistelet selaimessasi" toimii hyvin.

::: note
**Huomautus:** Varmista ennen aloittamista, että API-käyttöoikeus on käytössä tilauksessasi ja että sinulla on API-avain. Katso kohdasta [API-käyttöoikeus](../integrations/api-access.md), kuinka luot sellaisen. Kaikissa alla olevissa pyynnöissä käytetään perus-URL-osoitetta `https://api.youraiconnector.com/v1`, ja jokainen pyyntö on todennettava. Katso kohdasta [Todennus](authentication.md) neljä hyväksyttyä tapaa – tässä olevat esimerkit käyttävät `X-API-Key`-otsikkoa, ja jokaisella sivulla on yksi cURL-esimerkki, joka näyttää yksinkertaisemman `?apiKey=`-kyselymuodon.
:::


---

## Instagram + Messenger (Meta)

Instagram ja Messenger yhdistetään yhdessä kulussa, koska ne molemmat toimivat Facebook-sivulla. Tilinhaltija valtuuttaa yhteyden Facebookin kautta, sinä haet listan hänen hallinnoimistaan sivuista ja valitset, minkä sivun haluat yhdistää.

### Vaihe 1 - Aloita Instagram + Messenger -yhteys

```
POST /channels/meta/connect
```

Tämä palauttaa suostumus-URL-osoitteen. Tässä pyynnössä ei lähetetä tunnistetietoja – yhteys valtuutetaan kokonaan selaimessa.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/meta/connect?apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/channels/meta/connect", {
  method: "POST",
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
// Open data.oauth_url in the end user's browser.
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/channels/meta/connect",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
# Open data["oauth_url"] in the end user's browser.
```

**Vastaus**

```json
{
  "success": true,
  "oauth_url": "https://www.facebook.com/v21.0/dialog/oauth?client_id=...&state=...",
  "state_token": "opaque-one-time-token",
  "connect_url": "https://api.youraiconnector.com/v1/channels/meta/connect/page?token=eyJhbGciOi...",
  "connect_url_expires_at": 1717000000000,
  "expires_at": "2026-06-10T12:30:00.000Z"
}
```

Avaa `oauth_url` loppukäyttäjän selaimessa, jotta hän voi kirjautua Facebookiin ja hyväksyä käyttöoikeuden. Yhteysyritys vanhenee kohdassa `expires_at` (noin 30 minuuttia) – jos se vanhenee, aloita alusta. Käsittele `state_token` lyhytikäisenä salaisuutena äläkä kirjaa sitä lokiin.

### Helpoin vaihtoehto Instagram + Messengerille: luovuta `connect_url`

Vastaus sisältää myös valmiin `connect_url`: isännöidyn sivun, joka suorittaa koko prosessin tilinhaltijan puolesta. He avaavat sen, kirjautuvat Facebookiin, ja jos heillä on useampi kuin yksi sivu, se näyttää luettelon ja antaa heidän valita, minkä niistä he haluavat yhdistää – sen jälkeen se ilmoittaa onnistumisesta automaattisesti. Anna tämä linkki tilinhaltijalle sen sijaan, että avaisit `oauth_url` itse, rakentaisit sivunvalitsimen ja tekisit kyselyitä. Linkki toimii noin 30 minuuttia (`connect_url_expires_at`); jos se vanhenee, aloita uusi yhteys. Alla olevat manuaaliset vaiheet on tarkoitettu integraatioille, jotka haluavat hallita prosessia ja renderöidä sivunvalitsimen itse.

### Vaihe 2 - Kysy tilaa, kunnes sivut latautuvat

```
GET /channels/meta/status
```

Kun käyttäjä on saanut Facebook-kirjautumisen valmiiksi, kysy tätä päätepistettä muutaman sekunnin välein. `status`-kenttä käy läpi nämä vaiheet:

| `status` | Merkitys |
|---|---|
| `pending` | Suostumusta ei ole vielä annettu. Jatka odottamista. |
| `token_received` | Valtuutettu, mutta sivuluettelo latautuu vielä. |
| `pages_loaded` | Sivut ovat saatavilla - siirry vaiheeseen 3. |
| `connected` | Sivu on valittu ja kanava on aktiivinen. |

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/channels/meta/status" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/channels/meta/status", {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
// Poll until data.status === "pages_loaded".
```

**Python**

```python
res = requests.get(
    "https://api.youraiconnector.com/v1/channels/meta/status",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
# Poll until data["status"] == "pages_loaded".
```

**Vastaus (kun sivut ovat latautuneet)**

```json
{
  "success": true,
  "status": "pages_loaded",
  "pages": [
    {
      "id": "1234567890",
      "name": "My Business Page",
      "category": "Local business",
      "instagram_business_account": {
        "id": "17890000000000000",
        "username": "mybusiness"
      }
    }
  ],
  "selected_page": null
}
```

### Vaihe 3 - Listaa sivut (valinnainen)

Jos haluat mieluummin hakea sivuluettelon erikseen (esimerkiksi valitsimen näyttämistä varten), käytä tätä:

```
GET /channels/meta/pages
```

```bash
curl "https://api.youraiconnector.com/v1/channels/meta/pages" \
  -H "X-API-Key: YOUR_API_KEY"
```

Se palauttaa saman `pages`-taulukon kuin tila-päätepiste. (`status`-päätepiste sisältää jo sivut, joten tämä kutsu on vain mukavuutta varten.)

### Vaihe 4 - Valitse yhdistettävä sivu

```
POST /channels/meta/select-page
```

Lähetä käyttäjän valitseman sivun `page_id`. Kyseiseen sivuun linkitetty Instagram-tili yhdistetään automaattisesti; tarvitset `instagram`-objektia vain, jos haluat ohittaa käytettävän Instagram-tilin.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/meta/select-page" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "page_id": "1234567890" }'
```

**JavaScript**

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

**Python**

```python
res = requests.post(
    "https://api.youraiconnector.com/v1/channels/meta/select-page",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"page_id": "1234567890"},
)
data = res.json()
```

**Vastaus**

```json
{
  "success": true,
  "page_id": "1234567890",
  "instagram_business_account_id": "17890000000000000"
}
```

Kanava on nyt yhdistetty. Seurantana lähetettävä `GET /channels/meta/status` raportoi `status: "connected"`.

### Listaa yhdistetyn sivun julkaisut

```
GET /channels/meta/posts?platform=instagram
```

Palauttaa yhdistämäsi sivun viimeisimmät julkaisut – Instagram-media tai Facebook-julkaisut. Tästä muodostat valitsimen, kun määrität sisääntulopisteen (Entry Point), joka reagoi tiettyyn julkaisuun jätettyihin kommentteihin.

| Kyselyparametri | Pakollinen | Kuvaus |
|---|---|---|
| `platform` | Kyllä | `instagram` tai `facebook`. Mikä tahansa muu palauttaa virheen `400`. |
| `limit` | Ei | Palautettavien julkaisujen määrä, `1`-`50`. Oletusarvo on `25`. |
| `after` | Ei | Kursori seuraavalle sivulle – välitä edellisen vastauksen `nextCursor`-arvo. |

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/channels/meta/posts?platform=instagram&limit=25" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Vastaus**

```json
{
  "success": true,
  "connected": true,
  "platform": "instagram",
  "posts": [
    {
      "id": "17900000000000000",
      "caption": "New spring menu is live",
      "thumbnailUrl": "https://scontent.cdninstagram.com/...",
      "permalink": "https://www.instagram.com/p/Cxxxxxxxxxx/",
      "createdAt": "2026-05-02T09:12:00.000Z",
      "mediaType": "REELS"
    }
  ],
  "nextCursor": "QVFIUkxxxxxxxx"
}
```

`mediaType` on Instagramin oma tunniste (`REELS`, `FEED`, `STORY` tai muoto – `IMAGE`, `VIDEO`, `CAROUSEL_ALBUM`); Facebookille se on aina `POST`. `nextCursor` on `null` viimeisellä sivulla.

Jos mitään ei voida listata, kutsu palauttaa silti `200`, jossa on `connected: false` ja tyhjä `posts`-taulukko, sekä `reason`, joka kertoo syyn:

| `reason` | Mitä tehdä |
|---|---|
| _(puuttuu)_ | Sivua ei ole vielä yhdistetty – suorita yhdistämisprosessi ensin. |
| `no_instagram_account` | Facebook-sivu on yhdistetty, mutta siihen ei ole linkitetty Instagram-yritystiliä. Facebook-julkaisut näkyvät silti normaalisti. |
| `token_expired` | Tallennettu sivun tunnistetieto ei enää toimi – yhdistä kanava uudelleen. |

### Katkaise Instagram + Messenger -yhteys

```
DELETE /channels/meta
```

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/channels/meta" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Vastaus**

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

Tämä pysäyttää saapuvan reitityksen sekä Instagramille että Messengerille. Se on idempotentti - sen kutsuminen silloin, kun mitään ei ole yhdistetty, onnistuu silti.

---

## WhatsApp Business

Tämä yhdistää virallisen WhatsApp Business -numeron. Numeron on oltava jo olemassa tilillä ennen kuin kutsut yhdistämistä. Kuten Metan kohdalla, tilin haltija valtuuttaa selaimessaan, minkä jälkeen teet kyselyitä, kunnes numero ilmoittaa `ONLINE`.

### Vaihe 1 - Aloita WhatsApp Business -yhteys

```
POST /channels/whatsapp/connect
```

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/whatsapp/connect?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "phone_number": "+14155551234" }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/channels/whatsapp/connect", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ phone_number: "+14155551234" }),
});
const data = await res.json();
// Open data.oauth_url in the account holder's browser.
```

**Python**

```python
res = requests.post(
    "https://api.youraiconnector.com/v1/channels/whatsapp/connect",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"phone_number": "+14155551234"},
)
data = res.json()
# Open data["oauth_url"] in the account holder's browser.
```

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `phone_number` | Kyllä | Yhdistettävä numero E.164-muodossa (esim. `+14155551234`). |
| `only_waba_sharing` | Ei | Rajoita valtuutus olemassa olevan WhatsApp Business -tilin jakamiseen, jolloin uuden lähettäjän määritys ohitetaan. Oletusarvo on `false`. |
| `retry` | Ei | Suorita valtuutus uudelleen numerolle, jonka edellinen yritys ei valmistunut. Oletusarvo on `false`. |
| `business_name` | Ei | Kosmeettinen ohitus yrityksen nimelle, joka näkyy vain suostumusnäytöllä (enintään 256 merkkiä). Ei tallenneta. |
| `description` | Ei | Kosmeettinen ohitus yrityksen kuvaukselle, joka näkyy vain suostumusnäytöllä (enintään 256 merkkiä). Ei tallenneta. |

**Vastaus**

```json
{
  "success": true,
  "status": "pending",
  "oauth_url": "https://www.facebook.com/v21.0/dialog/oauth?client_id=...&state=...",
  "state_token": "opaque-one-time-token",
  "expires_at": "2026-06-10T12:30:00.000Z"
}
```

Avaa `oauth_url` tilin haltijan selaimessa valtuutusta varten. Kun he ovat hyväksyneet, rekisteröinti valmistuu taustalla.

### Vaihe 2 - Kysy tilaa, kunnes se on ONLINE

```
GET /channels/whatsapp/connect/{phoneNumber}/status
```

Tee kyselyitä, kunnes `status` on `ONLINE`.

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/channels/whatsapp/connect/+14155551234/status" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const phone = encodeURIComponent("+14155551234");
const res = await fetch(
  `https://api.youraiconnector.com/v1/channels/whatsapp/connect/${phone}/status`,
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
// Poll until data.status === "ONLINE".
```

**Python**

```python
import urllib.parse

phone = urllib.parse.quote("+14155551234")
res = requests.get(
    f"https://api.youraiconnector.com/v1/channels/whatsapp/connect/{phone}/status",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
# Poll until data["status"] == "ONLINE".
```

**Vastaus**

```json
{
  "success": true,
  "phone_number": "+14155551234",
  "channel": "whatsapp",
  "status": "ONLINE",
  "status_reason": null,
  "live": true
}
```

`status`-kenttä voi olla:

| `status` | Merkitys |
|---|---|
| `PENDING` | Valtuutettu, hyväksyntä on vielä kesken. Jatka kyselyitä. |
| `ONLINE` | Yhdistetty ja valmis lähettämään. |
| `RATE_LIMITED` | Liian monta yritystä - odota ennen kuin yrität uudelleen. |
| `REGISTRATION_FAILED` | Määritystä ei voitu suorittaa loppuun. |
| `DELETED` | Rekisteröintiä ei ole enää olemassa. |

`live: true` tarkoittaa, että tila tarkistettiin palveluntarjoajalta reaaliajassa; `false` tarkoittaa, että se tuli viimeisimmästä välimuistissa olevasta tilasta.

### Katkaise WhatsApp Business -numeron yhteys

```
DELETE /channels/whatsapp/{phoneNumber}
```

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/channels/whatsapp/+14155551234" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Vastaus**

```json
{ "success": true, "phone_number": "+14155551234", "disconnected": true }
```

Itse numero säilyy tilillä, joten voit yhdistää sen uudelleen myöhemmin.

---

## WhatsApp Web

WhatsApp Web yhdistää tavallisen WhatsApp-numeron skannaamalla QR-koodin, aivan kuten laitteen yhdistäminen WhatsApp-sovelluksessa. Prosessi on: aloita istunto, hae QR-koodi ja näytä se, ja kysy sitten tilaa, kunnes se on `connected`.

### Vaihe 1 - Aloita WhatsApp Web -pariliitoksen muodostaminen

```
POST /channels/whatsapp-web/connections
```

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/whatsapp-web/connections?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "phone_number": "+15551230000" }'
```

**JavaScript**

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

**Python**

```python
res = requests.post(
    "https://api.youraiconnector.com/v1/channels/whatsapp-web/connections",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"phone_number": "+15551230000"},
)
data = res.json()
```

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `phone_number` | Kyllä | Yhdistettävä WhatsApp-numero E.164-muodossa. |
| `proxy_country` | Ei | ISO 3166-1 alpha-2 -maakoodi reititysalueelle. Tunnistetaan automaattisesti numerosta, jos se jätetään pois. |
| `force_new` | Ei | Hylkää olemassa oleva istunto ja aloita uusi pariliitos. Oletusarvo on `false`. |
| `import_contacts` | Ei | Tuo laitteen olemassa olevat yhteystiedot ensimmäisellä yhteydellä. Oletusarvo on `false`. |
| `pause_ai_for_imported_contacts` | Ei | Kun tuot yhteystietoja, pidä automaattiset vastaukset keskeytettyinä niille. Oletusarvo on `true`. |
| `import_existing_chats` | Ei | Tuo olemassa oleva keskusteluhistoria (vaatii `import_contacts: true`). Oletusarvo on `false`. |

**Vastaus**

```json
{
  "success": true,
  "phone_number": "+15551230000",
  "session_id": "session-id",
  "status": "qr_pending",
  "connect_url": "https://api.youraiconnector.com/v1/channels/whatsapp-web/connect?token=eyJhbGciOi...",
  "connect_url_expires_at": 1717000000000,
  "poll_qr_path": "/v1/channels/whatsapp-web/connections/%2B15551230000/qr",
  "poll_status_path": "/v1/channels/whatsapp-web/connections/%2B15551230000/status"
}
```

### Helpoin vaihtoehto WhatsApp Webille: luovuta `connect_url`

Vastaus sisältää valmiin `connect_url`: isännöidyn sivun, joka näyttää QR-koodin, päivittää sen automaattisesti sen vaihtuessa ja vaihtaa onnistumisviestiin heti, kun numero on yhdistetty. Anna tämä linkki tilinhaltijalle (avaa se selaimessa, lähetä se heille tai näytä se QR-koodina/painikkeena) ja pyydä heitä skannaamaan se WhatsAppilla – sinun ei tarvitse hakea QR-koodia tai kysellä tilaa itse. Linkki toimii noin 30 minuuttia (`connect_url_expires_at`); jos se vanhenee ennen kuin he saavat prosessin valmiiksi, aloita uusi yhteys saadaksesi uuden linkin.

Tämä on suositeltu tapa, kun henkilö voi avata linkin. Alla olevat manuaaliset vaiheet (QR-koodin hakeminen itse, tilan kysely) on tarkoitettu integraatioille, jotka haluavat näyttää QR-koodin omassa käyttöliittymässään.

Vastaus antaa sinulle myös tarkan `poll_qr_path` ja `poll_status_path` käytettäväksi, joten sinun ei tarvitse rakentaa niitä itse.

### Vaihe 2 - Hae QR-koodi ja näytä se

```
GET /channels/whatsapp-web/connections/{phoneNumber}/qr
```

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/channels/whatsapp-web/connections/+15551230000/qr" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const phone = encodeURIComponent("+15551230000");
const res = await fetch(
  `https://api.youraiconnector.com/v1/channels/whatsapp-web/connections/${phone}/qr`,
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
// Render data.qr_data_url as an <img src> for the user to scan.
```

**Python**

```python
import urllib.parse

phone = urllib.parse.quote("+15551230000")
res = requests.get(
    f"https://api.youraiconnector.com/v1/channels/whatsapp-web/connections/{phone}/qr",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
# Render data["qr_data_url"] for the user to scan.
```

**Vastaus**

```json
{
  "success": true,
  "phone_number": "+15551230000",
  "status": "qr_pending",
  "qr_code": "2@raw-qr-payload-string...",
  "qr_data_url": "data:image/png;base64,iVBORw0KGgo...",
  "expires_at": "2026-06-10T12:05:00.000Z"
}
```

Näytä QR-koodi käyttäjälle skannattavaksi puhelimella (WhatsApp > Linkitetyt laitteet > Linkitä laite):

- `qr_data_url` on käyttövalmis kuva - lisää se suoraan `<img src>`-elementtiin.
- `qr_code` on raaka sisältö, jos haluat mieluummin luoda kuvan itse.

QR-koodi on lyhytikäinen. Jos kutsut tätä heti istunnon aloittamisen jälkeen, saatat saada `404`-virheen "QR code not available yet" – odota hetki ja yritä uudelleen. Jos saat `410`-virheen ("QR code expired"), aloita yhteys alusta saadaksesi uuden koodin.

### Vaihe 3 - Kysy tilaa, kunnes yhteys on muodostettu

```
GET /channels/whatsapp-web/connections/{phoneNumber}/status
```

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/channels/whatsapp-web/connections/+15551230000/status" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const phone = encodeURIComponent("+15551230000");
const res = await fetch(
  `https://api.youraiconnector.com/v1/channels/whatsapp-web/connections/${phone}/status`,
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
// Poll until data.status === "connected" (or "open").
```

**Python**

```python
import urllib.parse

phone = urllib.parse.quote("+15551230000")
res = requests.get(
    f"https://api.youraiconnector.com/v1/channels/whatsapp-web/connections/{phone}/status",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
# Poll until data["status"] == "connected" (or "open").
```

**Vastaus**

```json
{
  "success": true,
  "phone_number": "+15551230000",
  "status": "connected",
  "has_qr": false,
  "qr_expires_at": null,
  "last_activity": null,
  "message_count": null,
  "proxy": null,
  "live": true
}
```

| `status` | Merkitys |
|---|---|
| `not_initialized` | Ei istuntoa vielä (päätevirhe). |
| `qr_pending` | Odotetaan QR-koodin skannausta. |
| `connecting` | Skannattu, viimeistellään asetuksia. |
| `connected` / `open` | Linkitetty ja aktiivinen - tämä on onnistuminen. |
| `disconnected` | Istunto päättyi (päätevirhe). |

### Katkaise WhatsApp Web -istunto

```
DELETE /channels/whatsapp-web/connections/{phoneNumber}
```

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/channels/whatsapp-web/connections/+15551230000" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Vastaus**

```json
{ "success": true, "phone_number": "+15551230000", "status": "removed" }
```

Tämä poistaa laitteen linkityksen ja katkaisee yhteyden. Se puhdistaa aina paikallisen tilan, joten se on idempotentti, vaikka taustalla oleva istunto olisi jo poistunut.

---

## Telegram

> **Saatavuus:** Telegram yhdistetään kuten mikä tahansa muu kanava ja se on avoin kaikille tileille — sitä ei tarvitse kytkeä päälle puolestasi. Alla olevat Telegram-päätepisteet voivat silti palauttaa `403`, jos Telegram ei sisälly tilin tilaukseen. Tällöin virheilmoitus kuuluu `"This channel is not included in your current plan. Upgrade to unlock it."`.

Telegram yhdistää henkilökohtaisen tilin puhelinnumerolla ja kertakäyttöisellä kirjautumiskoodilla (sekä kaksivaiheisella salasanalla, jos sellainen on määritetty tilille). Prosessi on seuraava: aloita istunto, lähetä koodi, lähetä tarvittaessa salasana ja vahvista tila.

### Vaihe 1 - Aloita Telegram-yhteysistunto

```
POST /channels/telegram/connect
```

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/telegram/connect?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "phone_number": "+14155550100" }'
```

**JavaScript**

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

**Python**

```python
res = requests.post(
    "https://api.youraiconnector.com/v1/channels/telegram/connect",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"phone_number": "+14155550100"},
)
data = res.json()
```

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `phone_number` | Kyllä | Yhdistettävän tilin puhelinnumero E.164-muodossa. |
| `mode` | Ei | `code` (oletus) lähettää tilille kertakäyttöisen kirjautumiskoodin; `qr` palauttaa kirjautumistunnisteen ja QR-URL-osoitteen näytettäväksi. |
| `proxy_country` | Ei | ISO 3166-1 alpha-2 -maakoodi lähtevän verkon reititystä varten. |
| `force_new` | Ei | Kun `true`, hylkää olemassa olevan istunnon ja aloittaa alusta. |

**Vastaus**

```json
{
  "success": true,
  "phone_number": "+14155550100",
  "status": "code_required",
  "session_id": "session-id",
  "connect_url": "https://api.youraiconnector.com/v1/channels/telegram/connect/page?token=eyJhbGciOi...",
  "connect_url_expires_at": 1717000000000
}
```

`code`-tilassa tili vastaanottaa kirjautumiskoodin Telegramissa ja `status` on `code_required`. (`qr`-tilassa vastaus sisältää myös `login_token` ja `qr_url` skannausta varten, ja `status` on `qr_required`.)

### Helpoin vaihtoehto Telegramille: luovuta `connect_url`

Vastaus sisältää valmiin `connect_url`: isännöidyn sivun, joka viimeistelee yhteyden itsenäisesti. `code`-tilassa tilin omistaja syöttää kirjautumiskoodin – sekä kaksivaiheisen vahvistuksen salasanan, jos tilillä on sellainen. `qr`-tilassa sivu näyttää QR-koodin, joka päivittyy automaattisesti, jotta käyttäjä voi skannata sen Telegram-sovelluksella. Kummassakin tapauksessa sivu ilmoittaa onnistumisesta itse, joten voit vain antaa tämän linkin tilin omistajalle sen sijaan, että rakentaisit oman käyttöliittymän ja tekisit kyselyitä. Linkki toimii noin 30 minuuttia (`connect_url_expires_at`); jos se vanhenee, aloita uusi yhteys saadaksesi uuden linkin.

Alla olevat manuaaliset vaiheet (koodin kerääminen itse, sen lähettäminen ja tilan kysely; tai `qr_url`-sivun näyttäminen ja kysely) on tarkoitettu integraatioille, jotka haluavat näyttää käyttöliittymän itse.

### Vaihe 2 - Lähetä kirjautumiskoodi

```
POST /channels/telegram/connect/{phoneNumber}/verify-code
```

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/telegram/connect/+14155550100/verify-code" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "code": "12345" }'
```

**JavaScript**

```javascript
const phone = encodeURIComponent("+14155550100");
const res = await fetch(
  `https://api.youraiconnector.com/v1/channels/telegram/connect/${phone}/verify-code`,
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ code: "12345" }),
  }
);
const data = await res.json();
```

**Python**

```python
import urllib.parse

phone = urllib.parse.quote("+14155550100")
res = requests.post(
    f"https://api.youraiconnector.com/v1/channels/telegram/connect/{phone}/verify-code",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"code": "12345"},
)
data = res.json()
```

**Vastaus**

```json
{
  "success": true,
  "phone_number": "+14155550100",
  "status": "connected",
  "telegram_user_id": "100000001",
  "username": "myhandle"
}
```

Jos `status` on `connected`, olet valmis. Jos tilillä on kaksivaiheinen todennus käytössä, `status` on sen sijaan `password_required` – siirry vaiheeseen 3.

### Vaihe 3 - Lähetä kaksivaiheinen salasana (vain tarvittaessa)

```
POST /channels/telegram/connect/{phoneNumber}/verify-password
```

Kutsu tätä vain, kun vaihe 2 palautti `password_required`.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/telegram/connect/+14155550100/verify-password" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "password": "the-2fa-password" }'
```

**JavaScript**

```javascript
const phone = encodeURIComponent("+14155550100");
const res = await fetch(
  `https://api.youraiconnector.com/v1/channels/telegram/connect/${phone}/verify-password`,
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ password: "the-2fa-password" }),
  }
);
const data = await res.json();
```

**Python**

```python
import urllib.parse

phone = urllib.parse.quote("+14155550100")
res = requests.post(
    f"https://api.youraiconnector.com/v1/channels/telegram/connect/{phone}/verify-password",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"password": "the-2fa-password"},
)
data = res.json()
```

**Vastaus**

```json
{
  "success": true,
  "phone_number": "+14155550100",
  "status": "connected",
  "telegram_user_id": "100000001",
  "username": "myhandle"
}
```

### Tarkista Telegramin tila

```
GET /channels/telegram/connect/{phoneNumber}/status
```

```bash
curl "https://api.youraiconnector.com/v1/channels/telegram/connect/+14155550100/status" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Vastaus**

```json
{
  "success": true,
  "phone_number": "+14155550100",
  "status": "connected",
  "telegram_user_id": "100000001",
  "live": true
}
```

`status` voi olla `connected`, `code_required`, `password_required`, `initializing`, `disconnected`, `not_initialized` tai `error`.

### Katkaise Telegram-yhteys

```
DELETE /channels/telegram/{phoneNumber}
```

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/channels/telegram/+14155550100" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Vastaus**

```json
{ "success": true, "phone_number": "+14155550100", "status": "removed" }
```

Idempotentti – toistuvat kutsut onnistuvat.

---

## Instagram (henkilökohtainen tili)

> Rajoitetun saatavuuden beta-ominaisuus, joka otetaan käyttöön tili kerrallaan. Tämä yhdistää henkilökohtaisen Instagram-tilin kirjautumalla sisään sen käyttäjätunnuksella ja salasanalla (ei virallisen Business API:n kautta). Jos tiliä ei ole otettu käyttöön beta-versiota varten, yhteyskutsu palauttaa käyttöoikeusvirheen.

Koska tämä vaatii tilinhaltijan oman Instagram-kirjautumisen, yksinkertaisin tapa on antaa heille isännöity `connect_url` ja antaa heidän syöttää tunnistetietonsa siellä – integraatiosi ei koskaan käsittele salasanaa.

### Vaihe 1 - Aloita Instagram (henkilökohtainen) -yhteys

```
POST /channels/instagram-private/connect
```

Lähetä Instagram `username` ja `password`.

**Vastaus**

```json
{
  "success": true,
  "status": "connected",
  "connect_url": "https://api.youraiconnector.com/v1/channels/instagram-private/connect/page?token=eyJhbGciOi...",
  "connect_url_expires_at": 1717000000000
}
```

Jos tilillä on kaksivaiheinen todennus tai Instagram esittää tarkistuspisteen, `status` palautuu muodossa `two_factor_required` tai `challenge_required` – lähetä koodi alla olevaan `/connect/{id}/verify-2fa`- tai `/connect/{id}/verify-challenge`-kohtaan ja kysy sitten `/connect/{id}/status`-tilaa, kunnes `connected`. `{id}` on normalisoitu Instagram-käyttäjänimi, joka palautetaan vastauksessa muodossa `account_id`/`username` – käytä sitä jokaisessa alla olevassa vaiheessa.

### Vaihe 2 – Lähetä kaksivaiheisen todennuksen koodi (jos pyydetty)

```
POST /channels/instagram-private/connect/{id}/verify-2fa
```

Kutsu tätä vain, kun vaihe 1 (tai vaihe 3) palautti `two_factor_required`.

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/instagram-private/connect/yourbrand/verify-2fa" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "code": "123456" }'
```

**Vastaus**

```json
{
  "success": true,
  "account_id": "yourbrand",
  "status": "connected",
  "ig_user_id": "17890000000000000",
  "username": "yourbrand"
}
```

`status` voi palautua muodossa `connected` (valmis), `two_factor_required` (väärä koodi, yritä uudelleen) tai `challenge_required` (Instagram vaatii myös tarkistuspistekoodin – siirry vaiheeseen 3).

### Vaihe 3 – Lähetä tarkistuspisteen vahvistuskoodi (jos pyydetty)

```
POST /channels/instagram-private/connect/{id}/verify-challenge
```

Kutsu tätä vain, kun edellinen vaihe palautti `challenge_required`. Sama pyynnön ja vastauksen muoto kuin yllä olevassa vaiheessa 2.

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/instagram-private/connect/yourbrand/verify-challenge" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "code": "123456" }'
```

### Tarkista Instagram-tili (henkilökohtainen) tila

```
GET /channels/instagram-private/connect/{id}/status
```

Kysy tätä, kunnes `status` on `connected` tai kunnes se raportoi lopullisesta virheestä.

```bash
curl "https://api.youraiconnector.com/v1/channels/instagram-private/connect/yourbrand/status" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Vastaus**

```json
{
  "success": true,
  "account_id": "yourbrand",
  "status": "connected",
  "ig_user_id": "17890000000000000",
  "username": "yourbrand",
  "live": true
}
```

`status` voi olla `connected`, `two_factor_required`, `challenge_required`, `initializing`, `disconnected`, `not_initialized` tai `error`. `live: true` tarkoittaa, että tämä luettiin suoraan yhteystyöntekijältä (connection worker) välimuistiin tallennetun arvon sijaan.

### Helpoin vaihtoehto Instagramille (henkilökohtainen): luovuta `connect_url`

Vastaus sisältää `connect_url`: isännöidyn sivun, jossa tilinhaltija syöttää Instagram-käyttäjätunnuksensa ja salasanansa (sekä 2FA- tai tarkistuspistekoodin, jos Instagram sitä pyytää), ja joka ilmoittaa onnistumisesta automaattisesti. Tunnistetiedot menevät suoraan Instagramiin, eikä niitä tallenneta. Anna tämä linkki tilinhaltijalle sen sijaan, että keräisit heidän salasanansa omassa käyttöliittymässäsi. Linkki toimii noin 30 minuuttia (`connect_url_expires_at`).

### Katkaise Instagram-yhteys (henkilökohtainen)

```
DELETE /channels/instagram-private/{id}
```

Idempotentti – toistuvat kutsut onnistuvat.

### Seuraajien synkronointi

```
POST /channels/instagram-private/{id}/sync-followers
```

Käynnistää manuaalisesti seuraajien synkronoinnin yhdistetylle tilille – sama työ, joka suoritetaan automaattisesti taustalla, on tässä käytettävissä tarvittaessa suoritettavana "Päivitä seuraajat" -toimintona. Se hakee tilin nykyisen seuraajaluettelon, tallentaa uudet seuraajat ja (kun Live-kampanjassa on seuraajien tavoittaminen käytössä) lähettää uusille seuraajille aloitusviestin päivittäiseen rajaan asti.

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/instagram-private/yourbrand/sync-followers" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Vastaus**

```json
{
  "success": true,
  "accountId": "yourbrand",
  "totalFollowers": 1204,
  "newFollowers": 6,
  "dmsSent": 6,
  "isBaselineSeed": false
}
```

> Nämä viisi kenttää ovat sivun ainoa kohta, joka palauttaa `camelCase` arvon `snake_case` sijaan – näin tämä päätepiste on nykyään toteutettu, kyseessä ei ole kirjoitusvirhe. `isBaselineSeed: true` tarkoittaa, että kyseessä oli ensimmäinen synkronointi yhdistämisen jälkeen, jolloin tallennetaan vain alkuperäinen seuraajaluettelo eikä koskaan lähetetä tavoittavia suoria viestejä (joten `dmsSent` on kyseisellä ajokerralla aina `0`).

Tilin ensimmäinen kutsu voi kestää jonkin aikaa (koko seuraajaluettelon läpikäynti); myöhemmät kutsut ovat nopeampia, koska vain uudet seuraajat tarkistetaan. `404` tarkoittaa, että tiliä ei ole yhdistetty; `412` tarkoittaa, että yhdistämisen alustus on vielä kesken – odota ja yritä uudelleen.

---

## LINE

LINE on yksinkertaisin kanava yhdistettäväksi, koska se ei vaadi selaimen uudelleenohjausta tai kyselyä. Asiakas luo Messaging API -kanavan LINE Developers -konsolissa, kopioi kaksi arvoa, ja sinä lähetät ne yhdellä kutsulla. Annat heille sitten takaisin webhook-URL-osoitteen, joka liitetään konsoliin.

### Vaihe 1 – Yhdistä kanavan tunnistetiedoilla

```
POST /channels/line
```

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/line?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "channel_access_token": "LONG_LIVED_CHANNEL_ACCESS_TOKEN",
    "channel_secret": "CHANNEL_SECRET"
  }'
```

**JavaScript**

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

**Python**

```python
res = requests.post(
    "https://api.youraiconnector.com/v1/channels/line",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "channel_access_token": "LONG_LIVED_CHANNEL_ACCESS_TOKEN",
        "channel_secret": "CHANNEL_SECRET",
    },
)
data = res.json()
```

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `channel_access_token` | Kyllä | Virallisen tilin pitkäikäinen Messaging API -kanavan pääsytunniste. Käytetään viestien lähettämiseen ja vastaanottamiseen. |
| `channel_secret` | Kyllä | Messaging API -kanavan salaisuus, jota käytetään saapuvien tapahtumien allekirjoitusten varmentamiseen. |
| `channel_id` | Ei | Numeerinen kanavatunnus. Vain tiedoksi. |

**Vastaus**

```json
{
  "success": true,
  "status": "connected",
  "bot_user_id": "Uxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "basic_id": "@mybusiness",
  "display_name": "My Business",
  "picture_url": "https://...",
  "chat_mode": "bot",
  "chat_mode_ok": true,
  "webhook_url": "https://api.youraiconnector.com/line/webhook/..."
}
```

Kaksi kenttää ovat tärkeitä seuraavien toimenpiteiden kannalta:

- **`webhook_url`** – asiakkaan on liitettävä tämä LINE-kanavansa **Webhook URL** -kenttään LINE Developers -konsolissa (ja otettava käyttöön "Use webhook"). Ennen kuin he tekevät niin, saapuvia viestejä ei tule. Näytä tämä heille selkeästi.
- **`chat_mode_ok`** – kun `false`, virallinen tili on "chat"-tilassa eikä se vastaanota tai lähetä viestejä, ennen kuin se vaihdetaan "bot"-tilaan LINE Official Account Managerissa. Aseta käyttöönoton ehdoksi tämä lippu ja kehota asiakasta vaihtamaan tilaa.

> `channel_access_token` ja `channel_secret` eivät palaa missään päätepisteessä. Tallenna ne omalle puolellesi, jos tarvitset niitä uudelleen; muussa tapauksessa liitä ne uudelleen LINE-konsolista.

Tässä palautettu `bot_user_id` on yhteystunniste, jota käytät alla olevissa tila-, varmistus- ja katkaisukutsuissa.

### Vaihe 2 – Vahvista uudelleen webhook-asetusten jälkeen

```
POST /channels/line/{botUserId}/verify-webhook
```

Kun asiakas on määrittänyt webhook-URL-osoitteen ja vaihtanut bottitilaan, kutsu tätä tallennetun tunnisteen uudelleenvalidointia ja välimuistissa olevan chattilan päivittämistä varten.

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/line/Uxxxxxxxx.../verify-webhook" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Vastaus**

```json
{
  "success": true,
  "token_valid": true,
  "chat_mode": "bot",
  "chat_mode_ok": true,
  "webhook_url": "https://api.youraiconnector.com/line/webhook/..."
}
```

Jos `token_valid` on `false`, tallennettu pääsytunniste ei enää todenna - pyydä asiakasta luomaan se uudelleen konsolissa ja kutsumaan `POST /channels/line` uudelleen uudella tunnisteella.

### Tarkista LINE-tila

```
GET /channels/line/{botUserId}/status
```

```bash
curl "https://api.youraiconnector.com/v1/channels/line/Uxxxxxxxx.../status" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Vastaus**

```json
{
  "success": true,
  "bot_user_id": "Uxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "channel": "line",
  "status": "connected",
  "basic_id": "@mybusiness",
  "display_name": "My Business",
  "picture_url": "https://...",
  "chat_mode": "bot",
  "is_active": true,
  "live": false
}
```

LINE-palvelulla ei ole reaaliaikaista tilafeediä, joten `live` on tässä aina `false` - arvot heijastavat tilaa, joka oli voimassa yhdistämishetkellä (tai viimeisimmän vahvistuksen yhteydessä).

### Katkaise LINE-yhteys

```
DELETE /channels/line/{botUserId}
```

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/channels/line/Uxxxxxxxx..." \
  -H "X-API-Key: YOUR_API_KEY"
```

**Vastaus**

```json
{ "success": true, "status": "removed", "bot_user_id": "Uxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }
```

---

## Viber

Viber yhdistetään samalla tavalla kuin LINE – liitä botin todennustunnus Viberin hallintapaneelista yhdessä kutsussa – yhdellä huomionarvoisella erolla: yhdistäminen myös REKISTERÖI webhookimme botillesi välittömästi, joten erillistä konsolivaihetta ei tarvita. Tämä tarkoittaa myös sitä, että yhdistämisyritys voi epäonnistua, jos sisääntulomme ei pysty vastaamaan Viberin synkroniseen webhook-tarkistukseen, ei vain silloin, jos itse tunnus on väärä.

### Vaihe 1 – Yhdistä botin todennustunnuksella

```
POST /channels/viber
```

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `auth_token` | Kyllä | Botin todennustunnus Viberin hallintapaneelista (My Bot Settings). |

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

**Vastaus**

```json
{
  "success": true,
  "status": "connected",
  "bot_id": "botIdFromViber",
  "bot_name": "My Business Bot",
  "bot_avatar": "https://...",
  "bot_uri": "mybusinessbot",
  "subscribers_count": 0,
  "webhook_url": "https://api.youraiconnector.com/v1/incoming-viber-message/...",
  "event_types": ["delivered", "seen", "failed", "subscribed", "unsubscribed", "conversation_started"]
}
```

Todennustunnusta ei koskaan palauteta missään päätepisteessä – tallenna se omalle puolellesi, jos joudut liittämään sen uudelleen. `bot_id` on yhteystunniste, jota käytetään alla olevissa tila-, vahvistus- ja katkaisukutsuissa.

### Tarkista Viberin tila

```
GET /channels/viber/{botId}/status
```

Raportoi tallennetun yhteyden tilan. Lisää `?live=true`, jos haluat myös tarkistaa botin Viberiä vasten ja päivittää välimuistiin tallennetun webhook-rekisteröinnin – hyödyllistä ennen kuin oletat, että hiljainen botti on todella rikki.

```bash
curl "https://api.youraiconnector.com/v1/channels/viber/botIdFromViber/status?live=true" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Vastaus**

```json
{
  "success": true,
  "bot_id": "botIdFromViber",
  "channel": "viber",
  "status": "connected",
  "bot_name": "My Business Bot",
  "bot_avatar": "https://...",
  "bot_uri": "mybusinessbot",
  "webhook_url": "https://api.youraiconnector.com/v1/incoming-viber-message/...",
  "registered_webhook": "https://api.youraiconnector.com/v1/incoming-viber-message/...",
  "webhook_ok": true,
  "subscribers_count": 128,
  "is_active": true,
  "live": true
}
```

`webhook_ok: false` tarkoittaa, että botin webhook ei enää osoita meihin – saapuvat viestit eivät tule perille. Tämä tarkoittaa yleensä sitä, että jokin toinen työkalu on yhdistänyt saman botin sen jälkeen (Viberin webhook-rekisteröinnissä viimeisin kirjoitus voittaa). Korjaa se alla olevalla uudelleenvahvistuskutsulla; asiakasta ei tarvitse pyytää liittämään tunnustaan uudelleen. `live` on `false`, kun vastaus on viimeisin välimuistiin tallennettu tila eikä tuore tarkistus Viberiä vasten.

### Rekisteröi webhook uudelleen

```
POST /channels/viber/{botId}/verify-webhook
```

Korjaustoiminto `webhook_ok: false`-virheelle – rekisteröi webhookimme uudelleen botille käyttäen jo tallennettua todennustunnusta.

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/viber/botIdFromViber/verify-webhook" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Vastaus**

```json
{ "success": true, "token_valid": true, "webhook_ok": true, "webhook_url": "https://api.youraiconnector.com/v1/incoming-viber-message/...", "event_types": ["delivered", "seen", "failed", "subscribed", "unsubscribed", "conversation_started"] }
```

`token_valid: false` tarkoittaa, että tallennettu tunnus ei enää toimi – yhdistä uudelleen käyttämällä `POST /channels/viber`-toimintoa ja uutta tunnusta.

### Katkaise Viber-yhteys

```
DELETE /channels/viber/{botId}
```

Poistaa webhookimme rekisteröinnin Viberin puolelta (parhaan kyvyn mukaan) ja poistaa yhteyden.

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/channels/viber/botIdFromViber" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Vastaus**

```json
{ "success": true, "status": "removed", "bot_id": "botIdFromViber", "webhook_removed": true }
```

---

## TikTok

> **Saatavuus:** Rajoitetun saatavuuden beta, otetaan käyttöön tili kerrallaan. TikTokin yhdistäminen palauttaa käyttöoikeusvirheen, kunnes tili on otettu käyttöön sitä varten.

TikTok Business Messaging on täysimittainen OAuth-kanava kuten Meta, mutta kyselyn osalta yksinkertaisempi: siinä ei ole erillistä tilan kyselyvaihetta, jota vasten rakentaa, koska yhdistetty tili näkyy itsestään heti, kun TikTok ohjaa takaisin ja yhteys on kirjoitettu. Alla oleva tila-päätepiste on olemassa tilan vahvistamiseksi tarvittaessa (tukityökalut, kuntotarkistukset), ei jotain, jota sinun tarvitsee toistaa yhdistämisen aikana.

### Vaihe 1 - Aloita TikTok-yhteys

```
POST /channels/tiktok/connect
```

Ei vaadi tunnistetietoja – tilinhaltija valtuuttaa yhteyden kokonaan selaimessaan.

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/tiktok/connect?apiKey=YOUR_API_KEY"
```

**Vastaus**

```json
{
  "success": true,
  "status": "pending_authorization",
  "oauth_url": "https://www.tiktok.com/v2/auth/authorize?client_key=...&state=...",
  "state_token": "opaque-one-time-token",
  "expires_at": "2026-06-10T12:30:00.000Z"
}
```

Avaa `oauth_url` tilinhaltijan selaimessa, jotta hän voi kirjautua TikTokiin ja hyväksyä pääsyn. Tila vanhenee kohdassa `expires_at` (noin 30 minuuttia) – jos se vanhenee, aloita alusta. TikTokille ei ole `connect_url`-isännöityä sivu-oikotietä; `oauth_url` avaaminen itse on ainoa tapa.

### Tarkista TikTokin tila

```
GET /channels/tiktok/{openId}/status
```

`openId` on TikTok Business -tilin open_id, joka tiedetään, kun OAuth-takaisinkutsu on suoritettu.

```bash
curl "https://api.youraiconnector.com/v1/channels/tiktok/openIdFromTikTok/status" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Vastaus**

```json
{
  "success": true,
  "open_id": "openIdFromTikTok",
  "channel": "tiktok",
  "status": "connected",
  "business_id": "openIdFromTikTok",
  "username": "mybusiness",
  "display_name": "My Business",
  "avatar_url": "https://...",
  "status_reason": null,
  "is_active": true,
  "live": false
}
```

TikTokilla ei ole edullista reaaliaikaista kuntotarkistusta, joten `live` on tässä aina `false` – kentät heijastavat sitä, mitä yhdistäminen (tai viimeisin tunnisteen päivitys) kirjoitti. `status: "reauth_required"`, jossa on `status_reason` asetettuna, tarkoittaa, että tilin on käytävä yhdistämisprosessi uudelleen läpi; TikTok-tunnisteet päivitetään automaattisesti vuosittain, ja tämä näkyy, jos kyseinen päivitys epäonnistuu.

### Katkaise TikTok-yhteys

```
DELETE /channels/tiktok/{openId}
```

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/channels/tiktok/openIdFromTikTok" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Vastaus**

```json
{ "success": true, "status": "removed", "open_id": "openIdFromTikTok" }
```

---

## GoHighLevel

GoHighLevel (GHL) on CRM-integraatio, ei viestintäkanava – sen yhdistäminen ei kuluta tilauksen kanavapaikkaa, koska se hyödyntää tilin olemassa olevia kanavia uuden lisäämisen sijaan. Se on myös tämän sivun ainoa integraatio, joka voi pitää **useamman kuin yhden yhteyden kerrallaan**: jokainen GHL-alatili ("sijainti"), johon asiakas asentaa sovelluksen, saa oman merkintänsä.

### Vaihe 1 - Aloita GHL-yhteys

```
POST /channels/ghl/connect
```

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `brand` | Ei | Mikä GHL-markkinapaikkaluettelo valtuutetaan. Oletusarvona on vakioluettelo – tämä on merkityksellinen vain, jos käyttöönotossasi on määritetty useampi kuin yksi markkinapaikkasovellus. |

```bash
curl -X POST "https://api.youraiconnector.com/v1/channels/ghl/connect?apiKey=YOUR_API_KEY"
```

**Vastaus**

```json
{
  "success": true,
  "status": "pending_authorization",
  "oauth_url": "https://marketplace.gohighlevel.com/oauth/chooselocation?client_id=...&state=...",
  "state_token": "opaque-one-time-token",
  "brand": "dmchamp",
  "expires_at": "2026-06-10T12:30:00.000Z"
}
```

Avaa `oauth_url` tilinhaltijan selaimessa, jotta hän voi valita GHL-sijainnin ja hyväksyä pääsyn. Tila vanhenee kohdassa `expires_at` (noin 30 minuutin kuluttua).

### Listaa GHL-yhteydet

```
GET /channels/ghl/status
```

Toisin kuin muut kanavat, tämä ei ole yksittäisen yhteyden tila – se listaa jokaisen sijainnin, jonka tili on yhdistänyt.

```bash
curl "https://api.youraiconnector.com/v1/channels/ghl/status" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Vastaus**

```json
{
  "success": true,
  "connections": [
    {
      "location_id": "abc123location",
      "company_id": "xyz789company",
      "brand": "dmchamp",
      "status": "connected",
      "status_reason": null,
      "scopes": ["conversations.readonly", "conversations.write", "conversations/message.write"],
      "connected_at": "2026-06-01T10:00:00.000Z",
      "conversation_provider_id": "provider-id-in-ghl",
      "trigger_subscriptions": [
        { "id": "sub_1", "key": "InboundMessage", "workflow_id": "wf_123" }
      ]
    }
  ]
}
```

### Katkaise GHL-sijainnin yhteys

```
DELETE /channels/ghl/{locationId}
```

Poistaa yhteyden täältä, mikä pysäyttää jokaisen kyseisen sijainnin synkronoinnin ja käynnistimen. Tämä ei poista sovellusta GHL-puolelta – asiakas poistaa sen GHL-markkinapaikan asennuksistaan, jos hän haluaa myös sen tapahtuvan.

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/channels/ghl/abc123location" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Vastaus**

```json
{ "success": true, "status": "disconnected", "location_id": "abc123location" }
```

---

## Puhelinnumerot (osto ja vapauttaminen)

Olemassa olevan numeron yhdistämisen sijaan voit ostaa uuden WhatsApp-yhteensopivan numeron suoraan. Etsi saatavilla olevia numeroita, osta yksi ja kysy tilaa toistuvasti, kunnes sen provisiointi on valmis.

::: note
**Huomautus:** Täältä ostetut numerot tukevat WhatsAppia. WhatsApp-lähettäjän rekisteröinti tapahtuu taustalla ostoksen jälkeen, joten tarkista tilaa kyselyillä, kunnes se saavuttaa tilan `ONLINE` ennen viestien lähettämistä. Hyvitykset vähennetään ostoksen yhteydessä, eikä niitä **palauteta**, kun vapautat numeron.
:::


### Vaihe 1 - Etsi saatavilla olevia numeroita

```
GET /phone-numbers/available?country_code=ISO2
```

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/phone-numbers/available?country_code=US&apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.youraiconnector.com/v1/phone-numbers/available?country_code=US",
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
```

**Python**

```python
res = requests.get(
    "https://api.youraiconnector.com/v1/phone-numbers/available",
    params={"country_code": "US"},
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
```

| Kyselyparametri | Pakollinen | Kuvaus |
|---|---|---|
| `country_code` | Kyllä | ISO 3166-1 alpha-2 -maakoodi, josta etsitään (esim. `US`, `GB`, `NL`). |
| `type` | Ei | Ensisijainen numeroluokka, `local` tai `mobile`. Molempia luokkia saatetaan silti palauttaa. |

**Vastaus**

```json
{
  "success": true,
  "phone_numbers": [
    {
      "phone_number": "+14155551234",
      "purchase_credits": 50,
      "monthly_credits": 50,
      "cost_usd": 1.15
    }
  ]
}
```

Jokainen tulos näyttää kertaluonteisen `purchase_credits` ja toistuvan `monthly_credits`. Alustan tarjoama numero maksaa vähintään 50 krediittiä kuukaudessa, ja hinta nousee operaattorin oman kuukausihinnan mukaan. Maksu peritään ostohetkellä ja jokaisen uusimisen yhteydessä. Käytä hakutuloksena saatua `purchase_credits` / `monthly_credits`; älä koskaan laske hintaa itse. Ensimmäinen haku uudella tilillä varaa taustaresursseja, joten se voi olla hieman hitaampi kuin myöhemmät haut.

### Vaihe 2 - Osta numero

```
POST /phone-numbers
```

Käytä `phone_number` hakutuloksista.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/phone-numbers" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": "+14155551234",
    "country_code": "US",
    "display_name": "Support line"
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/phone-numbers", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    phone_number: "+14155551234",
    country_code: "US",
    display_name: "Support line",
  }),
});
const data = await res.json();
```

**Python**

```python
res = requests.post(
    "https://api.youraiconnector.com/v1/phone-numbers",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "phone_number": "+14155551234",
        "country_code": "US",
        "display_name": "Support line",
    },
)
data = res.json()
```

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `phone_number` | Kyllä | Saatavilla olevien numeroiden haun palauttama numero E.164-muodossa. |
| `country_code` | Kyllä | ISO 3166-1 alpha-2 -maakoodi (esim. `US`). |
| `display_name` | Ei | Käyttäjäystävällinen nimi. Oletuksena puhelinnumero. |
| `category` | Ei | Valinnainen luokkanimi. |

**Vastaus**

```json
{
  "success": true,
  "phone_number": "+14155551234",
  "channel": "whatsapp",
  "whatsapp_status": "PURCHASED",
  "outgoing_status": "PURCHASED",
  "status": "PURCHASED",
  "purchase_credits": 50,
  "monthly_credits": 50
}
```

Numero alkaa tilasta `PURCHASED`. WhatsApp-rekisteröinti jatkuu taustalla: `PURCHASED` -> `PENDING` -> `ONLINE`.

> Jos osto epäonnistuu, koska yrityksen osoite puuttuu tai jokin muu vaadittu tieto ei ole asetettu, saat `400`-vastauksen, jossa on kuvaava `error`. Määritä puuttuva tieto ja yritä uudelleen.

### Vaihe 3 - Kysely kunnes tila on ONLINE

```
GET /phone-numbers/{phoneNumber}/status
```

Tämä on jaettu puhelinnumeron tila-päätepiste – se toimii sekä ostetuille WhatsApp-numeroille että muille yhdistetyille numeroillesi.

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/phone-numbers/+14155551234/status" \
  -H "X-API-Key: YOUR_API_KEY"
```

**JavaScript**

```javascript
const phone = encodeURIComponent("+14155551234");
const res = await fetch(
  `https://api.youraiconnector.com/v1/phone-numbers/${phone}/status`,
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
// Poll until data.status === "ONLINE".
```

**Python**

```python
import urllib.parse

phone = urllib.parse.quote("+14155551234")
res = requests.get(
    f"https://api.youraiconnector.com/v1/phone-numbers/{phone}/status",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
# Poll until data["status"] == "ONLINE".
```

**Vastaus**

```json
{
  "success": true,
  "phone_number": "+14155551234",
  "channel": "whatsapp",
  "status": "ONLINE",
  "status_reason": null,
  "live": true
}
```

### Vaihe 4 - Vapauta numero

```
DELETE /phone-numbers/{phoneNumber}
```

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/phone-numbers/+14155551234" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Vastaus**

```json
{ "success": true, "phone_number": "+14155551234", "released": true }
```

Se, mitä tämä tekee, riippuu siitä, kenen numero on kyseessä.

Jos kyseessä on **alustan kautta vuokrattu** numero, kyseessä on todellinen vapauttaminen: WhatsApp-lähettäjän rekisteröinti poistetaan, numero palautetaan operaattorille ja poistetaan tililtä. Käytössä on 7 päivän jäähtymisaika, jonka aikana kukaan ei voi ostaa numeroa uudelleen, eikä hyvityksiä myönnetä.

Jos kyseessä on numero, **jonka tili toi itse** (oma Twilio-tili, oma Meta-sovellus tai WhatsApp Business -tili tai Android SMS -yhdyskäytävä), sama kutsu vain poistaa sen tililtä. Mitään ei vapauteta ylävirran palveluntarjoajalla eikä jäähtymisaikaa aseteta, joten numero voidaan yhdistää uudelleen välittömästi. Sen WhatsApp-lähettäjän rekisteröinti, jos sellainen oli, saattaa säilyä tai olla säilymättä: purkutoiminto yrittää poistaa lähettäjän käyttämällä tilin alustahallittuja Twilio-tunnistetietoja. Tilillä, joka on edelleen hallitussa asetuksessa, nuo tunnistetiedot ovat voimassa ja lähettäjä poistetaan, joten uudelleenyhdistäminen tarkoittaa sen rekisteröimistä uudelleen. Tilillä, joka on vaihtanut omaan Twilioon, poisto ei voi todentaa, ja lähettäjä jää rekisteröidyksi kyseiselle tilille – uudelleenyhdistäminen on tällöin vain olemassa olevan lähettäjän liittäminen takaisin.

### Lisää numero, jonka jo omistat (BYO)

```
POST /phone-numbers/byo
```

Ohittaa yllä olevan haku- ja ostoprosessin kokonaan. Käytä tätä, kun tili tuo oman numeronsa (oma Twilio, oma Meta WhatsApp Business -tili tai Android SMS -yhdyskäytävä) sen sijaan, että vuokraisit sellaisen alustan kautta. Tämä vain tallentaa numeron – krediittejä ei veloiteta, eikä mitään tarjota palveluntarjoajan kautta tässä vaiheessa. Numero pysyy epäaktiivisena, kunnes tilinhaltija suorittaa WhatsApp OAuth -rekisteröinnin lähettäjälle (sama prosessi, jonka kojelaudan "Bring your own number" -painike käynnistää).

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `phone_number` | Kyllä | Lisättävä numero E.164-muodossa (esim. `+14155551234`). |
| `country_code` | Kyllä | ISO 3166-1 alpha-2 -maakoodi (esim. `US`). |
| `display_name` | Ei | Käyttäjäystävällinen nimi. Oletusarvona on puhelinnumero. |
| `category` | Ei | Valinnainen luokkatunniste. |

```bash
curl -X POST "https://api.youraiconnector.com/v1/phone-numbers/byo?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": "+14155551234",
    "country_code": "US",
    "display_name": "Support line"
  }'
```

**Vastaus** (`201 Created`):

```json
{
  "success": true,
  "phone_number": "+14155551234",
  "channel": "whatsapp",
  "type": "BYO",
  "whatsapp_status": "ADDED",
  "outgoing_status": "ADDED",
  "is_active": false
}
```

`phone_number`, joka ei ole oikea E.164-numero (tai joka näyttää Metan WhatsApp-testinumerolta, jolla ei voi viestiä oikeille asiakkaille), palauttaa `400`. Sellaisen numeron lisääminen, joka on jo tilillä – vaikka se olisi kirjoitettu hieman eri tavalla, kuten Meksikon `+52` vs `+521` -muodot – palauttaa `409` sen sijaan, että luotaisiin päällekkäinen rivi.

### Aseta numero ensisijaiseksi

```
POST /phone-numbers/{phoneNumber}/set-primary
```

Muuttaa yhden numeron arvoksi `is_active: true` ja jokaisen muun tilin numeron arvoksi `is_active: false` atomisesti – tili ei koskaan päädy tilanteeseen, jossa on kaksi aktiivista numeroa tai ei yhtään pyynnön aikana. `is_active` ei voi asettaa yleisen päivityspäätepisteen kautta tarkoituksella; tämä erillinen kutsu on ainoa tapa muuttaa ensisijaista numeroa.

```bash
curl -X POST "https://api.youraiconnector.com/v1/phone-numbers/+14155551234/set-primary" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Vastaus**

```json
{
  "success": true,
  "phone_number": {
    "id": "+14155551234",
    "phone_number": "+14155551234",
    "display_name": "Support line",
    "channel": "whatsapp",
    "is_active": true,
    "whatsapp_status": "ONLINE"
  }
}
```

`phone_number` tässä on koko numero-objekti (sama muoto, jonka `GET /phone-numbers` palauttaa), ei vain merkkijono. `phoneNumber`, jota ei ole tilillä, palauttaa `404`.

### Poista numeron tietue (ilman sen vapauttamista)

```
DELETE /phone-numbers/{phoneNumber}/record
```

Numeron tietueen yksinkertainen poisto tältä tililtä – ei palveluntarjoajan puoleista vapauttamista tai rekisteröinnin poistoa, eikä yllä mainittua 7 päivän jäähtymisaikaa sovelleta. Käytä tätä tyhjentääksesi BYO-, WhatsApp Web-, Telegram- tai LINE-tietueet tai vanhentuneet merkinnät ilman hallittua vapautusprosessia. Toisin kuin vapauttamisessa, sellaisen numeron poistaminen, jota ei ole tilillä, on `404`, ei hiljainen onnistuminen.

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/phone-numbers/+14155551234/record" \
  -H "X-API-Key: YOUR_API_KEY"
```

**Vastaus**

```json
{ "success": true, "phone_number": "+14155551234", "deleted": true }
```

---

## Kanavan reitittäminen kampanjaan

Kanavan yhdistäminen tuo viestit **tilille**. Se ei päätä, **mikä tekoälyagentti niihin vastaa**.

Reititystä hallitaan tekoälyagentin **sisääntulopisteillä** (Entry Points), ei kampanjoilla. Jokaisella kanavalla on yksi kanavakohtainen oletussisääntulopiste, joka nimeää agentin, joka vastaa kyseisen kanavan uusiin, tuntemattomiin yhteystietoihin:

| Mitä haluat tehdä | Kutsu |
|---|---|
| Osoita kanava agentille, jonka tulisi vastata siihen | `PUT /entry-points/channel-defaults` rungolla `{ "channel": "instagram", "agent_id": "AGENT_ID" }` |
| Tarkista, onko tilin sisääntulopisteiden järjestelmä käytössä | `GET /entry-points/routing-status`, joka palauttaa `{ "success": true, "cutover_enabled": true }`, kun sisääntulopisteet päättävät tilin reitityksestä |
| Jätä kanava ilman vastaavaa agenttia | `DELETE /entry-points/channel-defaults?channel=instagram` |

Ennen kuin kanavalla on sisääntulopiste (Entry Point), tuntemattoman henkilön lähettämä ensimmäinen viesti tallennetaan kyllä, mutta mikään ei käsittele sitä eikä avustaja vastaa. Tämä on vaihe, jonka useimmat integraatiot unohtavat: Instagramin yhdistäminen ja agentin luominen ei yksinään riitä – kanava on myös osoitettava kyseiselle agentille. Täydellinen luettelo kutsuista – mukaan lukien yksi agentti per WhatsApp-numero, avainsanat ja kommenttisäännöt – löytyy [Entry Points API](entry-points.md) -dokumentaatiosta.

`POST /channels/campaign` kirjoittaa edelleen vanhaa kanavakohtaista kampanjareitityskarttaa, joka on dokumentoitu alla, mutta kyseistä karttaa ei enää käytetä saapuvan liikenteen reititykseen millään tilillä; se on säilytetty vain palautusta varten. Älä rakenna sen varaan.

### Reititä yksi tai useampi kanava (vanha kampanjareitityskartta)

`POST /channels/campaign`

**Pyynnön kentät**

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `campaign_id` | Kyllä | Kampanja, jonka tulisi vastata uusiin yhteystietoihin näillä kanavilla. Täytyy kuulua tilille. |
| `channels` | Kyllä | Tyhjästä poikkeava taulukko reititettävistä kanavista. Sallitut: `whatsapp`, `whatsapp_web`, `telegram`, `instagram`, `messenger`, `chat_widget`, `custom_channel`, `sms`, `email`. |

Reitityspaikka ja kampanjan `enabled_channels`-luettelo päivitetään yhdessä yhtenä atomisena toimintona, joten ne eivät voi koskaan eriytyä toisistaan. Kanava, joka on jo reititetty toiseen kampanjaan, osoitetaan yksinkertaisesti uudelleen tähän kampanjaan.

**cURL**

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

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/channels/campaign", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    campaign_id: "NBCXrhqGPSFsd6MV7pRo",
    channels: ["instagram", "messenger"],
  }),
});
const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/channels/campaign",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "campaign_id": "NBCXrhqGPSFsd6MV7pRo",
        "channels": ["instagram", "messenger"],
    },
)
data = res.json()
```

**Vastaus**

```json
{
  "success": true,
  "campaign_id": "NBCXrhqGPSFsd6MV7pRo",
  "channels": ["instagram", "messenger"]
}
```

### Mitä reitityksen onnistuminen edellyttää

Tilillä, joka lukee edelleen vanhaa kampanjareitityskarttaa, reititys onnistuu API-kutsuna, mutta kolme kampanjan seikkaa päättää, vastataanko todelliseen saapuvaan viestiin. Tarkista kaikki kolme, jos reititetty kanava pysyy hiljaisena.

| Vaatimus | Mitä muuten tapahtuu |
|---|---|
| `type` on `Incoming from Unknown Contacts` tai `Combined` | Pyyntö hylätään virheellä `400`. Lähtevän liikenteen ja avainsanakampanjat eivät voi sisältää reitityspaikkaa. |
| `status` on `Live` | Reititys tallennetaan, mutta se ei poimi mitään. `Draft`-kampanja on yleisin syy siihen, miksi "reititin sen, mutta mitään ei tapahdu". |
| `ai_mode` on `true` | Yhteystieto luodaan ja viesti tallennetaan, mutta avustaja ei koskaan vastaa. |

Avainsanojen täsmäytys sijaitsee nyt sisääntulopisteissä — luo `keyword`-tyyppinen sisääntulopiste tekoälyagentille, jonka tulisi vastata.

### Yksi kampanja per kanava

Jokaisella kanavalla on tasan yksi vanha reitityspaikka. Toisen kampanjan reitittäminen samalle kanavalle osoittaa paikan hiljaisesti uudelleen ja palauttaa `200` — ristiriitavirhettä ei tule. Edellinen kampanja jatkaa jo olemassa olevien yhteystietojen käsittelyä; se vain lakkaa vastaanottamasta uusia.

### Tyhjennä kanavan reititys

`DELETE /channels/campaign/{channel}`

Poistaa yksittäisen kanavan reitityksen riippumatta siitä, mihin kampanjaan se tällä hetkellä osoittaa, ja poistaa kanavan kyseisen kampanjan `enabled_channels`-kohdasta. Kampanjat eivät enää poimi uusia tuntemattomia yhteystietoja kanavalta. Kampanjassa jo olevat yhteystiedot jatkavat toimintaansa entiseen tapaan.

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/channels/campaign/instagram?apiKey=YOUR_API_KEY"
```

**Vastaus**

```json
{
  "success": true,
  "channel": "instagram",
  "cleared": true,
  "campaign_id": "NBCXrhqGPSFsd6MV7pRo"
}
```

Tämä on idempotentti: sellaisen kanavan tyhjentäminen, jota ei ole koskaan reititetty, palauttaa myös `200`, sekä `cleared: false` ja `campaign_id: null`. Tämä päätepiste vaatii tilaukselta **saapuvien kampanjoiden** (incoming campaigns) ominaisuuden; ilman sitä saat `403`.


---

## Käytä omaa Meta-sovellustasi (Instagram + Messenger)

Oletusarvoisesti Instagram + Messenger -yhteys toimii alustan Meta-sovelluksen kautta, joten tilinhaltija näkee kyseisen sovelluksen nimen Facebookin suostumusnäytöllä. Jos haluat, että suostumusnäytöllä näkyy **oma** brändisi, voit rekisteröidä oman Meta-sovelluksesi ja ohjata koko kulun sen kautta. Kun se on määritetty, se koskee tiliäsi – mikään ei muutu yllä olevissa yhdistämiskutsuissa brändäystä lukuun ottamatta.

> **Tämä koskee vain Instagramia + Messengeriä.** WhatsApp-, WhatsApp Web-, Telegram- ja LINE-yhteyksiin oma Meta-sovellus ei vaikuta.

### Mitä sovelluksesi tarvitsee ensin

Tämä on osa, joka vie aikaa, ja se tapahtuu kokonaan Metan puolella:

1. **Sovellus**, joka on tyypiltään Business ja johon on lisätty Messenger- ja Instagram-tuotteet.
2. **Laajennettu käyttöoikeus** (Advanced Access, Meta App Review'n kautta) seuraaville: `pages_show_list`, `pages_messaging`, `pages_manage_metadata`, `pages_read_engagement`, `instagram_basic`, `instagram_manage_messages`. Ilman laajennettua käyttöoikeutta vain sovelluksessasi roolin omaavat henkilöt voivat suorittaa yhteyden muodostamisen – asiakkaidesi yhteydet epäonnistuvat. Sovelluksen tarkistus (App Review) kestää yleensä muutaman viikon ja vaatii yrityksen vahvistamisen (Business Verification).
3. **Facebook Login for Business -määritys**, joka on luotu sovelluksesi sisällä ja jolle on myönnetty samat käyttöoikeudet. Sen numeerinen määritystunnus (configuration ID) on sovelluskohtainen, joten sinun on luotava oma.

Jos sovelluksestasi puuttuu jokin vaadituista käyttöoikeuksista, yhteys epäonnistuu yhdistämishetkellä selkeään virheeseen, joka nimeää puuttuvan osan (näkyy `/status`-kyselyssä muodossa `byo_app_missing_permissions`) – sen sijaan, että se näyttäisi toimivan ja epäonnistuisi vasta ensimmäisessä viestissä.

### Vaihe 1 - Tallenna sovelluksesi

`PUT /account-config/meta-app`

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `app_id` | Kyllä | Meta-sovelluksesi tunnus (Asetukset → Perusasetukset). |
| `app_secret` | Kyllä | Meta-sovelluksesi salaisuus (App Secret). Vahvistetaan Metan kanssa ennen tallennusta ja salataan sen jälkeen. Ei palauteta koskaan minkään päätepisteen kautta. |
| `config_id` | Kyllä | Sovelluksesi sisäisen Facebook Login for Business -määrityksen numeerinen tunnus. |

Kaikki kolme ovat välttämättömiä Facebook-kirjautumisprosessia varten. Jos käytät vain alempana kuvattua Instagram-kirjautumisen tunnusten välitystä, voit jättää ne kokonaan pois.

```bash
curl -X PUT "https://api.youraiconnector.com/v1/account-config/meta-app?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "app_id": "1234567890123456",
    "app_secret": "your-app-secret",
    "config_id": "9876543210987654"
  }'
```

**Vastaus**

```json
{
  "success": true,
  "app_id": "1234567890123456",
  "config_id": "9876543210987654",
  "verify_token": "1f4c…a9",
  "webhook_urls": {
    "instagram": "https://api.youraiconnector.com/v1/incoming-instagram-message/byo/YOUR_ACCOUNT_ID",
    "messenger": "https://api.youraiconnector.com/v1/incoming-messenger-message/byo/YOUR_ACCOUNT_ID"
  }
}
```

### Vaihe 2 - Määritä sovelluksesi kommunikoimaan kanssamme

Meta-sovelluksesi hallintapaneelissa:

1. **Webhooks** - Aseta sekä Instagram- että Messenger-tuotteille takaisinkutsun URL-osoitteeksi (Callback URL) vastaava `webhook_urls`-arvo vastauksesta ja vahvistustunnukseksi (Verify token) `verify_token`. Tilaa kentät `messages`, `messaging_postbacks` ja `comments`.
2. **Valid OAuth Redirect URIs** - lisää `https://api.youraiconnector.com/v1/auth-meta-callback-handler`, jotta suostumusprosessi voi palata.

`GET /account-config/meta-app` palauttaa samat asetustiedot milloin tahansa; `DELETE /account-config/meta-app` poistaa sovelluksen (tulevat yhteydet palautuvat alustan sovellukseen – poista myös webhook-tilaus sovelluksesi sisällä).

### Vaihe 3 – Yhdistä tavalliseen tapaan

Mikään muu ei muutu. `POST /channels/meta/connect` (ja isännöity `connect_url`-sivu) käyttää automaattisesti sovellustasi tilisi kohdalla; vastauksen `uses_byo_meta_app: true` vahvistaa, minkä sovelluksen suostumusnäyttö näyttää. Viestien lähettäminen, sivun valinta ja yhteyden katkaiseminen toimivat samalla tavalla.

## Käytä omaa Instagram Login -sovellustasi (tunnisteen siirto)

Yllä oleva osio käsittelee Facebook-kirjautumisen kulkua, jossa tili yhdistetään Facebook-sivun kautta. Meta tarjoaa myös **Instagram API:n Instagram-kirjautumisella** (Business Login for Instagram): tilin haltija tunnistautuu suoraan Instagramissa, ilman Facebook-tiliä tai -sivua.

Jos alustallasi on jo oma Meta-sovellus kyseisellä tuotteella, et tarvitse meidän puoleltamme mitään OAuth-kulkua. Asiakkaasi valtuuttavat **sinun** sovelluksesi, ja sinä lähetät meille valmiit tunnisteet tiliä kohden:

1. Tallennat Instagram-sovelluksesi tunnisteet kerran (jotta voimme vahvistaa webhookisi).
2. Lähetät tiliä kohden Instagram-ammattilaistilin tunnisteen (ID) + sovelluksesi hankkiman pitkäikäisen Instagram-käyttäjätunnisteen.
3. Osoitat sovelluksesi Instagram-viestintäwebhookin meille. Tapahtumat tileille, joita et ole lähettänyt, kuitataan ja jätetään huomiotta.
4. Hallitset tunnisteen elinkaarta: päivitä tunnisteet omassa järjestelmässäsi ja lähetä jokainen päivitetty tunniste samalla kutsulla. Emme koskaan päivitä lähetettyä tunnistetta.

### Mitä sovelluksesi tarvitsee ensin

- **Instagram**-tuote ("API setup with Instagram login") lisättynä Meta-sovellukseesi. Tuotteella on **oma sovellustunnus (App ID) ja sovellussalaisuus (App Secret)**, jotka ovat erillään Facebookin sovellustunnuksesta/-salaisuudesta – löydät ne tuotteen asetuspaneelista.
- **Laajennettu käyttöoikeus** (Meta App Review'n kautta) kohteille `instagram_business_basic` ja `instagram_business_manage_messages` (lisää `instagram_business_manage_comments`, jos käytät kommenttiautomaatioita). Ilman tätä vain sovelluksessasi roolin omaavat henkilöt voivat valtuuttaa sen.

### Vaihe 1 - Tallenna Instagram-sovelluksesi tunnisteet

Sama päätepiste kuin edellä – lähetä Instagram-pari osoitteeseen `PUT /account-config/meta-app`. Facebook-kenttiä ei tarvita tätä reittiä varten: lähetä pari yksinään, jos käytät vain Instagram-kirjautumista, tai yhdessä Facebook-kenttien kanssa, jos käytät molempia. Tallennus kuvaa aina koko asetusta, joten se joukko, jonka jätät pois, poistetaan.

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `instagram_app_id` | Yhdessä | Instagram-tuotteen oma numeerinen sovellustunnus (ei Facebookin sovellustunnus). |
| `instagram_app_secret` | Yhdessä | Instagram-tuotteen oma sovellussalaisuus. Salattu levossa, ei palauteta koskaan. |

```bash
curl -X PUT "https://api.youraiconnector.com/v1/account-config/meta-app?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "instagram_app_id": "1122334455667788",
    "instagram_app_secret": "your-instagram-app-secret"
  }'
```

**Vastaus** – sisältää Instagram-kirjautumisen webhook-URL-osoitteen (`instagram`- ja `messenger`-URL-osoitteet näkyvät vain, kun myös Facebook-kentät on tallennettu):

```json
{
  "success": true,
  "instagram_app_id": "1122334455667788",
  "verify_token": "1f4c…a9",
  "webhook_urls": {
    "instagram_login": "https://api.youraiconnector.com/v1/incoming-instagram-login-message/byo/YOUR_ACCOUNT_ID"
  }
}
```

Aseta sovelluksesi **Webhooks**-paneelissa Instagram-tuotteen kohdalla Callback URL -osoitteeksi `webhook_urls.instagram_login`, Verify token -tunnisteeksi `verify_token` ja tilaa kentät `messages` ja `comments`.

### Vaihe 2 - Lähetä tunniste tiliä kohden

`PUT /channels/instagram-login/token`

Toimii `sub_account_id`-kohteen kanssa kuten mikä tahansa muukin reitti, joten toimistoavain voi tarjota palvelun koko asiakaskunnalleen.

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `ig_user_id` | Kyllä | **Instagram-ammattilaistilin tunniste (ID)** – `user_id`-kenttä kohteesta `GET https://graph.instagram.com/v21.0/me?fields=user_id,username`. Tämä on sama tunniste, jonka Instagram-webhookit välittävät muodossa `entry.id`. ⚠️ Se **ei** ole `id`-kenttä kohteesta `/me` – se on sovelluskohtainen ja vaihtelee Meta-sovelluksittain. Sovelluskohtaisen tunnisteen lähettäminen palauttaa `400`-virheen, joka nimeää virheen. |
| `access_token` | Kyllä | Pitkäikäinen Instagram-käyttäjätunniste, jonka sovelluksesi hankki kyseiselle tilille. Validoidaan reaaliajassa Instagramia vasten ennen tallennusta: tunnisteen on oltava toimiva ja kuuluttava kohteelle `ig_user_id`. |
| `expires_at` | Ei | Tunnisteen vanhenemisaika ISO-8601-muodossa. Vaihtoehtoisesti lähetä `expires_in` (sekunteina). Oletusarvo on 60 päivää. |
| `username` | Ei | Tilin @käyttäjänimi; luemme sen joka tapauksessa Instagramista. |

```bash
curl -X PUT "https://api.youraiconnector.com/v1/channels/instagram-login/token?apiKey=YOUR_AGENCY_KEY&sub_account_id=CLIENT_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "ig_user_id": "17841400000000000",
    "access_token": "IGAAR…",
    "expires_at": "2026-11-01T00:00:00Z"
  }'
```

**Vastaus**

```json
{
  "success": true,
  "ig_user_id": "17841400000000000",
  "username": "acme.studio",
  "expires_at": "2026-11-01T00:00:00.000Z",
  "webhook_url": "https://api.youraiconnector.com/v1/incoming-instagram-login-message/byo/YOUR_ACCOUNT_ID"
}
```

Osana lähetystä tilaamme sovelluksesi kyseisen tilin webhookeihin (`subscribed_apps` lähetetyllä tunnisteella), joten viestit alkavat kulkea ilman lisäkutsuja sinun puoleltasi.

**Päivittäminen** - lähetä päivitetty tunniste samaan päätepisteeseen samalla `ig_user_id`-arvolla; se päivittää tallennetun tunnisteen ja vanhentumisajan paikallaan.

**Ristiriidat** - yksi Instagram-tili ei voi olla aktiivinen kahdessa yhteydessä samanaikaisesti. Jos tili on jo yhdistetty muualle tai tälle samalle tilille Facebook-sivun työnkulun kautta, lähetys palauttaa `409`-vastauksen, joka kertoo, mikä yhteys on katkaistava ensin. Facebook-työnkulun yhteyttä ei koskaan korvata automaattisesti, koska se saattaa palvella myös Messengeriä.

### Vaihe 3 - Katkaise yhteys, kun asiakas poistuu

`DELETE /channels/instagram-login/token` (sama todennus ja `sub_account_id`) peruuttaa webhookien tilauksen parhaansa mukaan ja poistaa tallennetun tunnistetiedon. Se onnistuu aina, vaikka tunniste olisi jo vanhentunut – ja kun tunnistetieto on poistettu, kyseisen tilin webhook-tapahtumat jätetään huomiotta.

---

## Vinkkejä luotettavan kääreen rakentamiseen

- **Kyselyt maltillisesti.** Muutaman sekunnin välein on riittävästi. Lopeta, kun saavutat päätetilan (`connected` / `ONLINE` tai virhetila), ja aseta silmukalle järkevä kokonaisaikakatkaisu (selain/QR-vaiheet vanhenevat, katso kukin `expires_at`).
- **URL-koodaa puhelinnumerot polussa.** Alussa oleva `+` tulee lähettää muodossa `%2B`. Päätepisteet palauttavat myös pelkät numerot, mutta koodaus on turvallinen oletus.
- **Älä koskaan odota salaisuuksia takaisin.** Pääsytunnisteet, kanavasalaisuudet ja sivutunnisteet hyväksytään tai tallennetaan, mutta niitä ei koskaan palauteta vastauksissa.
- **Käsittele todennusportti.** `403` tarkoittaa, että API-käyttöoikeus ei sisälly tilaukseen tai että yhdistämäsi kanava ei sisälly tilin tilaukseen. Katso [API-käyttöoikeus](../integrations/api-access.md).
- **Huomioi nopeusrajoitus.** Todennettuja pyyntöjä on rajoitettu 300 kappaleeseen minuutissa; `429` tarkoittaa, että sinun tulee odottaa ja yrittää uudelleen. Katso [Todennus](authentication.md).

## Seuraavat vaiheet

- [Todennus](authentication.md) - neljä hyväksyttyä todennusmuotoa ja virhemuoto.
- [API-käyttöoikeus](../integrations/api-access.md) - API-avaimen luominen ja hallinta.
