
# API-ul Echipei

Echipa ta reprezintă toți cei care lucrează în contul tău în afară de tine — administratori, agenți și vizitatori cu drept de citire — plus invitațiile pe care le-ai trimis și departamentele în care îi organizezi. API-ul Echipei este versiunea programatică a **Setări → Echipă**: adaugă și elimină persoane, stabilește ce poate vedea și face fiecare dintre aceștia, trimite și urmărește invitații și gestionează departamentele.

Toate punctele finale de mai jos sunt relative la URL-ul de bază `https://api.youraiconnector.com/v1`. Pentru versiunea din tabloul de bord a tot ceea ce se află pe această pagină, consultă [Gestionarea Echipei](../settings/team-management.md).

---

## Autentificare: aceste puncte finale necesită o persoană autentificată

**Aceasta este singura parte a API-ului pe care o cheie API nu o poate folosi.** Fiecare punct final `/team`, cu excepția celor pentru [departamente](#departments), trebuie apelat cu un **token Firebase ID** dintr-o sesiune autentificată:

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

Trimite o cheie API în schimb, iar cererea va fi respinsă cu un `401`:

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

Motivul este că aceste puncte finale decid ce să facă în funcție de **cine este autentificat**: rolul tău, limita a ceea ce ai voie să acorzi altcuiva și dacă lucrezi în prezent în interiorul unui alt cont. O cheie API este o integrare, nu o persoană, deci nu există nimeni căruia să i se aplice acele reguli.

În practică, acest lucru înseamnă că API-ul Echipei este destinat unei aplicații proprii cu un utilizator <span data-t="appName">Your AI Connector</span> autentificat (vezi [Autentificare → Token Firebase ID](authentication.md#4-firebase-id-token-first-party-only)). O integrare server-la-server nu poate gestiona membrii echipei — nu există nicio modalitate de a genera unul dintre aceste token-uri din afara aplicației.

> **Excepția:** cele patru puncte finale pentru [departamente](#departments) sunt puncte finale API obișnuite. Acestea acceptă cheia ta API exact ca restul API-ului, precum și o sesiune autentificată.

Fiecare răspuns de pe această pagină urmează plicul obișnuit: `success: true` plus câmpurile punctului final la nivelul superior, sau `success: false` cu `error` și `error_code` atunci când ceva nu merge bine.

---

## Roluri și permisiuni

Fiecare membru al echipei are un **rol**, care stabilește accesul implicit în 12 zone ale aplicației. Poți apoi să suprascrii zone individuale.

| Rol | Valoare | Rezumat |
|---|---|---|
| Admin | `admin` | Totul, cu excepția acțiunilor de facturare ale proprietarului. |
| Editor | `editor` | Poate crea și modifica lucruri. Afișat ca **Agent** în aplicație. |
| Vizitator | `viewer` | Doar citire. |

Fiecare zonă este setată la unul dintre cele patru niveluri: `none` (ascuns), `view` (doar citire), `edit` (creare și modificare), `full` (inclusiv ștergere).

| Zonă | Admin | Editor | Vizitator |
|---|---|---|---|
| `campaigns` | complet | editare | vizualizare |
| `contacts` | complet | editare | vizualizare |
| `messages` | complet | editare | vizualizare |
| `appointments` | complet | editare | vizualizare |
| `settings` | editare | vizualizare | niciunul |
| `billing` | editare | niciunul | niciunul |
| `team_management` | editare | niciunul | niciunul |
| `analytics` | complet | vizualizare | vizualizare |
| `phone_numbers` | editare | niciunul | niciunul |
| `integrations` | editare | niciunul | niciunul |
| `faqs` | complet | editare | vizualizare |
| `daily_summaries` | complet | vizualizare | vizualizare |

Pentru a devia de la setările implicite ale rolului, trimiteți `permission_overrides` — o matrice de obiecte `{ "area": ..., "level": ... }`. Fiecare intrare înlocuiește setarea implicită a rolului pentru acea zonă specifică; tot ceea ce nu listați păstrează setarea implicită a rolului.

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

**Cine poate apela aceste endpoint-uri**

- **Proprietarul contului** poate face întotdeauna totul.
- Un membru al echipei are nevoie de `team_management` la `view` pentru a citi lista membrilor și lista de invitații, și la `edit` pentru a adăuga, modifica, suspenda, elimina, invita, anula sau retrimite. Administratorii au `edit` în mod implicit; editorii și vizualizatorii au `none`, deci, în mod implicit, doar administratorii pot gestiona echipa.
- **Nimeni nu poate acorda un nivel de acces mai mare decât al său.** Dacă încercați să oferiți cuiva un nivel pe care nu îl dețineți — sau să editați, suspendați sau eliminați pe cineva al cărui acces este deja mai extins decât al dumneavoastră — cererea este refuzată cu `403` și un mesaj care specifică zona.

---

## Obiectul membru al echipei

`GET /team/members` returnează unul dintre acestea pentru fiecare membru:

| Câmp | Tip | Descriere |
|---|---|---|
| `member_uid` | string | ID-ul de utilizator al membrului. Acesta este `{memberUid}` în căile de mai jos. |
| `account_owner_uid` | string | Contul din care face parte. |
| `member_email` | string | Adresa lor de e-mail. |
| `member_display_name` | string | Numele afișat pentru aceștia în aplicație. |
| `role` | string | `admin`, `editor` sau `viewer`. |
| `permission_overrides` | array | Excepțiile lor pe zonă. `[]` atunci când folosesc doar setările implicite ale rolului. |
| `status` | string | `active` sau `suspended`. |
| `auto_assign_enabled` | boolean \| null | Dacă noile contacte pot fi alocate automat acestora. `null` înseamnă că nu a fost niciodată modificat, ceea ce se comportă ca `true`. |
| `created_by` | string | Cine i-a adăugat. |
| `created_at` | string \| null | Marcaj temporal ISO 8601. |
| `updated_at` | string \| null | Marcaj temporal ISO 8601. |

Membrii eliminați nu sunt returnați — lista conține doar membrii activi și suspendați.

> **Limitele de vizibilitate sunt doar pentru scriere aici.** `contact_scope`, `contact_scope_axes` și `sub_account_access` (consultați [Limitarea a ceea ce poate vedea un membru](#limiting-what-a-member-can-see)) pot fi setate la creare, actualizare și invitare, dar acest endpoint nu le returnează.

---

## Listarea membrilor echipei

`GET /team/members`

Returnează lista membrilor plus numărul de locuri al planului dumneavoastră, astfel încât să puteți afișa „3 din 5 locuri” și să știți când invitarea urmează să fie refuzată.

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

**Răspuns**

```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` este `null` atunci când planul dumneavoastră nu are o limită de locuri. `seats_used` numără doar membrii **activi** — suspendarea sau eliminarea cuiva eliberează imediat locul acestuia.

---

## Adăugarea directă a unui membru în echipă

`POST /team/members`

Adaugă pe cineva în echipă imediat, fără o invitație.

> **Acest lucru nu trimite niciun e-mail.** Nimeni nu este anunțat că a fost adăugat și, dacă nu aveau deja o autentificare <span data-t="appName">Your AI Connector</span>, contul creat pentru ei **nu are parolă**, deci nu se pot conecta până nu o resetează. Folosiți [Trimiteți o invitație](#send-an-invitation) decât dacă aveți propria metodă de a anunța persoana și de a o ajuta să se conecteze.

**Câmpuri de solicitare**

| Câmp | Obligatoriu | Descriere |
|---|---|---|
| `email` | Da | Adresa de e-mail a coechipierului. |
| `display_name` | Da | Numele afișat pentru acesta în aplicație. |
| `role` | Da | `admin`, `editor` sau `viewer`. |
| `permission_overrides` | Nu | Excepții pe zonă față de valorile implicite ale rolului. |
| `contact_scope` | Nu | `all` sau `assigned` — consultați [Limitarea a ceea ce poate vedea un membru](#limiting-what-a-member-can-see). |
| `contact_scope_unassigned` | Nu | Cu `assigned`, permiteți-le să vadă și contactele care nu au încă un proprietar. |
| `contact_scope_axes` | Nu | Limitați-i la agenți, canale sau departamente numite. |
| `sub_account_access` | Nu | Doar pentru agenții — ce sub-conturi de client pot deschide. |

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

**Răspuns** — `201 Created`

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

| Status | Când |
|---|---|
| `400` | `email`, `display_name` sau `role` lipsește, rolul nu este unul dintre cele trei sau ați încercat să vă adăugați pe dumneavoastră. |
| `403` | Nu aveți permisiunea de a gestiona echipa sau ați încercat să acordați acces mai mare decât al dumneavoastră. |
| `409` | Acea persoană este deja un membru activ al echipei dumneavoastră. |
| `429` | Locurile din echipa planului dumneavoastră sunt ocupate. |

Adăugarea cuiva care a fost anterior **suspendat sau eliminat** îi repune în funcție în loc să eșueze.

---

## Actualizați un membru al echipei

`PATCH /team/members/{memberUid}`

Modifică rolul, permisiunile, vizibilitatea, accesul la clienți sau participarea unui membru la alocarea automată a contactelor. Trimiteți doar câmpurile pe care doriți să le modificați; tot ceea ce omiteți își păstrează valoarea curentă.

**Câmpuri de solicitare**

| Câmp | Descriere |
|---|---|
| `role` | `admin`, `editor` sau `viewer`. |
| `permission_overrides` | Înlocuiește întreaga listă de excepții. Trimiteți `[]` pentru a reveni la valorile implicite ale rolului. |
| `status` | Doar `active` este acceptat, pentru a readuce un membru suspendat. Pentru a suspenda pe cineva, folosiți [endpoint-ul de suspendare](#suspend-a-team-member). |
| `auto_assign_enabled` | `true` sau `false`. |
| `contact_scope` | `all` sau `assigned`. |
| `contact_scope_unassigned` | `true` sau `false`. |
| `contact_scope_axes` | Consultați [Limitarea a ceea ce poate vedea un membru](#limiting-what-a-member-can-see). |
| `sub_account_access` | Doar pentru agenții. |

> **Acesta este singurul endpoint unde `null` înseamnă „ștergere”.** Trimiterea `"contact_scope": null`, `"contact_scope_axes": null` sau `"sub_account_access": null` elimină complet acea limită și readuce membrul la starea în care vede totul. La creare și invitație, `null` înseamnă pur și simplu „nefurnizat”.

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

**Răspuns**

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

| Status | Când |
|---|---|
| `400` | O valoare `status` sau `auto_assign_enabled` invalidă, sau ați încercat să reactivați un membru care a fost eliminat (membrii eliminați trebuie reinvitați). |
| `403` | Nu aveți permisiunea sau modificarea ar edita sau crea un acces mai larg decât al dumneavoastră. |
| `404` | Nu există un astfel de membru al echipei. |

---

## Suspendați un membru al echipei

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

Suspendă pe cineva: își păstrează locul în echipă, dar pierde accesul. Folosiți acest lucru în loc de eliminare atunci când pauza este temporară — readuceți-i cu `PATCH /team/members/{memberUid}` și `{"status": "active"}`.

**cURL**

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

**Răspuns**

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

Un membru suspendat **eliberează locul**, astfel încât să puteți invita pe altcineva în locul său. Accesul lor se încheie când tokenul sesiunii curente se reînnoiește, ceea ce poate dura până la o oră — eliminați-i în schimb dacă aveți nevoie ca acest lucru să fie imediat.

| Status | Când |
|---|---|
| `400` | Ați încercat să suspendați proprietarul contului sau un membru care este deja suspendat sau eliminat. |
| `403` | Accesul lor este mai larg decât al dumneavoastră. |
| `404` | Nu există un astfel de membru al echipei. |

---

## Eliminarea unui membru al echipei

`DELETE /team/members/{memberUid}`

Elimină o persoană din echipa ta și eliberează locul ocupat de aceasta. Membrul respectiv este deconectat și pierde accesul la contul tău; propriile sale date de autentificare rămân intacte.

**cURL**

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

**Răspuns**

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

Eliminarea este permanentă din partea ta: un membru eliminat **nu poate fi reactivat** prin endpoint-ul de actualizare — invită-l din nou dacă te răzgândești. Adresa sa de e-mail este, de asemenea, eliminată din lista de notificări a contului tău.

| Status | Când |
|---|---|
| `400` | Ai încercat să elimini proprietarul contului. |
| `403` | Accesul acestuia este mai extins decât al tău. |
| `404` | Nu există un astfel de membru al echipei. |

---

## Limitarea vizibilității unui membru

Trei câmpuri opționale, acceptate la [adăugare](#add-a-team-member-directly), [actualizare](#update-a-team-member) și [invitare](#send-an-invitation), decid cât de mult din cont poate vedea o persoană. Acestea se cumulează: un membru limitat prin mai mult de unul este limitat de toate acestea.

**`contact_scope`** — `all` (implicit: fiecare contact și conversație) sau `assigned` (doar cele care îi sunt alocate). Cu `assigned`, adaugă `"contact_scope_unassigned": true` pentru a-i permite să vadă și contactele care nu aparțin nimănui încă.

**`contact_scope_axes`** — îi limitează la agenți, canale sau departamente numite:

| Câmp | Tip | Descriere |
|---|---|---|
| `agents` | string[] | ID-uri de agenți. Aceștia văd doar chat-urile direcționate către unul dintre acești agenți. Maxim 200. |
| `channels` | string[] | Numele canalelor — `whatsapp`, `whatsapp_web`, `sms`, `instagram`, `instagram_private`, `messenger`, `facebook`, `chat_widget`, `telegram`, `line`, `viber`, `tiktok`, `imessage`, `email`, `linkedin`, `skool`, `custom`, `custom_channel`. Maxim 200. |
| `departments` | string[] | ID-uri de departamente (vezi [Departamente](#departments)). Aceștia văd doar lead-urile înregistrate în cadrul acestora. Maxim 200. |
| `include_unrouted` | boolean | Cu `agents` setat, afișează și chat-urile care nu sunt gestionate de niciun agent. Dezactivat implicit. Ignorat când `agents` este gol. |
| `include_undepartmented` | boolean | Cu `departments` setat, afișează și chat-urile care nu aparțin niciunui departament. Dezactivat implicit. Ignorat când `departments` este gol. |

ID-urile agenților și departamentelor nu sunt verificate atunci când le salvezi — un ID care nu există pur și simplu nu corespunde cu nimic, ceea ce apare ca o căsuță de primire goală în loc de o eroare. Numele canalelor **sunt** verificate: unul nerecunoscut este respins cu `400`.


Niciunul dintre aceste trei nu poate fi setat pentru proprietarul contului — acea cerere este refuzată cu `400`.

---

## Listare invitații

`GET /team/invites`

Invitațiile pe care le-ai trimis, cele mai noi primele, astfel încât să poți vedea cine nu a acceptat încă.

**Parametri de interogare**

| Parametru | Obligatoriu | Descriere |
|---|---|---|
| `status` | Nu | Returnează doar invitațiile în această stare — `pending`, `accepted`, `declined`, `cancelled` sau `expired`. |

**cURL**

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

**Răspuns**

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

Tokenul de invitație nu este returnat niciodată — acesta există doar în e-mailul care a fost trimis.

---

## Trimiterea unei invitații

`POST /team/invites`

Trimite prin e-mail cuiva o invitație de a se alătura echipei tale. Aceasta este modalitatea obișnuită de a adăuga un coechipier: acesta dă clic pe link, se conectează cu propriile date și acceptă. Dacă nu are încă un cont <span data-t="appName">Your AI Connector</span>, i se creează unul, iar e-mailul îl ghidează prin procesul de setare a unei parole.

**Câmpuri de solicitare**

| Câmp | Obligatoriu | Descriere |
|---|---|---|
| `email` | Da | Unde să trimiți invitația. |
| `role` | Da | `admin`, `editor` sau `viewer`. |
| `permission_overrides` | Nu | Excepții pe zonă, aplicate în momentul în care acceptă. |
| `contact_scope` | Nu | Aplicat când acceptă. |
| `contact_scope_unassigned` | Nu | Aplicat când acceptă. |
| `contact_scope_axes` | Nu | Aplicat când acceptă. |
| `sub_account_access` | Nu | Doar pentru agenții. Aplicat când acceptă. |

Setarea permisiunilor în prealabil înseamnă că nu trebuie să editezi membrul ulterior — totul este copiat în calitatea lor de membru atunci când acceptă.

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

**Răspuns** — `201 Created`

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

**Aspecte de planificat**

- **Invitațiile expiră după 7 zile.** O invitație expirată poate fi retrimisă, ceea ce resetează perioada de 7 zile.
- **Invitațiile în așteptare ocupă un loc.** Spre deosebire de adăugarea directă a unui membru, verificarea locurilor aici numără membrii activi *plus* invitațiile în așteptare, astfel încât un cont care are toate locurile ocupate va fi refuzat înainte ca e-mailul să fie trimis.
- **20 de invitații pe zi**, numărate per cont, atât pentru trimitere, cât și pentru retrimitere.

| Status | Când |
|---|---|
| `400` | `email` lipsește sau rolul este invalid. |
| `403` | Nu ai permisiunea de a gestiona echipa sau ai încercat să oferi un nivel de acces mai mare decât al tău. |
| `409` | Există deja o invitație în așteptare pentru acel e-mail sau acea persoană este deja în echipa ta. |
| `429` | Locurile din echipa planului tău sunt ocupate sau ai atins limita de 20 de invitații pe zi. Mesajul `error` specifică care dintre acestea. |

---

## Anularea unei invitații

`DELETE /team/invites/{inviteId}`

Retrage o invitație înainte ca aceasta să fie acceptată. Linkul din e-mail nu va mai funcționa.

**cURL**

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

**Răspuns**

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

Atât invitațiile `pending`, cât și cele `expired` pot fi anulate. O invitație care a fost deja acceptată, refuzată sau anulată returnează `400`; una care nu vă aparține returnează `403`; un ID necunoscut returnează `404`.

---

## Retrimiterea unei invitații

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

Trimite din nou e-mailul de invitație — pentru situațiile în care a fost omis sau a ajuns în spam. Funcționează pentru invitațiile `pending` și `expired` și resetează data expirării la 7 zile de acum înainte.

**cURL**

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

**Răspuns**

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

Noul e-mail conține un link nou, iar **vechiul link continuă de asemenea să funcționeze**, astfel încât o persoană care găsește primul e-mail mai târziu nu va fi blocată. Retrimiterea se contorizează în limita de 20 pe zi, la fel ca trimiterea inițială, iar reactivarea unei invitații *expirate* verifică din nou locurile disponibile — un plan complet va fi refuzat cu `429`.

---

## Acceptarea unei invitații

`POST /team/invites/accept`

Acceptă o invitație folosind tokenul din e-mailul de invitație, adăugând persoana autentificată în echipa contului respectiv.

> **Aceasta este o acțiune care ține de propria identitate.** Conectați-vă cu propriul cont — acțiunea este refuzată în mod deliberat cu `403` în timp ce lucrați în interiorul contului altcuiva.

**Câmpuri de solicitare**

| Câmp | Obligatoriu | Descriere |
|---|---|---|
| `invite_token` | Da | Tokenul din linkul e-mailului de invitație. |

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

**Răspuns**

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

| Status | Când |
|---|---|
| `400` | `invite_token` lipsește sau invitația este pentru propriul cont. |
| `403` | Sesiunea este activă în interiorul altui cont sau invitația a fost trimisă la o altă adresă de e-mail decât cea cu care sunteți autentificat. |
| `404` | Invitația nu există sau a fost deja utilizată. |
| `429` | Locurile contului s-au ocupat între momentul invitației și cel al acceptării. |
| `504` | Invitația a expirat. Cereți expeditorului să o retrimită. |

---

## Refuzarea unei invitații

`POST /team/invites/decline`

Refuză o invitație folosind tokenul din e-mail. La fel ca acceptarea, aceasta este o acțiune care ține de propria identitate și este refuzată în timp ce lucrați în interiorul altui cont.

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

**Răspuns**

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

---

## Departamente

Un **departament** este un grup numit din echipa ta — Vânzări, Relații cu clienții, Resurse Umane. Acesta oferă unui lead o echipă responsabilă, poate prelua singur conversații noi și poate fi utilizat pentru a limita ceea ce vede un membru.

> **Aceste patru endpoint-uri necesită o cheie API.** Spre deosebire de restul acestei pagini, ele se autentifică la fel ca orice alt endpoint din API (vezi [Autentificare](authentication.md)). O sesiune autentificată funcționează de asemenea: citirea necesită `contacts` la `view`, iar crearea, modificarea sau ștergerea necesită `team_management` la `edit`.

**Obiectul departament**

| Câmp | Tip | Descriere |
|---|---|---|
| `id` | string | ID-ul departamentului. Folosește-l în `contact_scope_axes.departments` și în căile de mai jos. |
| `name` | string | Cum se numește echipa. Până la 60 de caractere, unic în cont. |
| `color` | string \| null | Culoare de accent ca `#rrggbb`, sau `null`. |
| `member_uids` | string[] | Membrii echipei din acest departament. Poate include proprietarul contului. |
| `auto_assign_enabled` | boolean | Dacă un lead înregistrat în acest departament este, de asemenea, atribuit cuiva din cadrul acestuia. `false` înseamnă că departamentul lucrează dintr-o coadă partajată. |
| `routing_agents` | string[] | Conversațiile noi gestionate de acești Agenți AI sunt înregistrate automat în acest departament. Gol înseamnă nicio regulă pentru agent. |
| `routing_channels` | string[] | Conversațiile noi pe aceste canale sunt înregistrate aici automat. Gol înseamnă nicio regulă pentru canal. |
| `created_by` | string \| null | Cine l-a creat. |

Când atât `routing_agents` cât și `routing_channels` sunt setate, o conversație trebuie să corespundă **ambelor** pentru a fi înregistrată aici — așa poți oferi unei echipe „agentul de suport, dar numai pe WhatsApp”.

Un cont poate avea până la **50** de departamente.

### Listarea departamentelor

`GET /team/departments`

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

**Răspuns**

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

### Crearea unui departament

`POST /team/departments`

**Câmpuri de solicitare**

| Câmp | Obligatoriu | Descriere |
|---|---|---|
| `name` | Da | Până la 60 de caractere. Nu trebuie să coincidă cu un departament existent. |
| `color` | Nu | `#rrggbb` hex, sau `null`. |
| `member_uids` | Nu | Cine face parte din el. Fiecare UID trebuie să fie proprietarul contului sau un membru **activ** al echipei. |
| `auto_assign_enabled` | Nu | Implicit `true`. |
| `routing_agents` | Nu | ID-urile agenților ale căror chat-uri noi ajung aici. |
| `routing_channels` | Nu | Numele canalelor ale căror chat-uri noi ajung aici — același vocabular ca `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"]
```

**Răspuns** — `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"
  }
}
```

| Status | Când |
|---|---|
| `400` | `name` lipsește sau este prea lung, `color` nu este `#rrggbb`, un nume de canal nu este recunoscut, un UID listat nu este un membru activ al acestei echipe sau ai deja 50 de departamente. |
| `409` | Un departament cu acel nume există deja. |

### Actualizarea unui departament

`PATCH /team/departments/{departmentId}`

Modifică un departament. Doar câmpurile pe care le trimiți sunt modificate.

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

**Răspuns**

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

Trimiterea unor câmpuri nerecunoscute returnează `400`; un departament necunoscut returnează `404`; un nume care intră în conflict cu un alt departament returnează `409`.

### Ștergerea unui departament

`DELETE /team/departments/{departmentId}`

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

**Răspuns**

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

> **Ștergerea unui departament la care cineva este restricționat este refuzată.** Răspunsul `400` enumeră membrii a căror vizibilitate este limitată la acesta, astfel încât să îi puteți reconfigura mai întâi. Acest lucru este deliberat: eliminarea silențioasă a restricțiilor le-ar oferi acces la întreaga bază de clienți fără nicio notificare că acest lucru s-a întâmplat.

Contactele înregistrate sub un departament șters nu sunt modificate — pur și simplu nu mai afișează niciun departament, iar data viitoare când le veți înregistra, modificarea va fi salvată.

---

## Verificarea propriilor permisiuni

`GET /team/permissions`

Returnează acțiunile pe care persoana autentificată are voie să le efectueze în contul în care lucrează în prezent. Utilizați acest lucru pentru a ascunde butoanele pe care un membru nu le poate folosi, în loc să îi permiteți să descopere limitarea printr-o eroare.

**cURL**

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

**Răspuns — proprietarul contului**

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

**Răspuns — un membru al echipei care lucrează în interiorul unui cont**

```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` este `owner` atunci când persoana autentificată este proprietarul contului; în caz contrar, este rolul său în echipă. `member` este prezent doar în modul echipă și conține `contact_scope`, `contact_scope_unassigned` și `contact_scope_axes` atunci când apartenența lor le include.

---

## Tokenuri de sesiune

Cinci endpoint-uri generează un token de autentificare de unică folosință pentru comutarea între conturi. Toate răspund în același mod:

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

Tokenul este schimbat pentru o sesiune cu SDK-ul client Firebase. **Acesta nu este o cheie API și nu poate fi trimis ca atare**, motiv pentru care aceste endpoint-uri sunt utile doar în interiorul unei aplicații proprii.

| Endpoint | Ce face | Corp |
|---|---|---|
| `POST /team/tokens/team-member` | Permite unui membru al echipei să înceapă lucrul în interiorul unui cont din care face parte. | `account_owner_uid` (obligatoriu) |
| `POST /team/tokens/return-from-team` | Îi readuce înapoi, în propriul cont. | — |
| `POST /team/tokens/assist` | Permite personalului <span data-t="appName">Your AI Connector</span> să deschidă contul unui client pentru a oferi asistență. Doar pentru personal. | `customerUid` |
| `POST /team/tokens/return-to-admin` | Încheie o sesiune de asistență și returnează personalul în propriul cont. | — |
| `POST /team/tokens/agency-assist` | Permite unei agenții să deschidă unul dintre sub-conturile sale de client — sau, dacă este apelat fără unul, să revină la contul agenției. | `subAccountUid` (opțional) |

Fiecare refuză cu `403` atunci când sesiunea nu are dreptul la acest lucru: nu este membru al acelui cont, nu este personal, acel sub-cont nu aparține agenției tale sau nu ți-a fost acordat, ori sesiunea nu se află în prezent în modul în care se termină endpoint-ul.

---

## Atribuirea unui rol de platformă

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

Setează rolul de **platformă** al unui utilizator — `User`, `Dev`, `Support` sau `Agency`. Aceasta nu reprezintă calitatea de membru al unei echipe: este tipul de cont <span data-t="appName">Your AI Connector</span> pe care îl are cineva.

Acest endpoint este restricționat pentru personalul <span data-t="appName">Your AI Connector</span>, iar ultimul `Dev` rămas nu poate fi retrogradat. Listat pentru completitudine; nu face parte din gestionarea propriei echipe.

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

| Status | Când |
|---|---|
| `400` | `role` lipsește sau nu este unul dintre cele patru, sau acest lucru ar elimina ultimul `Dev`. |
| `403` | Nu ești personal sau sesiunea lucrează în interiorul altui cont. |
| `404` | Nu există un astfel de utilizator. |

---

## Erori API echipă

Endpoint-urile de echipă returnează plicul de eroare standard, întotdeauna cu `error_code` alături de statusul HTTP:

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

| Status | Când se întâmplă pe un endpoint de echipă |
|---|---|
| `400` | Un câmp obligatoriu lipsește sau este invalid, ori acțiunea nu este permisă în această stare (reactivarea unui membru eliminat, suspendarea proprietarului, ștergerea unui departament la care cineva este limitat). |
| `401` | Ai trimis o cheie API către un endpoint care necesită o persoană autentificată — vezi [Autentificare](#authentication-these-endpoints-need-a-signed-in-person). |
| `403` | Nu ai permisiunea `team_management`, modificarea depășește propriul tău acces sau acțiunea este refuzată în timp ce lucrezi în interiorul altui cont. |
| `404` | Nu există un astfel de membru, invitație, departament sau utilizator. |
| `409` | Este deja membru al echipei, există deja o invitație în așteptare sau există un departament cu acel nume. |
| `429` | Locurile în echipă sunt ocupate, limita de 20 de invitații pe zi a fost atinsă sau ai atins limita de rată API. |
| `504` | Invitația pe care ai încercat să o accepți a expirat. |

Codurile partajate pe care orice endpoint le poate returna — `429` (limită de rată) și `500` — sunt listate cu îndrumări pentru reîncercare în [Erori și Paginare](errors-and-pagination.md).

---

## Legate

- [Gestionarea echipei](../settings/team-management.md) — aceleași funcționalități în tabloul de bord, cu capturi de ecran.
- [Autentificare](authentication.md) — cum să trimiți un token ID Firebase în loc de o cheie API.
- [API Contacte](contacts.md) — contactele la care se aplică limitele de vizibilitate ale unui membru.

