
# Tiimi-API

Tiimisi koostuu kaikista tililläsi työskentelevistä henkilöistä sinun lisäksesi – ylläpitäjistä, agenteista ja vain luku -oikeudella varustetuista katselijoista – sekä lähettämistäsi kutsuista ja osastoista, joihin olet heidät järjestänyt. Tiimi-API on ohjelmallinen versio kohdasta **Asetukset → Tiimi**: lisää ja poista ihmisiä, määritä mitä kukin heistä voi nähdä ja tehdä, lähetä ja muistuta kutsuista sekä hallinnoi osastoja.

Kaikki alla olevat päätepisteet ovat suhteessa perus-URL-osoitteeseen `https://api.youraiconnector.com/v1`. Katso hallintapaneeliversio kaikesta tällä sivulla olevasta kohdasta [Tiimin hallinta](../settings/team-management.md).

---

## Todennus: nämä päätepisteet vaativat sisäänkirjautuneen henkilön

**Tämä on se osa APIa, jota API-avain ei voi käyttää.** Jokainen `/team`-päätepiste, lukuun ottamatta [osasto](#departments)-päätepisteitä, on kutsuttava sisäänkirjautuneen istunnon **Firebase ID -tunnuksella**:

```
Authorization: Bearer <Firebase ID token>
```

Jos lähetät API-avaimen, pyyntö hylätään virheellä `401`:

```json
{
  "success": false,
  "error_code": 401,
  "error": "This endpoint requires a Firebase ID token (Authorization: Bearer <token>)."
}
```

Syy on se, että nämä päätepisteet päättävät toimintatavan sen perusteella, **kuka on kirjautunut sisään**: roolisi, yläraja sille, mitä saat myöntää muille, ja se, työskenteletkö parhaillaan toisen tilin sisällä. API-avain on integraatio, ei henkilö, joten näitä sääntöjä ei voida soveltaa kehenkään.

Käytännössä tämä tarkoittaa, että Tiimi-API on tarkoitettu ensimmäisen osapuolen sovellukselle, jossa on sisäänkirjautunut <span data-t="appName">Your AI Connector</span>-käyttäjä (katso [Todennus → Firebase ID -tunnus](authentication.md#4-firebase-id-token-first-party-only)). Palvelimien välinen integraatio ei voi hallinnoida tiimin jäseniä – näitä tunnuksia ei voi luoda sovelluksen ulkopuolelta.

> **Poikkeus:** neljä [osasto](#departments)-päätepistettä ovat tavallisia API-päätepisteitä. Ne hyväksyvät API-avaimesi aivan kuten muukin API, sekä sisäänkirjautuneen istunnon.

Jokainen tämän sivun vastaus noudattaa tavallista kirjekuorirakennetta: `success: true` ja päätepisteen kentät ylimmällä tasolla, tai `success: false`, jossa on `error` ja `error_code`, kun jokin menee vikaan.

---

## Roolit ja käyttöoikeudet

Jokaisella tiimin jäsenellä on yksi **rooli**, joka määrittää heidän oletusarvoisen pääsynsä sovelluksen 12 eri osa-alueelle. Voit sen jälkeen ohittaa yksittäisiä osa-alueita.

| Rooli | Arvo | Yhteenveto |
|---|---|---|
| Ylläpitäjä | `admin` | Kaikki paitsi omistajan laskutukseen liittyvät toiminnot. |
| Muokkaaja | `editor` | Voi luoda ja muuttaa asioita. Näkyy sovelluksessa nimellä **Agentti**. |
| Katselija | `viewer` | Vain luku -oikeus. |

Jokainen osa-alue on asetettu yhdelle neljästä tasosta: `none` (piilotettu), `view` (vain luku), `edit` (luo ja muuta), `full` (mukaan lukien poistaminen).

| Osa-alue | Ylläpitäjä | Muokkaaja | Katselija |
|---|---|---|---|
| `campaigns` | täysi | muokkaa | katso |
| `contacts` | täysi | muokkaa | katso |
| `messages` | täysi | muokkaa | katso |
| `appointments` | täysi | muokkaa | katso |
| `settings` | muokkaa | katso | ei mitään |
| `billing` | muokkaa | ei mitään | ei mitään |
| `team_management` | muokkaa | ei mitään | ei mitään |
| `analytics` | täysi | katso | katso |
| `phone_numbers` | muokkaa | ei mitään | ei mitään |
| `integrations` | muokkaa | ei mitään | ei mitään |
| `faqs` | täysi | muokkaa | katso |
| `daily_summaries` | täysi | katso | katso |

Jos haluat poiketa roolin oletusasetuksista, lähetä `permission_overrides` – taulukko `{ "area": ..., "level": ... }`-objekteja. Jokainen merkintä korvaa roolin oletusasetuksen kyseisellä osa-alueella; kaikki, mitä et listaa, säilyttää roolin oletusasetuksen.

```json
"permission_overrides": [
  { "area": "analytics", "level": "full" },
  { "area": "billing", "level": "none" }
]
```

**Kuka voi kutsua näitä päätepisteitä**

- **Tilin omistaja** voi aina tehdä kaiken.
- Tiimin jäsen tarvitsee `team_management`-oikeuden tasolla `view` lukeakseen jäsenluetteloa ja kutsulistaa, sekä tasolla `edit` lisätäkseen, muuttaakseen, keskeyttääkseen, poistaakseen, kutsuakseen, peruuttaakseen tai lähettääkseen kutsun uudelleen. Järjestelmänvalvojilla on oletuksena `edit`; muokkaajilla ja katselijoilla on `none`, joten oletuksena vain järjestelmänvalvojat voivat hallinnoida tiimiä.
- **Kukaan ei voi myöntää korkeampia käyttöoikeuksia kuin itsellään on.** Jos yrität antaa jollekulle tason, jota sinulla ei itselläsi ole – tai muokata, keskeyttää tai poistaa henkilöä, jonka käyttöoikeudet ovat jo laajemmat kuin omasi – pyyntö hylätään virheellä `403` ja viestillä, joka nimeää kyseisen osa-alueen.

---

## Tiimin jäsen -objekti

`GET /team/members` palauttaa yhden näistä per jäsen:

| Kenttä | Tyyppi | Kuvaus |
|---|---|---|
| `member_uid` | string | Jäsenen oma käyttäjätunnus. Tämä on `{memberUid}` alla olevissa poluissa. |
| `account_owner_uid` | string | Tili, jonka jäsen hän on. |
| `member_email` | string | Hänen sähköpostiosoitteensa. |
| `member_display_name` | string | Sovelluksessa näkyvä nimi. |
| `role` | string | `admin`, `editor` tai `viewer`. |
| `permission_overrides` | array | Hänen osa-aluekohtaiset poikkeuksensa. `[]`, kun hän käyttää vain roolin oletusasetuksia. |
| `status` | string | `active` tai `suspended`. |
| `auto_assign_enabled` | boolean \| null | Voiko uusia yhteystietoja määrittää hänelle automaattisesti. `null` tarkoittaa, ettei asetusta ole muutettu, mikä toimii kuten `true`. |
| `created_by` | string | Kuka hänet lisäsi. |
| `created_at` | string \| null | ISO 8601 -aikaleima. |
| `updated_at` | string \| null | ISO 8601 -aikaleima. |

Poistettuja jäseniä ei palauteta – luettelo sisältää vain aktiiviset ja keskeytetyt jäsenet.

> **Näkyvyysrajoitukset ovat tässä vain kirjoitettavissa.** `contact_scope`, `contact_scope_axes` ja `sub_account_access` (katso [Jäsenen näkyvyyden rajoittaminen](#limiting-what-a-member-can-see)) voidaan asettaa luonnin, päivityksen ja kutsun yhteydessä, mutta tämä päätepiste ei palauta niitä.

---

## Listaa tiimin jäsenet

`GET /team/members`

Palauttaa jäsenluettelon sekä tilauksesi paikkamäärät, jotta voit näyttää "3/5 paikkaa käytössä" ja tietää, milloin kutsuminen on estymässä.

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/team/members" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN"
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/team/members", {
  headers: { Authorization: `Bearer ${idToken}` },
});
const { members, seat_limit, seats_used } = await res.json();
```

**Python**

```python
import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/team/members",
    headers={"Authorization": f"Bearer {id_token}"},
)
data = res.json()
```

**Vastaus**

```json
{
  "success": true,
  "members": [
    {
      "account_owner_uid": "owner_uid_123",
      "member_uid": "uid_alice",
      "member_email": "alice@example.com",
      "member_display_name": "Alice Chen",
      "role": "admin",
      "permission_overrides": [],
      "status": "active",
      "auto_assign_enabled": true,
      "created_by": "owner_uid_123",
      "created_at": "2026-05-01T10:00:00.000Z",
      "updated_at": "2026-06-02T09:15:00.000Z"
    }
  ],
  "seat_limit": 5,
  "seats_used": 3
}
```

`seat_limit` on `null`, kun tilauksessasi ei ole paikkakiintiötä. `seats_used` laskee vain **aktiiviset** jäsenet – jonkun keskeyttäminen tai poistaminen vapauttaa hänen paikkansa välittömästi.

---

## Lisää tiimin jäsen suoraan

`POST /team/members`

Lisää henkilön tiimiisi välittömästi ilman kutsua.

> **Tämä ei lähetä sähköpostia.** Kenellekään ei ilmoiteta heidän lisäämisestään, ja jos heillä ei ollut jo <span data-t="appName">Your AI Connector</span>-kirjautumistunnuksia, heille luodulla tilillä **ei ole salasanaa**, joten he eivät voi kirjautua sisään ennen kuin he nollaavat sen. Käytä [Lähetä kutsu](#send-an-invitation) -toimintoa, ellet itse kerro henkilölle asiasta ja auta häntä kirjautumaan sisään.

**Pyynnön kentät**

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `email` | Kyllä | Tiimin jäsenen sähköpostiosoite. |
| `display_name` | Kyllä | Sovelluksessa näytettävä nimi. |
| `role` | Kyllä | `admin`, `editor` tai `viewer`. |
| `permission_overrides` | Ei | Aluekohtaiset poikkeukset roolin oletusasetuksiin. |
| `contact_scope` | Ei | `all` tai `assigned` — katso [Jäsenen näkyvyyden rajoittaminen](#limiting-what-a-member-can-see). |
| `contact_scope_unassigned` | Ei | Kun käytössä on `assigned`, salli heidän nähdä myös yhteystiedot, joilla ei vielä ole omistajaa. |
| `contact_scope_axes` | Ei | Rajoita heidät tiettyihin edustajiin, kanaviin tai osastoihin. |
| `sub_account_access` | Ei | Vain toimistoille — mitkä asiakasalitilit he voivat avata. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/team/members" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "sam@example.com",
    "display_name": "Sam Rivera",
    "role": "editor"
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/team/members", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${idToken}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    email: "sam@example.com",
    display_name: "Sam Rivera",
    role: "editor",
  }),
});
const { member_uid } = await res.json();
```

**Vastaus** — `201 Created`

```json
{
  "success": true,
  "team_member_id": "owner_uid_123_uid_sam",
  "member_uid": "uid_sam",
  "message": "Team member created successfully."
}
```

| Tila | Milloin |
|---|---|
| `400` | `email`, `display_name` tai `role` puuttuu, rooli ei ole yksi kolmesta sallitusta tai yritit lisätä itsesi. |
| `403` | Sinulla ei ole oikeutta hallinnoida tiimiä tai yritit myöntää laajemmat oikeudet kuin sinulla itselläsi on. |
| `409` | Kyseinen henkilö on jo tiimisi aktiivinen jäsen. |
| `429` | Tilauksesi tiimipaikat ovat täynnä. |

Aiemmin **jäädytetyn tai poistetun** henkilön lisääminen palauttaa hänet tiimiin epäonnistumisen sijaan.

---

## Päivitä tiimin jäsen

`PATCH /team/members/{memberUid}`

Muuttaa jäsenen roolia, käyttöoikeuksia, näkyvyyttä, asiakaspääsyä tai sitä, osallistuuko hän automaattiseen yhteystietojen jakoon. Lähetä vain ne kentät, joita haluat muuttaa; kaikki pois jätetyt säilyttävät nykyisen arvonsa.

**Pyynnön kentät**

| Kenttä | Kuvaus |
|---|---|
| `role` | `admin`, `editor` tai `viewer`. |
| `permission_overrides` | Korvaa koko poikkeuslistan. Lähetä `[]` palauttaaksesi jäsenen käyttämään roolin oletusasetuksia. |
| `status` | Vain `active` hyväksytään jäädytetyn jäsenen palauttamiseksi. Jos haluat jäädyttää jonkun, käytä [jäädytysrajapintaa](#suspend-a-team-member). |
| `auto_assign_enabled` | `true` tai `false`. |
| `contact_scope` | `all` tai `assigned`. |
| `contact_scope_unassigned` | `true` tai `false`. |
| `contact_scope_axes` | Katso [Jäsenen näkyvyyden rajoittaminen](#limiting-what-a-member-can-see). |
| `sub_account_access` | Vain toimistoille. |

> **Tämä on ainoa rajapinta, jossa `null` tarkoittaa "tyhjennä".** Arvojen `"contact_scope": null`, `"contact_scope_axes": null` tai `"sub_account_access": null` lähettäminen poistaa rajoituksen kokonaan ja palauttaa jäsenen näkemään kaiken. Luonnin ja kutsun yhteydessä `null` tarkoittaa yksinkertaisesti "ei määritetty".

**cURL**

```bash
curl -X PATCH "https://api.youraiconnector.com/v1/team/members/uid_sam" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "role": "admin",
    "permission_overrides": [{ "area": "billing", "level": "none" }]
  }'
```

**Vastaus**

```json
{
  "success": true,
  "message": "Team member updated successfully."
}
```

| Tila | Milloin |
|---|---|
| `400` | Virheellinen `status`- tai `auto_assign_enabled`-arvo, tai yritit aktivoida uudelleen poistetun jäsenen (poistetut jäsenet on kutsuttava uudelleen). |
| `403` | Sinulla ei ole oikeuksia tai muutos loisi laajemmat oikeudet kuin sinulla itselläsi on. |
| `404` | Kyseistä tiimin jäsentä ei löydy. |

---

## Jäädytä tiimin jäsen

`POST /team/members/{memberUid}/suspend`

Jäädyttää henkilön: hän säilyttää paikkansa tiimissä, mutta menettää käyttöoikeudet. Käytä tätä poistamisen sijaan, kun tauko on väliaikainen — palauta hänet takaisin käyttämällä `PATCH /team/members/{memberUid}` ja `{"status": "active"}`.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/team/members/uid_sam/suspend" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN"
```

**Vastaus**

```json
{
  "success": true,
  "message": "Team member suspended successfully."
}
```

Jäädytetty jäsen **vapauttaa paikkansa**, joten voit kutsua jonkun muun hänen tilalleen. Hänen käyttöoikeutensa päättyvät, kun hänen nykyinen istuntotunnisteensa päivittyy seuraavan kerran, mikä voi kestää jopa tunnin — poista hänet, jos tarvitset välittömän vaikutuksen.

| Tila | Milloin |
|---|---|
| `400` | Yritit jäädyttää tilin omistajan tai jäsenen, joka on jo jäädytetty tai poistettu. |
| `403` | Hänen käyttöoikeutensa ovat laajemmat kuin sinun. |
| `404` | Kyseistä tiimin jäsentä ei löydy. |

---

## Tiimin jäsenen poistaminen

`DELETE /team/members/{memberUid}`

Poistaa henkilön tiimistäsi ja vapauttaa hänen paikkansa. Hänet kirjataan ulos ja hän menettää pääsyn tilillesi; hänen oma kirjautumisensa säilyy ennallaan.

**cURL**

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/team/members/uid_sam" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN"
```

**Vastaus**

```json
{
  "success": true,
  "message": "Team member removed successfully."
}
```

Poistaminen on pysyvää sinun puoleltasi: poistettua jäsentä **ei voi aktivoida uudelleen** päivityksen päätepisteen kautta — kutsu hänet uudelleen, jos muutat mielesi. Hänen sähköpostiosoitteensa poistetaan myös tilisi ilmoituslistalta.

| Tila | Milloin |
|---|---|
| `400` | Yritit poistaa tilin omistajan. |
| `403` | Hänen käyttöoikeutensa ovat laajemmat kuin sinun. |
| `404` | Kyseistä tiimin jäsentä ei ole olemassa. |

---

## Jäsenen näkyvyyden rajoittaminen

Kolme valinnaista kenttää, jotka hyväksytään [lisäyksessä](#add-a-team-member-directly), [päivityksessä](#update-a-team-member) ja [kutsussa](#send-an-invitation), määrittävät, kuinka paljon henkilö näkee tilistä. Ne yhdistyvät: jos jäsen on rajoitettu useammalla kuin yhdellä tavalla, häntä rajoittavat ne kaikki.

**`contact_scope`** — `all` (oletus: jokainen yhteystieto ja keskustelu) tai `assigned` (vain hänelle määritetyt). Kun käytössä on `assigned`, lisää `"contact_scope_unassigned": true`, jotta hän näkee myös yhteystiedot, joita kukaan ei vielä omista.

**`contact_scope_axes`** — rajoittaa hänet nimettyihin agentteihin, kanaviin tai osastoihin:

| Kenttä | Tyyppi | Kuvaus |
|---|---|---|
| `agents` | string[] | Agenttien tunnukset. He näkevät vain keskustelut, jotka on reititetty yhdelle näistä agenteista. Enintään 200. |
| `channels` | string[] | Kanavien nimet — `whatsapp`, `whatsapp_web`, `sms`, `instagram`, `instagram_private`, `messenger`, `facebook`, `chat_widget`, `telegram`, `line`, `viber`, `tiktok`, `imessage`, `email`, `linkedin`, `skool`, `custom`, `custom_channel`. Enintään 200. |
| `departments` | string[] | Osastojen tunnukset (katso [Osastot](#departments)). He näkevät vain heille määritetyt liidit. Enintään 200. |
| `include_unrouted` | boolean | Kun `agents` on asetettu, näytä myös keskustelut, joita kukaan agentti ei käsittele. Pois päältä oletuksena. Ohitetaan, kun `agents` on tyhjä. |
| `include_undepartmented` | boolean | Kun `departments` on asetettu, näytä myös keskustelut, jotka eivät kuulu mihinkään osastoon. Pois päältä oletuksena. Ohitetaan, kun `departments` on tyhjä. |

Agenttien ja osastojen tunnuksia ei tarkisteta tallennettaessa — olematon tunnus ei yksinkertaisesti vastaa mitään, mikä näkyy tyhjänä postilaatikkona virheen sijaan. Kanavien nimet **tarkistetaan**: tunnistamaton nimi hylätään virheellä `400`.


Mitään näistä kolmesta ei voi asettaa tilin omistajalle — kyseinen pyyntö hylätään virheellä `400`.

---

## Listaa kutsut

`GET /team/invites`

Lähettämäsi kutsut uusimmasta alkaen, jotta näet, kuka ei ole vielä hyväksynyt kutsua.

**Kyselyparametrit**

| Parametri | Pakollinen | Kuvaus |
|---|---|---|
| `status` | Ei | Palauta vain tässä tilassa olevat kutsut — `pending`, `accepted`, `declined`, `cancelled` tai `expired`. |

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/team/invites?status=pending" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN"
```

**Vastaus**

```json
{
  "success": true,
  "invites": [
    {
      "id": "inv_abc123",
      "account_owner_uid": "owner_uid_123",
      "account_owner_display_name": "Acme Ltd",
      "invitee_email": "sam@example.com",
      "invitee_uid": null,
      "role": "editor",
      "permission_overrides": [],
      "status": "pending",
      "created_by": "owner_uid_123",
      "created_at": "2026-06-10T12:00:00.000Z",
      "expires_at": "2026-06-17T12:00:00.000Z",
      "responded_at": null
    }
  ]
}
```

Kutsutunnistetta ei palauteta koskaan — se on olemassa vain lähetetyssä sähköpostiviestissä.

---

## Lähetä kutsu

`POST /team/invites`

Lähettää sähköpostitse kutsun liittyä tiimiisi. Tämä on tavallinen tapa lisätä tiimin jäsen: he klikkaavat linkkiä, kirjautuvat sisään omilla tunnuksillaan ja hyväksyvät kutsun. Jos heillä ei ole vielä <span data-t="appName">Your AI Connector</span>-tiliä, sellainen luodaan heille ja sähköpostiviesti opastaa salasanan asettamisessa.

**Pyynnön kentät**

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `email` | Kyllä | Mihin kutsu lähetetään. |
| `role` | Kyllä | `admin`, `editor` tai `viewer`. |
| `permission_overrides` | Ei | Aluekohtaiset poikkeukset, jotka otetaan käyttöön heti, kun he hyväksyvät kutsun. |
| `contact_scope` | Ei | Otetaan käyttöön, kun he hyväksyvät kutsun. |
| `contact_scope_unassigned` | Ei | Otetaan käyttöön, kun he hyväksyvät kutsun. |
| `contact_scope_axes` | Ei | Otetaan käyttöön, kun he hyväksyvät kutsun. |
| `sub_account_access` | Ei | Vain toimistoille. Otetaan käyttöön, kun he hyväksyvät kutsun. |

Käyttöoikeuksien määrittäminen etukäteen tarkoittaa, ettei jäsentä tarvitse muokata jälkikäteen — kaikki kopioidaan heidän jäsenyyteensä, kun he hyväksyvät kutsun.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/team/invites" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "email": "sam@example.com", "role": "editor" }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/team/invites", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${idToken}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ email: "sam@example.com", role: "editor" }),
});
const { invite_id } = await res.json();
```

**Vastaus** — `201 Created`

```json
{
  "success": true,
  "invite_id": "inv_abc123",
  "message": "Team invite sent successfully."
}
```

**Huomioitavia asioita**

- **Kutsut vanhenevat 7 päivän kuluttua.** Vanhentuneen kutsun voi lähettää uudelleen, mikä aloittaa uuden 7 päivän jakson.
- **Vireillä olevat kutsut varaavat paikan.** Toisin kuin jäsentä suoraan lisättäessä, paikkojen tarkistus laskee tässä aktiiviset jäsenet *sekä* vireillä olevat kutsut, joten tili, jonka kaikki paikat on varattu, hylätään ennen kuin sähköpostia lähetetään.
- **20 kutsua päivässä**, laskettuna tiliä kohden sekä lähetysten että uudelleenlähetysten osalta.

| Tila | Milloin |
|---|---|
| `400` | `email` puuttuu tai rooli on virheellinen. |
| `403` | Sinulla ei ole oikeutta hallinnoida tiimiä, tai yritit myöntää korkeammat oikeudet kuin itselläsi on. |
| `409` | Kyseiselle sähköpostiosoitteelle on jo olemassa vireillä oleva kutsu, tai kyseinen henkilö on jo tiimissäsi. |
| `429` | Tilauksesi tiimipaikat ovat täynnä, tai olet saavuttanut 20 kutsun päiväkohtaisen rajan. `error`-viesti kertoo, kumpi on kyseessä. |

---

## Peruuta kutsu

`DELETE /team/invites/{inviteId}`

Peruuttaa kutsun ennen kuin se on hyväksytty. Sähköpostissa oleva linkki lakkaa toimimasta.

**cURL**

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/team/invites/inv_abc123" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN"
```

**Vastaus**

```json
{
  "success": true,
  "message": "Team invite cancelled."
}
```

Sekä `pending`- että `expired`-kutsut voidaan peruuttaa. Kutsu, joka on jo hyväksytty, hylätty tai peruutettu, palauttaa `400`; kutsu, joka ei ole sinun, palauttaa `403`; tuntematon tunnus palauttaa `404`.

---

## Lähetä kutsu uudelleen

`POST /team/invites/{inviteId}/resend`

Lähettää kutsusähköpostin uudelleen — jos se jäi huomaamatta tai päätyi roskapostiin. Toimii `pending`- ja `expired`-kutsuille ja nollaa vanhenemisajan 7 päivän päähän tästä hetkestä.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/team/invites/inv_abc123/resend" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN"
```

**Vastaus**

```json
{
  "success": true,
  "message": "Team invite resent successfully."
}
```

Uusi sähköposti sisältää uuden linkin, ja **vanha linkki toimii myös edelleen**, joten henkilö, joka löytää ensimmäisen sähköpostin myöhemmin, ei jää jumiin. Uudelleenlähetys lasketaan samaan 20 kpl päivittäiseen rajoitukseen kuin lähettäminen, ja *vanhentuneen* kutsun elvyttäminen tarkistaa paikkamääräsi uudelleen — täysi tilaus hylätään virheellä `429`.

---

## Hyväksy kutsu

`POST /team/invites/accept`

Hyväksyy kutsun sähköpostiviestissä olevalla tunnisteella ja liittää kirjautuneen käyttäjän kyseisen tilin tiimiin.

> **Tämä on henkilökohtainen toiminto.** Kirjaudu sisään omana itsenäsi — toiminto hylätään tarkoituksella virheellä `403`, jos työskentelet jonkun toisen tilin sisällä.

**Pyynnön kentät**

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `invite_token` | Kyllä | Kutsusähköpostin linkissä oleva tunniste. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/team/invites/accept" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "invite_token": "1f4c…" }'
```

**Vastaus**

```json
{
  "success": true,
  "team_member_id": "owner_uid_123_uid_sam",
  "account_owner_uid": "owner_uid_123",
  "message": "Team invite accepted successfully."
}
```

| Tila | Milloin |
|---|---|
| `400` | `invite_token` puuttuu tai kutsu on omaa tiliäsi varten. |
| `403` | Istunto on käynnissä toisen tilin sisällä tai kutsu lähetettiin eri sähköpostiosoitteeseen kuin se, jolla olet kirjautunut sisään. |
| `404` | Kutsua ei ole olemassa tai se on jo käytetty. |
| `429` | Tilin paikat täyttyivät kutsun ja hyväksymisen välisenä aikana. |
| `504` | Kutsu on vanhentunut. Pyydä lähettäjää lähettämään se uudelleen. |

---

## Hylkää kutsu

`POST /team/invites/decline`

Hylkää kutsun sähköpostiviestissä olevalla tunnisteella. Kuten hyväksyminen, tämä on henkilökohtainen toiminto, ja se hylätään, jos työskentelet toisen tilin sisällä.

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/team/invites/decline" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "invite_token": "1f4c…" }'
```

**Vastaus**

```json
{
  "success": true,
  "message": "Team invite declined."
}
```

---

## Osastot

**Osasto** on tiimisi nimetty ryhmä – esimerkiksi myynti, asiakaspalvelu tai HR. Se antaa liidille omistajatiimin, voi ottaa uusia keskusteluja vastaan itsenäisesti, ja sitä voidaan käyttää rajoittamaan sitä, mitä jäsen näkee.

> **Nämä neljä päätepistettä vaativat API-avaimen.** Toisin kuin muualla tällä sivulla, ne todennetaan samalla tavalla kuin kaikki muutkin API:n päätepisteet (katso [Todennus](authentication.md)). Myös sisäänkirjautunut istunto toimii: lukeminen vaatii `contacts` osoitteessa `view`, ja luominen, muuttaminen tai poistaminen vaatii `team_management` osoitteessa `edit`.

**Osasto-objekti**

| Kenttä | Tyyppi | Kuvaus |
|---|---|---|
| `id` | string | Osaston tunnus. Käytä sitä kohdassa `contact_scope_axes.departments` ja alla olevissa poluissa. |
| `name` | string | Tiimin nimi. Enintään 60 merkkiä, yksilöllinen tilillä. |
| `color` | string \| null | Korostusväri muodossa `#rrggbb` tai `null`. |
| `member_uids` | string[] | Tämän osaston tiimin jäsenet. Voi sisältää tilin omistajan. |
| `auto_assign_enabled` | boolean | Määritetäänkö tähän osastoon kirjattu liidi myös jollekin sen jäsenelle. `false` tarkoittaa, että osasto työskentelee jaetusta jonosta. |
| `routing_agents` | string[] | Näiden tekoälyagenttien käsittelemät uudet keskustelut kirjataan automaattisesti tähän osastoon. Tyhjä tarkoittaa, ettei agenttisääntöä ole. |
| `routing_channels` | string[] | Näiden kanavien uudet keskustelut kirjataan automaattisesti tänne. Tyhjä tarkoittaa, ettei kanavasääntöä ole. |
| `created_by` | string \| null | Kuka sen loi. |

Kun sekä `routing_agents` että `routing_channels` on asetettu, keskustelun on täytettävä **molemmat** ehdot, jotta se kirjataan tänne – näin voit antaa tiimille esimerkiksi "tukiedustaja, mutta vain WhatsAppissa".

Tilillä voi olla enintään **50** osastoa.

### Listaa osastot

`GET /team/departments`

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

**Vastaus**

```json
{
  "success": true,
  "departments": [
    {
      "id": "dep_abc123",
      "name": "Sales",
      "color": "#2f6fed",
      "member_uids": ["uid_alice", "uid_bob"],
      "auto_assign_enabled": true,
      "routing_agents": [],
      "routing_channels": ["whatsapp"],
      "created_by": "owner_uid_123"
    }
  ]
}
```

### Luo osasto

`POST /team/departments`

**Pyynnön kentät**

| Kenttä | Pakollinen | Kuvaus |
|---|---|---|
| `name` | Kyllä | Enintään 60 merkkiä. Ei saa olla sama kuin olemassa oleva osasto. |
| `color` | Ei | `#rrggbb` heksadesimaalina tai `null`. |
| `member_uids` | Ei | Ketkä kuuluvat siihen. Jokaisen UID:n on oltava tilin omistaja tai **aktiivinen** tiimin jäsen. |
| `auto_assign_enabled` | Ei | Oletusarvo on `true`. |
| `routing_agents` | Ei | Agenttien tunnukset, joiden uudet keskustelut ohjautuvat tänne. |
| `routing_channels` | Ei | Kanavien nimet, joiden uudet keskustelut ohjautuvat tänne – sama sanasto kuin kohdassa `contact_scope_axes.channels`. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/team/departments?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Sales",
    "color": "#2f6fed",
    "member_uids": ["uid_alice", "uid_bob"],
    "routing_channels": ["whatsapp"]
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/team/departments", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    name: "Sales",
    color: "#2f6fed",
    member_uids: ["uid_alice", "uid_bob"],
    routing_channels: ["whatsapp"],
  }),
});
const { department } = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/team/departments",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "name": "Sales",
        "color": "#2f6fed",
        "member_uids": ["uid_alice", "uid_bob"],
        "routing_channels": ["whatsapp"],
    },
)
department = res.json()["department"]
```

**Vastaus** — `201 Created`

```json
{
  "success": true,
  "department": {
    "id": "dep_abc123",
    "name": "Sales",
    "color": "#2f6fed",
    "member_uids": ["uid_alice", "uid_bob"],
    "auto_assign_enabled": true,
    "routing_agents": [],
    "routing_channels": ["whatsapp"],
    "created_by": "owner_uid_123"
  }
}
```

| Tila | Milloin |
|---|---|
| `400` | `name` puuttuu tai on liian pitkä, `color` ei ole `#rrggbb`, kanavan nimeä ei tunnisteta, listattu UID ei ole tämän tiimin aktiivinen jäsen tai sinulla on jo 50 osastoa. |
| `409` | Samanniminen osasto on jo olemassa. |

### Päivitä osasto

`PATCH /team/departments/{departmentId}`

Muuttaa osastoa. Vain lähettämäsi kentät muuttuvat.

```bash
curl -X PATCH "https://api.youraiconnector.com/v1/team/departments/dep_abc123?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "member_uids": ["uid_alice"], "auto_assign_enabled": false }'
```

**Vastaus**

```json
{
  "success": true,
  "department": {
    "id": "dep_abc123",
    "name": "Sales",
    "color": "#2f6fed",
    "member_uids": ["uid_alice"],
    "auto_assign_enabled": false,
    "routing_agents": [],
    "routing_channels": ["whatsapp"],
    "created_by": "owner_uid_123"
  }
}
```

Jos yhtään tunnistettua kenttää ei lähetetä, palautetaan `400`; tuntematon osasto palauttaa `404`; nimi, joka on ristiriidassa toisen osaston kanssa, palauttaa `409`.

### Osaston poistaminen

`DELETE /team/departments/{departmentId}`

```bash
curl -X DELETE "https://api.youraiconnector.com/v1/team/departments/dep_abc123?apiKey=YOUR_API_KEY"
```

**Vastaus**

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

> **Osaston poistaminen, johon joku on rajoitettu, evätään.** `400`-vastaus nimeää ne jäsenet, joiden näkyvyys on rajoitettu kyseiseen osastoon, jotta voit muuttaa heidän laajuuttaan ensin. Tämä on harkittua: heidän rajoitustensa hiljainen poistaminen antaisi heille pääsyn koko asiakaskuntaasi ilman, että siitä jäisi mitään merkkiä.

Poistetun osaston alle arkistoituja yhteystietoja ei muuteta – niissä ei vain enää näy osastoa, ja seuraavan kerran kun arkistoit ne, se tallentuu.

---

## Tarkista omat käyttöoikeutesi

`GET /team/permissions`

Palauttaa tiedot siitä, mitä kirjautunut henkilö saa tehdä tilillä, jossa hän parhaillaan työskentelee. Käytä tätä piilottaaksesi painikkeet, joita jäsen ei voi käyttää, sen sijaan että antaisit heidän huomata rajoituksen virheilmoituksen kautta.

**cURL**

```bash
curl "https://api.youraiconnector.com/v1/team/permissions" \
  -H "Authorization: Bearer FIREBASE_ID_TOKEN"
```

**Vastaus – tilin omistaja**

```json
{
  "success": true,
  "role": "owner",
  "is_team_mode": false,
  "permissions": {
    "campaigns": "full",
    "contacts": "full",
    "messages": "full",
    "appointments": "full",
    "settings": "full",
    "billing": "full",
    "team_management": "full",
    "analytics": "full",
    "phone_numbers": "full",
    "integrations": "full",
    "faqs": "full",
    "daily_summaries": "full"
  }
}
```

**Vastaus – tiimin jäsen, joka työskentelee tilin sisällä**

```json
{
  "success": true,
  "role": "editor",
  "is_team_mode": true,
  "permissions": { "campaigns": "edit", "billing": "none", "…": "…" },
  "member": {
    "uid": "uid_sam",
    "email": "sam@example.com",
    "display_name": "Sam Rivera",
    "account_owner_uid": "owner_uid_123"
  }
}
```

`role` on `owner`, kun kirjautunut henkilö on tilin omistaja; muussa tapauksessa se on hänen tiimiroolinsa. `member` on läsnä vain tiimitilassa, ja se sisältää `contact_scope`, `contact_scope_unassigned` ja `contact_scope_axes`, kun heidän jäsenyytensä ne sisältää.

---

## Istuntotunnisteet

Viisi päätepistettä luovat kertakäyttöisen kirjautumistunnisteen tilien välillä vaihtamista varten. Ne kaikki vastaavat samalla tavalla:

```json
{
  "success": true,
  "customToken": "eyJhbGciOi…"
}
```

Tunniste vaihdetaan istuntoon Firebase-asiakas-SDK:n avulla. **Se ei ole API-avain, eikä sitä voi lähettää sellaisena**, minkä vuoksi nämä päätepisteet ovat hyödyllisiä vain ensimmäisen osapuolen sovelluksissa.

| Päätepiste | Mitä se tekee | Runko |
|---|---|---|
| `POST /team/tokens/team-member` | Antaa tiimin jäsenen aloittaa työskentelyn tilillä, johon hän kuuluu. | `account_owner_uid` (pakollinen) |
| `POST /team/tokens/return-from-team` | Palauttaa hänet takaisin omaan tiliinsä. | — |
| `POST /team/tokens/assist` | Antaa <span data-t="appName">Your AI Connector</span>-henkilökunnan avata asiakkaan tilin avustamista varten. Vain henkilökunnalle. | `customerUid` |
| `POST /team/tokens/return-to-admin` | Päättää avustusistunnon ja palauttaa henkilökunnan omaan tiliinsä. | — |
| `POST /team/tokens/agency-assist` | Antaa toimiston avata yhden asiakasalitileistään – tai jos sitä kutsutaan ilman sellaista, palata toimiston tilille. | `subAccountUid` (valinnainen) |

Jokainen hylätään virheellä `403`, kun istunnolla ei ole siihen oikeutta: käyttäjä ei ole kyseisen tilin jäsen, ei ole henkilökuntaa, kyseinen alatili ei kuulu toimistollesi tai sitä ei ole myönnetty sinulle, tai istunto ei ole tällä hetkellä siinä tilassa, jota päätepiste edellyttää.

---

## Määritä alustarooli

`POST /team/users/{targetUid}/role`

Asettaa käyttäjän **alustaroolin** — `User`, `Dev`, `Support` tai `Agency`. Tämä ei ole tiimin jäsenyys: se määrittää, millainen <span data-t="appName">Your AI Connector</span>-tili henkilöllä on.

Tämä päätepiste on rajoitettu <span data-t="appName">Your AI Connector</span>-henkilökunnalle, eikä viimeistä jäljellä olevaa `Dev`-käyttäjää voi alentaa. Listattu täydellisyyden vuoksi; se ei ole osa oman tiimin hallintaa.

```json
{
  "success": true,
  "targetUid": "uid_sam",
  "role": "Agency",
  "claimUpdated": true
}
```

| Tila | Milloin |
|---|---|
| `400` | `role` puuttuu tai ei ole yksi neljästä, tai tämä poistaisi viimeisen `Dev`-käyttäjän. |
| `403` | Et ole henkilökuntaa tai istunto toimii toisen tilin sisällä. |
| `404` | Käyttäjää ei löydy. |

---

## Tiimin API-virheet

Tiimin päätepisteet palauttavat vakioituja virheviestejä, joissa on aina `error_code` HTTP-tilan ohella:

```json
{
  "success": false,
  "error_code": 403,
  "error": "Cannot grant \"full\" access to \"billing\" — exceeds your own permissions."
}
```

| Tila | Milloin se tapahtuu tiimin päätepisteessä |
|---|---|
| `400` | Pakollinen kenttä puuttuu tai on virheellinen, tai toiminto ei ole sallittu tässä tilassa (poistetun jäsenen uudelleenaktivointi, omistajan keskeyttäminen, osaston poistaminen, johon joku on rajoitettu). |
| `401` | Lähetit API-avaimen päätepisteeseen, joka vaatii sisäänkirjautuneen henkilön — katso [Todennus](#authentication-these-endpoints-need-a-signed-in-person). |
| `403` | Sinulla ei ole `team_management`-oikeutta, muutos ylittää omat käyttöoikeutesi tai toiminto hylätään, kun työskentelet toisen tilin sisällä. |
| `404` | Jäsentä, kutsua, osastoa tai käyttäjää ei löydy. |
| `409` | Käyttäjä on jo tiimin jäsen, vireillä oleva kutsu on jo olemassa tai samanniminen osasto on jo olemassa. |
| `429` | Tiimin paikat ovat täynnä, 20 kutsun päivittäinen raja on saavutettu tai API-nopeusrajoitus on tullut vastaan. |
| `504` | Kutsu, jonka yritit hyväksyä, on vanhentunut. |

Jaetut koodit, jotka jokainen päätepiste voi palauttaa — `429` (nopeusrajoitus) ja `500` — on listattu uudelleenkokeiluohjeiden kera kohdassa [Virheet ja sivutus](errors-and-pagination.md).

---

## Aiheeseen liittyvää

- [Tiimin hallinta](../settings/team-management.md) — samat ominaisuudet hallintapaneelissa kuvakaappausten kera.
- [Todennus](authentication.md) — miten lähetät Firebase ID -tunnisteen API-avaimen sijaan.
- [Yhteystietojen API](contacts.md) — yhteystiedot, joihin jäsenen näkyvyysrajoitukset soveltuvat.

