
# API Contacte

Un contact este o persoană căreia îi trimiți mesaje — numele, numărul de telefon, adresa de e-mail, canalul, etichetele, câmpurile personalizate, precum și listele și campaniile din care face parte. API-ul de Contacte îți permite să creezi contacte, să le cauți, să le actualizezi, să le etichetezi, să le imporți în masă și să le elimini, totul fără a utiliza tabloul de bord.

Toate căile de pe această pagină sunt relative la URL-ul de bază:

```
https://api.youraiconnector.com/v1
```

Așadar, `/contacts` înseamnă `https://api.youraiconnector.com/v1/contacts`.

> **Ești nou în utilizarea API-ului?** Citește mai întâi [Acces API](../integrations/api-access.md) — acesta acoperă modul de generare a cheii API, cele trei metode de autentificare, limitele de rată și formatul erorilor. Tot ce este pe această pagină presupune că ai deja o cheie API funcțională.

---

## Despre ID-urile de contact

Fiecare contact are un ID unic. ID-ul pe care îl primești atunci când **creezi** un contact (în `data.contactId`) este același ID pe care îl folosești peste tot în altă parte — pentru a prelua, actualiza, eticheta, trimite un mesaj sau șterge acel contact. Salvează-l o dată și refolosește-l.

Nu trebuie să creezi un contact pentru a-i obține ID-ul. De asemenea, îl poți căuta după numărul de telefon sau adresa de e-mail (vezi [Obține un contact](#get-a-contact-by-phone-or-email)) sau poți parcurge toate contactele (vezi [Listează contactele](#list-contacts)). Fiecare dintre acestea returnează același ID.

---

## Creează un contact

`POST /contacts`

Adaugă un contact nou în contul tău. Este **obligatoriu un număr de telefon cu prefix de țară** — o adresă de e-mail nu este suficientă. Orice altceva este opțional.

Poți, opțional, să adaugi noul contact direct într-una sau mai multe liste folosind `listId` (o singură listă) sau `listIds` (o matrice). Dacă sunt trimise ambele, `listIds` are prioritate.

Orice câmp pe care îl trimiți și care nu este unul dintre câmpurile standard de creare enumerate în tabelul de câmpuri **Creează un contact** de mai jos (`phoneNumber`, `firstName`, `lastName`, `email`, `channel`, `is_bot_active`, `is_private`, `lead_profile`, `listId`, `listIds`, `custom_fields`) este stocat automat ca un **câmp personalizat** — astfel încât un payload plat de la un instrument precum Make sau Zapier funcționează fără imbricare. De asemenea, poți transmite un obiect `custom_fields` explicit.

| Câmp | Obligatoriu | Descriere |
|---|---|---|
| `phoneNumber` | Da | Numărul de telefon al contactului, cu prefix de țară (de ex. `+15551234567`). |
| `firstName` | Nu | Prenume. |
| `lastName` | Nu | Nume de familie. |
| `email` | Nu | Adresă de e-mail. |
| `channel` | Nu | Canal de mesagerie. Unul dintre `whatsapp`, `sms`, `whatsapp_web`. Implicit este `whatsapp`. |
| `is_bot_active` | Nu | Dacă asistentul AI răspunde acestui contact. Implicit este `true`. |
| `is_private` | Nu | Marchează contactul ca privat. Când este `true`, asistentul AI este dezactivat pentru acesta. Implicit este `false`. |
| `lead_profile` | Nu | Note text libere despre lead. |
| `listId` | Nu | Un singur ID de listă în care să adaugi contactul. |
| `listIds` | Nu | O matrice de ID-uri de liste în care să adaugi contactul (are prioritate față de `listId`). |
| `custom_fields` | Nu | Un obiect cu propriile tale câmpuri cheie/valoare. Poți, de asemenea, să le transmiți ca chei de nivel superior. |

**cURL**

```bash
curl -X POST "https://api.youraiconnector.com/v1/contacts?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phoneNumber": "+15551234567",
    "firstName": "Jane",
    "lastName": "Smith",
    "email": "jane@example.com",
    "is_bot_active": true,
    "listIds": ["list123", "list456"]
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.youraiconnector.com/v1/contacts", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    phoneNumber: "+15551234567",
    firstName: "Jane",
    lastName: "Smith",
    email: "jane@example.com",
    is_bot_active: true,
    listIds: ["list123", "list456"],
  }),
});
const data = await res.json();
console.log(data.data.contactId);
```

**Python**

```python
import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/contacts",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "phoneNumber": "+15551234567",
        "firstName": "Jane",
        "lastName": "Smith",
        "email": "jane@example.com",
        "is_bot_active": True,
        "listIds": ["list123", "list456"],
    },
)
print(res.json()["data"]["contactId"])
```

**Răspuns**

```json
{
  "success": true,
  "data": {
    "message": "Successfully created new contact",
    "contactId": "contact_abc123",
    "listsAdded": ["list123", "list456"]
  }
}
```

ID-ul noului contact se află la `data.contactId`. Listele în care a fost adăugat sunt returnate în `data.listsAdded`.

> **Nu se creează duplicate.** Dacă un contact cu același număr de telefon există deja, apelul de creare **nu** îl creează și nici nu îl returnează. Răspunsul revine cu starea HTTP `200` și un `error_code` de `409` în corp, deci verifică `error_code` în loc de starea HTTP:
>
> ```json
> { "success": false, "error_code": 409, "error": "A contact with this phone number already exists for the current user." }
> ```
>
> Pentru a lucra cu un contact existent după un `error_code` de `409`, caută-l cu [Obține un contact prin telefon sau e-mail](#get-a-contact-by-phone-or-email) — `GET /contacts?phoneNumber=...` — și refolosește ID-ul pe care îl returnează.

> **Scrierile echivalente în WhatsApp sunt considerate același număr.** Unele țări au două moduri valide de scriere pentru aceeași linie mobilă, iar WhatsApp poate raporta oricare dintre ele: Mexic (`+52…` și varianta veche `+521…`), Brazilia (cu sau fără a noua cifră) și Argentina (cu sau fără `9` după `+54`). Verificarea duplicatelor la creare și potrivirea `GET /contacts?phoneNumber=` funcționează pentru ambele moduri de scriere, astfel încât veți primi înapoi contactul existent indiferent de forma pe care o trimiteți. `phone_number` stocat în contact nu este niciodată suprascris.

---

## Obține un contact prin telefon sau e-mail

`GET /contacts?phoneNumber=...` sau `GET /contacts?email=...`

Caută un singur contact și returnează obiectul complet și îmbogățit al contactului — incluzând listele, etichetele și campaniile sale rezolvate în perechi `{ id, name }`, plus ultimul mesaj schimbat.

Transmite **fie** `phoneNumber` (în format internațional), **fie** `email`. Dacă nu transmiți niciunul, acest endpoint comută în schimb la modul [Listare contacte](#list-contacts).

**cURL**

```bash
curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts?phoneNumber=%2B15551234567&apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const phone = encodeURIComponent("+15551234567");
const res = await fetch(`https://api.youraiconnector.com/v1/contacts?phoneNumber=${phone}`, {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
console.log(data.contact);
```

**Python**

```python
import requests

res = requests.get(
    "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"phoneNumber": "+15551234567"},
)
print(res.json()["contact"])
```

**Răspuns**

```json
{
  "success": true,
  "contactId": "contact_abc123",
  "contact": {
    "id": "contact_abc123",
    "firstName": "Jane",
    "lastName": "Smith",
    "email": "jane@example.com",
    "phoneNumber": "+15551234567",
    "channel": "whatsapp",
    "isBotActive": true,
    "isPrivate": false,
    "doNotDisturb": false,
    "lead_profile": null,
    "avatarUrl": "https://example.com/photo.jpg",
    "customFields": {},
    "lists": [{ "id": "list123", "name": "VIP customers" }],
    "tags": [{ "id": "tagHotLead", "name": "Hot lead" }],
    "campaigns": [{ "id": "campaign789", "name": "Spring promo" }],
    "currentCampaign": { "id": "campaign789", "name": "Spring promo" },
    "lastMessage": {
      "direction": "inbound",
      "body": "Sounds good, thanks!",
      "status": "received",
      "timestamp": "2026-06-09T10:21:00.000Z"
    }
  }
}
```

ID-ul contactului este returnat atât la nivelul superior (`contactId`), cât și în interiorul obiectului (`contact.id`). Dacă nu există nicio potrivire, primești un `404` cu `{ "success": false, "message": "Contact not found" }`.

> **`avatarUrl`** este fotografia de profil a contactului, preluată din WhatsApp sau Meta atunci când vă trimite un mesaj. Este doar în citire: nu o puteți seta și este `null` pentru contactele care nu au o fotografie sau care vă contactează printr-un canal care nu partajează una. Tratați linkul ca fiind temporar în loc să îl stocați, deoarece unele dintre aceste linkuri către fotografii expiră și sunt reîmprospătate automat. (În punctul final al listei de mai jos, aceeași valoare este numită `avatar_url`.)

> **Numere de telefon în URL-uri.** Un semn `+` dintr-un șir de interogare trebuie să fie codificat URL ca `%2B`, altfel este citit ca un spațiu. Exemplele de mai sus fac acest lucru pentru tine.

---

## Obțineți un contact după ID

`GET /contacts/{contactId}`

Când aveți deja ID-ul unui contact, preluați-l direct. Structura răspunsului este identică cu cea a căutării de mai sus.

**cURL**

```bash
curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123?apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123", {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
console.log(data.contact);
```

**Python**

```python
import requests

res = requests.get(
    "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
print(res.json()["contact"])
```

Un ID de contact care nu există în contul dvs. va returna un `404`.

---

## Obține statisticile contactului

`GET /contacts/{contactId}/stats`

Returnează statistici agregate ale mesajelor pentru un contact: totaluri, răspunsuri AI vs. umane, credite consumate și marcaje temporale pentru primul/ultimul mesaj.

**cURL**

```bash
curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/stats?apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/stats", {
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
console.log(data.totalMessages, data.creditsUsed);
```

**Python**

```python
import requests

res = requests.get(
    "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/stats",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
print(data["totalMessages"], data["creditsUsed"])
```

**Răspuns**

```json
{
  "success": true,
  "totalMessages": 48,
  "sent": 21,
  "received": 27,
  "aiReplies": 18,
  "humanReplies": 3,
  "creditsUsed": 34,
  "botMessageCount": 18,
  "firstMessageAt": "2026-05-01T09:00:00.000Z",
  "lastMessageAt": "2026-06-09T10:21:00.000Z"
}
```

`botMessageCount` este același contor de mesaje AI pe care butonul „reset” din aplicație îl resetează pentru un contact. `creditsUsed` este totalul curent de credite pentru acest contact, nu doar cifrele acestui răspuns. Un ID de contact care nu există în contul tău returnează un `404`.

---

## Listare contacte

`GET /contacts`

Apelați `GET /contacts` **fără** `phoneNumber` sau `email` pentru a parcurge toate contactele, începând cu cele mai noi. Fiecare pagină returnează rezumate compacte ale contactelor (listele, etichetele și campaniile sunt returnate ca matrice de ID-uri, nu ca obiecte complete) și un `next_cursor`.

| Parametru de interogare | Descriere |
|---|---|
| `limit` | Dimensiunea paginii. Valoarea implicită este 50, maxim 100. |
| `cursor` | Valoarea `next_cursor` din pagina anterioară. Omiteți-o pe prima pagină. |
| `listId` | Opțional. Returnează doar contactele care aparțin acestei liste. |

Pentru a parcurge fiecare pagină: efectuați primul apel fără cursor, apoi continuați să transmiteți `next_cursor` returnat ca `cursor`. **Opriți-vă când `next_cursor` este `null`** — acest lucru înseamnă că nu mai există rezultate.

**cURL**

```bash
curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts?limit=50&apiKey=YOUR_API_KEY"

# next page:
curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts?limit=50&cursor=contact_abc123&apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
async function listAllContacts() {
  const all = [];
  let cursor = null;
  do {
    const url = new URL("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts");
    url.searchParams.set("limit", "100");
    if (cursor) url.searchParams.set("cursor", cursor);
    const res = await fetch(url, { headers: { "X-API-Key": "YOUR_API_KEY" } });
    const data = await res.json();
    all.push(...data.contacts);
    cursor = data.next_cursor;
  } while (cursor);
  return all;
}
```

**Python**

```python
import requests

def list_all_contacts():
    all_contacts = []
    cursor = None
    while True:
        params = {"limit": 100}
        if cursor:
            params["cursor"] = cursor
        res = requests.get(
            "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts",
            headers={"X-API-Key": "YOUR_API_KEY"},
            params=params,
        )
        data = res.json()
        all_contacts.extend(data["contacts"])
        cursor = data["next_cursor"]
        if not cursor:
            break
    return all_contacts
```

**Răspuns**

```json
{
  "success": true,
  "contacts": [
    {
      "id": "contact_abc123",
      "first_name": "Jane",
      "last_name": "Smith",
      "email": "jane@example.com",
      "phone_number": "+15551234567",
      "channel": "whatsapp",
      "is_bot_active": true,
      "is_private": false,
      "do_not_disturb": false,
      "avatar_url": "https://example.com/photo.jpg",
      "custom_fields": {},
      "created_at": "2026-06-01T09:00:00.000Z",
      "list_ids": ["list123"],
      "tag_ids": ["tagHotLead"],
      "campaign_ids": ["campaign789"],
      "current_campaign_id": "campaign789"
    }
  ],
  "next_cursor": "contact_abc123"
}
```

::: note
**Notă:** Filtrarea după un `listId` care nu există în contul tău returnează un `404`. Un `cursor` nevalid returnează un `400`.
:::


---

## Numărarea contactelor

`GET /contacts/count`

Returnează numărul de contacte care corespund unui filtru, plus o defalcare pe canal, fără a fi nevoie de paginare. Acesta este apelul potrivit pentru orice întrebare de tipul „câte sunt” — pentru un element de tablou de bord, o automatizare sau pentru a întreba Champ. Toate filtrele sunt opționale, iar combinarea mai multora restrânge numărătoarea (un contact trebuie să corespundă fiecăruia dintre ele).

| Parametru de interogare | Descriere |
|---|---|
| `agentId` | Doar contactele alocate acestui agent AI. Trimiteți `none` pentru contactele fără un agent alocat (cele care sunt gestionate de agentul implicit al canalului). |
| `channel` | Doar contactele de pe acest canal, de ex. `whatsapp`, `messenger`, `instagram`, `sms`, `email`, `chat_widget`. |
| `tag` | Doar contactele care poartă această etichetă, după **numele** etichetei (majusculele/minusculele nu contează). Un nume de etichetă pe care nu îl aveți returnează `404`. |
| `listId` | Doar contactele din această listă. |
| `botActive` | `true` sau `false` — doar contactele al căror asistent AI este activat sau dezactivat. |
| `status` | Doar contactele cu acest status, de ex. `Lead`. |
| `rules` | Un obiect JSON de reguli codificat URL, folosind aceeași formă ca o listă inteligentă (consultați [Forma `smart_rules`](#the-smart_rules-shape) mai jos). Nu poate fi combinat cu celelalte filtre. |

Dacă nu trimiteți niciun filtru, veți primi numărul total de contacte din contul dumneavoastră.

**cURL**

```bash
# everything
curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/count?apiKey=YOUR_API_KEY"

# only the contacts one agent handles on Messenger
curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/count?agentId=agent_xyz789&channel=messenger&apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const url = new URL("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/count");
url.searchParams.set("agentId", "agent_xyz789");
url.searchParams.set("channel", "messenger");

const res = await fetch(url, { headers: { "X-API-Key": "YOUR_API_KEY" } });
const data = await res.json();
console.log(data.total);
```

**Python**

```python
import requests

res = requests.get(
    "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/count",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"agentId": "agent_xyz789", "channel": "messenger"},
)
data = res.json()
print(data["total"])
```

**Răspuns**

```json
{
  "success": true,
  "total": 3423,
  "by_channel": { "messenger": 2744, "instagram": 667, "none": 12 },
  "filters": { "agentId": "agent_xyz789" }
}
```

`by_channel` împarte același total pe canal; contactele care nu sunt pe niciun canal sunt numărate sub `none`. `filters` returnează filtrele care au fost aplicate, astfel încât să puteți verifica dacă apelul a făcut ceea ce ați dorit.

::: note
**Notă:** Trimiterea `rules` împreună cu orice alt filtru sau o valoare `rules` care nu este un JSON valid returnează `400`. Un nume de etichetă sau un ID de listă care nu există în contul dumneavoastră returnează `404`.
:::


---

## Actualizarea unui contact

`PUT /contacts/{contactId}`

Actualizează un contact existent. Doar câmpurile pe care le incluzi sunt modificate — omite tot ce nu dorești să atingi. Trebuie să trimiți cel puțin un câmp, altfel vei primi un `400` („Nu există câmpuri de actualizat”).

| Câmp | Descriere |
|---|---|
| `firstName` | Prenume. |
| `lastName` | Nume de familie. |
| `email` | Adresă de e-mail. |
| `is_bot_active` | Dacă asistentul AI răspunde acestui contact. |
| `is_private` | Marchează ca privat. Setarea acestei opțiuni pe `true` dezactivează, de asemenea, asistentul AI. |
| `do_not_disturb` | Întrerupe comunicarea automată cu acest contact. De asemenea, oprește AI-ul din a răspunde. |
| `follow_ups_disabled` | Oprește toate mesajele de follow-up automate pentru acest contact (rapide, ciclice și pentru lead-uri reci) în timp ce AI-ul continuă să răspundă la mesajele trimise de acesta. Util după ce cineva a efectuat o achiziție. Rămâne dezactivat până când îl setați înapoi la `false`. |
| `lead_profile` | Note despre lead sub formă de text liber. |
| `custom_fields` | Un obiect de câmpuri personalizate. **Îmbinate per cheie** — sunt scrise doar cheile pe care le trimiteți, restul câmpurilor personalizate existente sunt păstrate. Puteți, de asemenea, să transmiteți chei de câmpuri personalizate la nivelul superior. |

**cURL**

```bash
curl -X PUT "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "firstName": "Jane", "do_not_disturb": true }'
```

**JavaScript**

```javascript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123", {
  method: "PUT",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ firstName: "Jane", do_not_disturb: true }),
});
const data = await res.json();
console.log(data.message);
```

**Python**

```python
import requests

res = requests.put(
    "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"firstName": "Jane", "do_not_disturb": True},
)
print(res.json()["message"])
```

**Răspuns**

```json
{
  "success": true,
  "message": "Contact updated successfully"
}
```

> **Câmpurile personalizate sunt îmbinate, nu înlocuite.** Trimiterea `{ "custom_fields": { "tier": "gold" } }` setează doar `tier` — orice alte câmpuri personalizate de pe contact rămân exact așa cum erau. Pentru a elimina complet un câmp personalizat din toate contactele, folosește [Ștergerea unui câmp personalizat](#delete-a-custom-field).

---

## Adăugarea sau eliminarea etichetelor

`POST /contacts/{contactId}/tags`

Adaugă și/sau elimină etichete de pe un singur contact într-un singur apel. Transmite **ID-urile** etichetelor în `addTagIds` și `removeTagIds`. Cel puțin unul dintre cele două trebuie să fie nevid.

Etichetele trebuie să existe deja în contul tău — creează-le mai întâi prin [endpoint-ul de etichete](reference.md). Dacă contactul sau oricare dintre etichetele referențiate nu există, vei primi un `404`.

| Câmp | Descriere |
|---|---|
| `addTagIds` | Matrice de ID-uri de etichete de adăugat la contact. |
| `removeTagIds` | Matrice de ID-uri de etichete de eliminat din contact. |

**cURL**

```bash
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/tags?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "addTagIds": ["tagHotLead"], "removeTagIds": ["tagColdLead"] }'
```

**JavaScript**

```javascript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/tags", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    addTagIds: ["tagHotLead"],
    removeTagIds: ["tagColdLead"],
  }),
});
const data = await res.json();
console.log(data.added, data.removed);
```

**Python**

```python
import requests

res = requests.post(
    "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/tags",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"addTagIds": ["tagHotLead"], "removeTagIds": ["tagColdLead"]},
)
data = res.json()
print(data["added"], data["removed"])
```

**Răspuns**

```json
{
  "success": true,
  "contact_id": "contact_abc123",
  "added": 1,
  "removed": 1
}
```

---

## Gestionează biblioteca de etichete

Aceste endpoint-uri gestionează eticheta în sine — redenumirea sau ștergerea acesteia din contul tău — spre deosebire de aplicarea sau eliminarea unei etichete de pe un contact (vezi [Adăugarea sau eliminarea etichetelor](#add-or-remove-tags) mai sus). Fiecare etichetă din contul tău are un ID (`tagId`): cel afișat în managerul de etichete din tabloul de bord și cel returnat ca `data.tag_id` atunci când creezi o etichetă cu `POST /tags` și un corp JSON de `{ "name": "..." }` (fără `phoneNumber`, `email` sau `contactId`).

### Actualizarea unei etichete

`PUT /tags/{tagId}`

Trimite doar câmpurile pe care le modifici.

| Câmp | Descriere |
|---|---|
| `name` | Numele etichetei. |

```bash
curl -X PUT "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/tags/tagHotLead?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Hot lead (Q3)" }'
```

**Răspuns**

```json
{ "success": true, "tag_id": "tagHotLead" }
```

Un `tagId` care nu există în contul tău returnează un `404`.

### Ștergerea unei etichete

`DELETE /tags/{tagId}`

Șterge o etichetă după ID. **Această acțiune nu poate fi anulată** — contactele care poartă eticheta o vor pierde pur și simplu. Ștergerea unei etichete care a fost deja eliminată (sau care nu a existat niciodată) returnează `200` cu `deleted: 0` în loc de `404`, deoarece nu există nimic de enumerat.

```bash
curl -X DELETE "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/tags/tagColdLead?apiKey=YOUR_API_KEY"
```

**Răspuns**

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

### Ștergerea mai multor etichete simultan

`DELETE /tags`

| Câmp | Descriere |
|---|---|
| `tagIds` | Matrice de ID-uri de etichete de șters (max 1000). |

```bash
curl -X DELETE "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/tags?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "tagIds": ["tagColdLead", "tagUnsubscribed"] }'
```

**Răspuns**

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

ID-urile care nu există sau aparțin altui cont sunt omise silențios și nu sunt numărate în `deleted`.

---

## Setare în masă a unui indicator

`POST /contacts/bulk-flag`

Setează un indicator boolean pentru mai multe contacte simultan. Până la 500 de ID-uri de contact per cerere. ID-urile care nu există în contul tău sunt omise și numărate în `skipped`.

| Câmp | Descriere |
|---|---|
| `contactIds` | Matrice de ID-uri de contact de actualizat (max 500). |
| `field` | Ce indicator să setezi. Unul dintre `bot_active` (asistent AI pornit/oprit), `dnd` (întrerupere comunicare automată), `spam`, `private`. |
| `value` | Valoarea booleană la care să setezi indicatorul. |

**cURL**

```bash
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/bulk-flag?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contactIds": ["contactId1", "contactId2"],
    "field": "bot_active",
    "value": false
  }'
```

**JavaScript**

```javascript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/bulk-flag", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    contactIds: ["contactId1", "contactId2"],
    field: "bot_active",
    value: false,
  }),
});
const data = await res.json();
console.log(data.updated, data.skipped);
```

**Python**

```python
import requests

res = requests.post(
    "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/bulk-flag",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "contactIds": ["contactId1", "contactId2"],
        "field": "bot_active",
        "value": False,
    },
)
data = res.json()
print(data["updated"], data["skipped"])
```

**Răspuns**

```json
{
  "success": true,
  "updated": 2,
  "skipped": 0
}
```

---

## Import în masă al contactelor

`POST /contacts/import`

Creează până la 500 de contacte într-un singur apel dintr-o matrice JSON. Fiecare înregistrare necesită un `phone_number` în format internațional; tot restul este opțional. Înregistrările cu numere de telefon invalide sau canale neacceptate sunt **omise** (nu sunt create), iar fiecare înregistrare omisă este raportată cu indicele și motivul său — astfel încât să puteți corecta doar eșecurile și să reîncercați.

Numerele de telefon care există deja în contul dvs. sunt omise implicit ca `duplicate`. Trimiteți `updateExisting: true` pentru a **actualiza** acele contacte în schimb: câmpurile prezente în înregistrare suprascriu datele contactului (`first_name`, `last_name`, `email`, `lead_profile` și `custom_fields` sunt îmbinate cheie cu cheie), `tags` sunt adăugate, iar contactul este adăugat la `listId`. Canalul, numărul de telefon și indicatorii botului nu sunt niciodată modificați pentru un contact existent.

Puteți adăuga opțional fiecare contact importat (sau actualizat) la o listă cu `listId`, seta un `defaultChannel` pentru înregistrările care nu specifică unul și eticheta înregistrările cu `tags` (numele etichetelor — etichetele lipsă sunt create, cele existente sunt potrivite indiferent de majuscule/minuscule).

**Câmpuri de nivel superior**

| Câmp | Obligatoriu | Descriere |
|---|---|---|
| `contacts` | Da | Matrice de înregistrări de contacte (max 500). |
| `listId` | Nu | Listă la care să fie adăugat fiecare contact importat (și actualizat). Trebuie să fie o listă din contul dvs. |
| `defaultChannel` | Nu | Canal aplicat înregistrărilor care omit `channel`. Unul dintre `whatsapp`, `sms`, `whatsapp_web`. Implicit este `whatsapp`. |
| `updateExisting` | Nu | `true` pentru a actualiza contactele al căror număr de telefon există deja, în loc să le omiteți ca `duplicate`. Implicit este `false`. |

**Câmpuri per înregistrare**

| Câmp | Obligatoriu | Descriere |
|---|---|---|
| `phone_number` | Da | Număr de telefon în format internațional (un `+` inițial este adăugat dacă lipsește). |
| `first_name` | Nu | Prenume. |
| `last_name` | Nu | Nume de familie. |
| `email` | Nu | Adresă de e-mail. |
| `channel` | Nu | Unul dintre `whatsapp`, `sms`, `whatsapp_web`. Revine la `defaultChannel`. |
| `is_bot_active` | Nu | Dacă asistentul AI răspunde. Implicit este `true`. |
| `is_private` | Nu | Marchează ca privat. Implicit este `false`. |
| `lead_profile` | Nu | Note despre lead în text liber. |
| `custom_fields` | Nu | Obiect de chei și valori pentru câmpuri personalizate. |
| `tags` | Nu | Matrice de nume de etichete (funcționează și un singur șir `"a; b"`). Etichetele care nu există sunt create; cele existente sunt potrivite ignorând majusculele/minusculele. Max 25 per înregistrare. |

**cURL**

```bash
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/import?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contacts": [
      { "phone_number": "+12025551234", "first_name": "Ann", "last_name": "Lee", "tags": ["vip", "newsletter"] },
      { "phone_number": "+12025551235", "first_name": "Bob" }
    ],
    "listId": "list123",
    "defaultChannel": "whatsapp_web",
    "updateExisting": true
  }'
```

**JavaScript**

```javascript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/import", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    contacts: [
      { phone_number: "+12025551234", first_name: "Ann", last_name: "Lee", tags: ["vip", "newsletter"] },
      { phone_number: "+12025551235", first_name: "Bob" },
    ],
    listId: "list123",
    defaultChannel: "whatsapp_web",
    updateExisting: true,
  }),
});
const data = await res.json();
console.log(`Imported ${data.imported}, updated ${data.updated}, skipped ${data.skipped.length}`);
```

**Python**

```python
import requests

res = requests.post(
    "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/import",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "contacts": [
            {"phone_number": "+12025551234", "first_name": "Ann", "last_name": "Lee", "tags": ["vip", "newsletter"]},
            {"phone_number": "+12025551235", "first_name": "Bob"},
        ],
        "listId": "list123",
        "defaultChannel": "whatsapp_web",
        "updateExisting": True,
    },
)
data = res.json()
print(f"Imported {data['imported']}, updated {data['updated']}, skipped {len(data['skipped'])}")
```

**Răspuns**

```json
{
  "success": true,
  "imported": 2,
  "contact_ids": ["contact_abc123", "contact_def456"],
  "updated": 0,
  "updated_contact_ids": [],
  "skipped": []
}
```

Dacă unele înregistrări nu pot fi create, acestea apar în `skipped` cu motivul (aici fără `updateExisting`, deci numărul existent este omis):

```json
{
  "success": true,
  "imported": 1,
  "contact_ids": ["contact_abc123"],
  "updated": 0,
  "updated_contact_ids": [],
  "skipped": [
    { "index": 1, "phone_number": "+12025551235", "reason": "duplicate" }
  ]
}
```

Cu `updateExisting: true`, aceeași cerere raportează contactul existent sub `updated` / `updated_contact_ids` în schimb.

Motive posibile pentru omitere: `invalid_record`, `missing_phone_number`, `invalid_phone_number`, `invalid_channel`, `duplicate_in_request`, `duplicate`, `contact_limit_reached`, `create_failed`.

> **Limite de plan.** Dacă limita de contacte a planului dvs. nu permite un număr atât de mare de contacte noi, întreaga solicitare este respinsă din start cu un `403`. Dacă limita este atinsă pe parcurs, înregistrările rămase sunt returnate ca omise cu motivul `contact_limit_reached`.

---

## Importă contacte dintr-un fișier CSV

Pentru importuri mai mari decât cele suportate de [importul în masă](#bulk-import-contacts) (până la aproximativ 50.000 de rânduri), puneți la coadă o sarcină de import asincron pentru un fișier CSV deja existent în stocarea contului dvs., apoi interogați-l până la finalizare.

### Începe importul

`POST /contacts/import-csv`

| Câmp | Obligatoriu | Descriere |
|---|---|---|
| `csvStoragePath` | Da | Calea de stocare a fișierului CSV, sub `users/{your account id}/imports/`, terminându-se în `.csv`. |
| `listName` | Da | Creează (sau reutilizează) o listă cu acest nume și adaugă fiecare contact importat în ea. |
| `existingListRefs` | Nu | Matrice de ID-uri de liste existente în care să fie adăugat, de asemenea, fiecare contact importat. |
| `defaultChannel` | Nu | Canal aplicat rândurilor care nu specifică unul. |

```bash
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/import-csv?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "csvStoragePath": "users/abc123/imports/leads.csv",
    "listName": "Webinar signups"
  }'
```

**JavaScript**

```javascript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/import-csv", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    csvStoragePath: "users/abc123/imports/leads.csv",
    listName: "Webinar signups",
  }),
});
const data = await res.json();
console.log(data.job_id);
```

**Python**

```python
import requests

res = requests.post(
    "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/import-csv",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "csvStoragePath": "users/abc123/imports/leads.csv",
        "listName": "Webinar signups",
    },
)
job_id = res.json()["job_id"]
```

**Răspuns** (`202` — importul este pus la coadă, nu este încă finalizat)

```json
{
  "success": true,
  "job_id": "csvimp_abc123",
  "status": "queued"
}
```

> **Introducerea fișierului în stocare.** Acest endpoint pornește și urmărește sarcina de import; nu acceptă el însuși o încărcare. Fișierul CSV trebuie să fie deja la `csvStoragePath` înainte de a-l apela — propriul importator CSV al tabloului de bord face acest lucru ca prim pas.

### Interoghează jobul de import

`GET /contacts/import-csv/{jobId}`

```bash
curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/import-csv/csvimp_abc123?apiKey=YOUR_API_KEY"
```

**Răspuns**

```json
{
  "success": true,
  "job_id": "csvimp_abc123",
  "status": "completed",
  "imported": 812,
  "updated": 0,
  "skipped": 14,
  "errors": [],
  "error_message": null
}
```

`status` trece prin `queued` → `processing` → `completed` sau `failed` cu motivul în `error_message`. Un `jobId` care nu există în contul dvs. returnează un `404`.

---

## Exportă contacte

Inițiază un export CSV asincron al contactelor dvs. și returnează o sarcină pe care o puteți interoga pentru finalizare.

### Începe exportul

`POST /contacts/export`

| Câmp | Obligatoriu | Descriere |
|---|---|---|
| `listId` | Nu | Exportă doar contactele care aparțin acestei liste. |
| `contactIds` | Nu | Exportă doar aceste ID-uri de contact specifice. |

Dacă le lași pe ambele necompletate, se vor exporta toate contactele din contul tău.

```bash
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/export?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "listId": "list123" }'
```

**JavaScript**

```javascript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/export", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ listId: "list123" }),
});
const data = await res.json();
console.log(data.job_id);
```

**Python**

```python
import requests

res = requests.post(
    "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/export",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"listId": "list123"},
)
job_id = res.json()["job_id"]
```

**Răspuns** (`202` — exportul este pus în coadă)

```json
{
  "success": true,
  "job_id": "export_abc123",
  "status": "queued"
}
```

### Interoghează starea exportului

`GET /contacts/export/{jobId}`

```bash
curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/export/export_abc123?apiKey=YOUR_API_KEY"
```

**Răspuns**

```json
{
  "success": true,
  "job_id": "export_abc123",
  "status": "completed",
  "export_id": "exp_xyz789",
  "contact_count": 812,
  "error_message": null
}
```

> Odată ce `status` este `"completed"`, vei primi `export_id` și `contact_count`. Descărcarea fișierului CSV generat se face din pagina Exporturi a tabloului tău de bord.

---

## Trimite un mesaj către un contact

`POST /contacts/{contactId}/send-message`

Trimite un mesaj unui contact existent pe canalul pe care acesta se află deja. Mesajul este pus în coadă și livrat în fundal — răspunsul confirmă că a fost acceptat, nu că a fost deja livrat.

| Câmp | Obligatoriu | Descriere |
|---|---|---|
| `body` | Da | Textul mesajului de trimis. |
| `mediaUrl` | Nu | URL-ul unui fișier media de atașat. |
| `mediaContentType` | Nu | Tipul MIME al fișierului media atașat (de ex. `image/jpeg`). |

**cURL**

```bash
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/send-message?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "body": "Hi! Your appointment is confirmed." }'
```

**JavaScript**

```javascript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/send-message", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ body: "Hi! Your appointment is confirmed." }),
});
const data = await res.json();
console.log(data.messageId);
```

**Python**

```python
import requests

res = requests.post(
    "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/send-message",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"body": "Hi! Your appointment is confirmed."},
)
print(res.json()["messageId"])
```

**Răspuns**

```json
{
  "success": true,
  "messageId": "aB3dE5fG7hI9jK1lM2nO",
  "contactId": "contact_abc123",
  "channel": "whatsapp",
  "message": "Message created successfully. Delivery is being processed."
}
```

> **Nu poți trimite acum?** Dacă persoana de contact are activat modul „nu deranja” sau modul privat, ori nu se află pe un canal care poate primi mesaje de ieșire, cererea este respinsă cu un `422` și un `error` explicativ.

Pentru trimiterea prin număr de telefon, ID de Instagram sau altă identitate de canal în loc de un ID de contact — și pentru mai multe informații despre mesagerie în general — consultă [Messages API](messages.md).

---

## Atribuie un agent AI unui contact

`POST /contacts/{contactId}/assign-agent`

Mută o conversație existentă către un alt agent AI, începând cu următorul mesaj. Este același lucru cu **Atribuire agent AI** din meniul unui chat și este aceeași acțiune pe care o folosește pasul **Atribuie agent AI sau campanie** în Automatizări.

| Câmp | Obligatoriu | Descriere |
|---|---|---|
| `agentId` | Da | ID-ul agentului AI care ar trebui să preia conversația sau `null` pentru a șterge atribuirea, astfel încât conversația să revină în inbox-ul echipei tale. |
| `triggerAIResponse` | Nu | `true` determină noul agent atribuit să răspundă imediat la ultimele mesaje fără răspuns ale contactului. Valoarea implicită este `false`. |

> **Atenție la `triggerAIResponse: true`** — acesta trimite contactului un mesaj pe loc, așa că folosiți-l doar atunci când doriți ca acesta să primească mesajul imediat. Pe Messenger și Instagram, acel mesaj eșuează dacă contactul v-a scris ultima dată acum mai mult de 24 de ore.

**cURL**

```bash
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/assign-agent?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "agentId": "agent_xyz789" }'
```

**JavaScript**

```javascript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/assign-agent", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ agentId: "agent_xyz789" }),
});
const data = await res.json();
console.log(data.data.agentId);
```

**Python**

```python
import requests

res = requests.post(
    "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/assign-agent",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"agentId": "agent_xyz789"},
)
print(res.json()["data"]["agentId"])
```

**Răspuns**

```json
{
  "success": true,
  "data": {
    "contactId": "contact_abc123",
    "agentId": "agent_xyz789",
    "aiResponseTriggered": false
  }
}
```

> Agentul trebuie să aparțină aceluiași cont ca și contactul; în caz contrar, cererea este respinsă cu o eroare `404` sau `403`. Găsește ID-urile agenților pe pagina Agenți AI (URL-ul fiecărui agent se termină cu ID-ul său).

---

## Alocarea unui agent AI către mai multe contacte

`POST /contacts/bulk-assign-agent`

Mută mai multe conversații către un alt agent AI într-un singur apel — sau șterge alocarea pentru toate acestea cu `null`. Este pur și simplu o modificare de rutare: **nu se trimite niciun mesaj și agentul nu răspunde nimănui**. Fiecare contact primește pur și simplu noul agent data viitoare când scrie. (De aceea nu există `triggerAIResponse` aici.)

| Câmp | Obligatoriu | Descriere |
|---|---|---|
| `agentId` | Da | Agentul AI care ar trebui să preia sarcina sau `null` pentru a șterge alocarea. |
| `contactIds` | Unul dintre cele trei | Până la 500 de ID-uri de contact de mutat. |
| `filter` | Unul dintre cele trei | Selectați contactele de pe server în loc să le listați, cele mai noi primele. Utilizează aceleași chei ca filtrele endpoint-ului de numărare: `agentId` (sau `none`), `channel`, `tag`, `listId`, `botActive`, `status`. |
| `rules` | Unul dintre cele trei | Un obiect de reguli pentru listă inteligentă — consultați [Forma `smart_rules`](#the-smart_rules-shape). |
| `limit` | Nu | Câte contacte să mutați în acest apel când selectați cu `filter` sau `rules`. De la 1 la 500, implicit 500. |

Trimiteți exact unul dintre `contactIds`, `filter` sau `rules`.

**cURL**

```bash
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/bulk-assign-agent?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agentId": "agent_xyz789",
    "filter": { "agentId": "agent_abc123", "channel": "messenger" }
  }'
```

**JavaScript**

```javascript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/bulk-assign-agent", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    agentId: "agent_xyz789",
    filter: { agentId: "agent_abc123", channel: "messenger" },
  }),
});
const data = await res.json();
console.log(data.updated, data.remaining);
```

**Python**

```python
import requests

res = requests.post(
    "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/bulk-assign-agent",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "agentId": "agent_xyz789",
        "filter": {"agentId": "agent_abc123", "channel": "messenger"},
    },
)
data = res.json()
print(data["updated"], data["remaining"])
```

**Răspuns**

```json
{
  "success": true,
  "agentId": "agent_xyz789",
  "matched": 3415,
  "updated": 500,
  "skipped": 0,
  "remaining": 2915,
  "filters": { "agentId": "agent_abc123" }
}
```

`matched` reprezintă câte contacte a găsit selecția în total, `updated` câte au fost mutate prin acest apel, `skipped` câte dintre ID-urile trimise nu au fost găsite în contul dumneavoastră și `remaining` câte mai corespund acum după finalizarea apelului.

**Mutarea tuturor.** Deoarece un apel mută cel mult 500 de contacte, un grup mare necesită câteva apeluri. Folosiți un filtru care încetează să mai corespundă unui contact odată ce acesta a fost mutat — de exemplu `filter: { "agentId": "agent_abc123" }` în timp ce alocați către `agent_xyz789` — și repetați exact același apel până când `remaining` revine ca `0`. Când trimiteți `contactIds` în schimb, `remaining` este întotdeauna `0`.

---

## Alocă un contact unui departament

`POST /contacts/{contactId}/department`

„Alocă acest lead către Vânzări” — înregistrează un contact sub un departament numit și, în mod implicit, îl atribuie persoanei din acel departament care are în prezent cele mai puține contacte. Aceasta este o acțiune separată de [alocarea unui agent AI](#assign-an-ai-agent-to-a-contact): un departament răspunde la întrebarea „ce echipă deține acest lucru”, un agent răspunde la „ce AI răspunde la acest lucru”, iar setarea uneia nu o șterge niciodată pe cealaltă.

| Câmp | Obligatoriu | Descriere |
|---|---|---|
| `department_id` | Da | Departamentul sub care se înregistrează contactul. Trimite `null` pentru a-l șterge. |
| `hand_to_member` | Nu | De asemenea, atribuie contactul persoanei cu cea mai mică încărcare din acel departament. Valoarea implicită este `true`. Nu realocă niciodată un contact pe care cineva îl deține deja. |

**cURL**

```bash
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/department?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "department_id": "dept_sales" }'
```

**JavaScript**

```javascript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/department", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ department_id: "dept_sales" }),
});
const data = await res.json();
console.log(data.assigned_to);
```

**Python**

```python
import requests

res = requests.post(
    "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/department",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"department_id": "dept_sales"},
)
print(res.json()["assigned_to"])
```

**Răspuns**

```json
{
  "success": true,
  "department_id": "dept_sales",
  "assigned_to": "member_uid_123"
}
```

`assigned_to` este `null` atunci când contactul era deja deținut de cineva sau ai trimis `hand_to_member: false`.

---

## Conectează un contact prin mai multe canale

„Continuă pe WhatsApp” (sau SMS) găsește sau creează contactul acestei persoane pe un alt canal bazat pe telefon și le leagă între ele, astfel încât restul aplicației să le recunoască drept aceeași persoană.

### Conectarea la un alt canal

`POST /contacts/{contactId}/link-channel`

| Câmp | Obligatoriu | Descriere |
|---|---|---|
| `channel` | Da | Canalul la care se face conectarea. Unul dintre `whatsapp`, `whatsapp_web`, `sms`. |
| `phoneNumber` | Nu | Numărul de telefon de utilizat pe noul canal. Implicit este numărul propriu al contactului sursă. |

```bash
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/link-channel?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "channel": "sms" }'
```

**Răspuns**

```json
{
  "success": true,
  "data": {
    "contact_id": "contact_def456",
    "person_id": "person_xyz789",
    "created": true
  }
}
```

`created` vă indică dacă un contact nou a fost creat pentru canalul țintă sau dacă a fost găsit și conectat unul existent. Apelarea acestei funcții a doua oară este sigură — returnează același `contact_id` cu `created: false` în loc să creeze un duplicat.

O eroare `422` înseamnă că contul nu poate efectua această conectare în acest moment: contactul se află deja în acea familie de canale, nu are un număr de telefon de utilizat sau nu există niciun expeditor conectat pentru canalul țintă. O eroare `409` înseamnă că cele două contacte sunt deja conectate la două persoane diferite — deconectați-l pe unul mai întâi.

### Listarea conversațiilor conectate ale unui contact

`GET /contacts/{contactId}/linked`

Returnează celelalte conversații care reprezintă aceeași persoană ca acest contact. Un contact neconectat returnează o matrice goală, nu o eroare `404` — „această persoană nu are alte canale” este o stare normală.

```bash
curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/linked?apiKey=YOUR_API_KEY"
```

**Răspuns**

```json
{
  "success": true,
  "data": [
    {
      "contact_id": "contact_def456",
      "channel": "sms",
      "custom_channel": null,
      "first_name": "Jane",
      "last_name": "Smith",
      "phone_number": "+15551234567",
      "last_message": "Sounds good, thanks!",
      "last_message_timestamp": "2026-06-09T10:21:00.000Z",
      "linked_from": {
        "contact_id": "contact_abc123",
        "channel": "whatsapp",
        "linked_at": "2026-06-01T09:00:00.000Z",
        "reason": "continue_on_channel"
      }
    }
  ]
}
```

### Deconectarea unui contact

`DELETE /contacts/{contactId}/link`

Elimină acest contact din persoana sa, unilateral — orice alte contacte încă legate de acea persoană își păstrează conexiunea, deci deconectarea unuia din trei nu dizolvă grupul.

```bash
curl -X DELETE "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/link?apiKey=YOUR_API_KEY"
```

**Răspuns**

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

---

## Preluarea fotografiei de profil a unui contact

`POST /contacts/{contactId}/profile-pic`

Preluarea (și stocarea în cache) fotografiei de profil WhatsApp sau Meta a contactului la cerere — aceeași fotografie returnată ca `avatarUrl` în [Obținere contact](#get-a-contact-by-phone-or-email), actualizată.

```bash
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123/profile-pic?apiKey=YOUR_API_KEY"
```

**Răspuns**

```json
{
  "success": true,
  "avatar_url": "https://example.com/photo.jpg",
  "cached": false
}
```

`cached: true` înseamnă că URL-ul provine dintr-o preluare recentă, nu dintr-o căutare proaspătă la furnizor — fotografiile sunt stocate în cache timp de 7 zile, iar un contact despre care furnizorul raportează că nu are nicio fotografie accesibilă este stocat ca indisponibil timp de 24 de ore. Când nu există nicio fotografie de preluat, `avatar_url` este omis și `message` explică motivul.

---

## Etichetarea automată a contactelor cu AI

Rulează regulile de etichetare ale contului tău peste istoricul complet al conversațiilor unuia sau mai multor contacte și aplică (sau elimină) etichete exact ca etichetarea în timp real care rulează în timpul unui chat live — aceleași reguli, același cost de credite per etichetă.

### Începe o rulare

`POST /contacts/auto-tag`

| Câmp | Obligatoriu | Descriere |
|---|---|---|
| `scope` | Da | `"contacts"` pentru a eticheta contacte specifice sau `"agent"` pentru a eticheta fiecare conversație gestionată în prezent de un agent AI. |
| `contact_ids` | Obligatoriu când `scope` este `"contacts"` | Matrice de ID-uri de contact, de la 1 la 500. |
| `agent_id` | Obligatoriu când `scope` este `"agent"` | Agentul AI ale cărui conversații trebuie etichetate. Când `scope` este `"contacts"`, acesta este opțional și doar restrânge regulile de etichetare ale agentului care rulează. |

```bash
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/auto-tag?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "scope": "contacts", "contact_ids": ["contact_abc123", "contact_def456"] }'
```

Un **singur** contact rulează inline și returnează rezultatul imediat:

```json
{ "success": true, "result": { "tags_applied": 2, "tags_removed": 0 } }
```

**Două sau mai multe** contacte (sau `scope: "agent"`) rulează ca un job de fundal și returnează `202` imediat:

```json
{ "success": true, "run_id": "m1x2y3-a1b2c3d4", "total": 214 }
```

### Interoghează o rulare

`GET /contacts/auto-tag/run`

Returnează rularea curentă (sau cea mai recentă) a contului, astfel încât să poți interoga progresul fără a urmări singur `run_id`.

```bash
curl "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/auto-tag/run?apiKey=YOUR_API_KEY"
```

**Răspuns**

```json
{
  "success": true,
  "run": {
    "run_id": "m1x2y3-a1b2c3d4",
    "status": "running",
    "total": 214,
    "processed": 58,
    "tagged_contacts": 12,
    "tags_applied": 15,
    "tags_removed": 2,
    "credits_charged": 15
  }
}
```

`run` este `null` atunci când contul nu a început niciodată una. `status` trece de la `"running"` la `"completed"` sau `"failed"`.

Doar o singură rulare în masă poate fi în curs per cont la un moment dat — pornirea unei a doua în timp ce alta rulează returnează `409` cu `error_code: "auto_tag_run_in_progress"`. Epuizarea creditelor în timpul unei rulări pentru un singur contact returnează `402` cu `error_code: "insufficient_credits"`; o rulare în masă se oprește în schimb mai devreme și raportează cât de departe a ajuns în `run`.

---

## Șterge un contact

`DELETE /contacts/{contactId}`

Șterge permanent un contact după ID, împreună cu istoricul mesajelor sale. **Această acțiune nu poate fi anulată.** Pentru a șterge mai multe contacte într-un singur apel, folosește [Șterge contacte](#delete-contacts) mai jos.

**cURL**

```bash
curl -X DELETE "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123?apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123", {
  method: "DELETE",
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
console.log(data.success);
```

**Python**

```python
import requests

res = requests.delete(
    "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/contact_abc123",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
print(res.json()["success"])
```

**Răspuns**

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

Un ID de contact care nu există în contul tău sau care aparține unui alt cont va returna o eroare `404`.

---

## Ștergerea contactelor

`DELETE /contacts`

Șterge definitiv unul sau mai multe contacte după ID într-un singur apel (până la 500 de ID-uri). ID-urile care nu există în contul tău sunt omise și numărate în `skipped`. **Această acțiune nu poate fi anulată.**

| Câmp | Descriere |
|---|---|
| `contactIds` | Matrice de ID-uri de contact de șters (max 500). |

**cURL**

```bash
curl -X DELETE "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "contactIds": ["contactId1", "contactId2"] }'
```

**JavaScript**

```javascript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts", {
  method: "DELETE",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ contactIds: ["contactId1", "contactId2"] }),
});
const data = await res.json();
console.log(`Deleted ${data.deleted}, skipped ${data.skipped}`);
```

**Python**

```python
import requests

res = requests.delete(
    "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"contactIds": ["contactId1", "contactId2"]},
)
data = res.json()
print(f"Deleted {data['deleted']}, skipped {data['skipped']}")
```

**Răspuns**

```json
{
  "success": true,
  "deleted": 2,
  "skipped": 0
}
```

---

## Șterge un câmp personalizat

`DELETE /contacts/custom-fields/{fieldKey}`

Elimină o cheie de câmp personalizat din **fiecare** contact din contul tău. Folosește această opțiune pentru a face curățenie după redenumirea sau eliminarea unui câmp personalizat. Cheia poate conține doar litere, cifre, caractere de subliniere și cratime. Returnează numărul de contacte actualizate. **Această acțiune nu poate fi anulată.**

**cURL**

```bash
curl -X DELETE "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/custom-fields/webinar_date_nh?apiKey=YOUR_API_KEY"
```

**JavaScript**

```javascript
const res = await fetch("<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/custom-fields/webinar_date_nh", {
  method: "DELETE",
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();
console.log(`Removed from ${data.updated} contacts`);
```

**Python**

```python
import requests

res = requests.delete(
    "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/contacts/custom-fields/webinar_date_nh",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
print(f"Removed from {res.json()['updated']} contacts")
```

**Răspuns**

```json
{
  "success": true,
  "updated": 42
}
```

::: note
**Notă:** O cheie de câmp cu caractere neacceptate returnează un `400`.
:::


---

## Liste

Listele grupează contacte. O listă este fie **statică** (tu decizi cine face parte din ea), fie **inteligentă** (apartenența este calculată pe baza unor reguli și menținută la zi automat — vezi [Organizarea listelor și a contactelor](../get-started/list-and-contact-management.md#smart-lists-auto-updating)).

| Câmp | Descriere |
|---|---|
| `name` | Obligatoriu la creare. Până la 100 de caractere. |
| `status` | `live` (implicit) sau `draft`. Cu litere mici. |
| `contact_ids` | Matrice de ID-uri de contacte de adăugat în listă. **Doar pentru liste statice.** |
| `type` | `static` (implicit) sau `smart`. |
| `smart_rules` | Setul de reguli — obligatoriu când `type` este `smart`. Vezi mai jos. |

### Crearea unei liste

`POST /lists`

```bash
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/lists?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "name": "Hot leads (active)",
        "type": "smart",
        "smart_rules": {
          "match": "all",
          "conditions": [
            { "field": "tags", "op": "has_any", "value": ["tagHotLead"] },
            { "field": "last_activity_at", "op": "within_last", "value": { "amount": 90, "unit": "days" } }
          ]
        }
      }'
```

**Răspuns**

```json
{
  "success": true,
  "list_id": "list_abc123",
  "evaluation": { "added": 3, "removed": 0, "total": 3 }
}
```

O listă inteligentă este evaluată **inline**, în aceeași cerere, deci `evaluation` îți spune exact cine a ajuns în ea. În cazul unei liste statice, `evaluation` este `null`.

### Actualizarea unei liste

`PUT /lists/{listId}`

Trimite doar câmpurile pe care le modifici. Modificarea `smart_rules` reevaluează lista imediat și returnează același obiect `evaluation`.

```bash
curl -X PUT "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/lists/list_abc123?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "smart_rules": { "match": "any", "conditions": [ { "field": "tags", "op": "has_any", "value": ["tagHotLead", "tagWebinar"] } ] } }'
```

Poți schimba tipul unei liste între cele două variante:

- **Statică → inteligentă**: trimite `{ "type": "smart", "smart_rules": { … } }`. Regulile preiau controlul pe loc.
- **Inteligentă → statică**: trimite `{ "type": "static" }`. Regulile sunt eliminate, iar cei care se află deja în listă rămân acolo.

### Structura `smart_rules`

```json
{
  "match": "all",
  "conditions": [
    { "field": "tags", "op": "has_any", "value": ["tagHotLead"] },
    { "field": "channel", "op": "is_any", "value": ["whatsapp", "sms"] },
    { "field": "last_incoming_message_at", "op": "not_within_last", "value": { "amount": 7, "unit": "days" } },
    { "field": "created_at", "op": "after", "value": "2026-01-01" },
    { "field": "is_bot_active", "op": "is", "value": true },
    { "field": "email", "op": "is_set" },
    { "field": "custom_field", "key": "Plan", "op": "eq", "value": "pro" }
  ]
}
```

- `match` — `all` (toate condițiile trebuie să fie adevărate) sau `any` (cel puțin una).
- `conditions` — între 1 și 20 de condiții, fiecare cu cel mult 100 de valori, șiruri de caractere de până la 200 de caractere.

| `field` | `op` | `value` |
|---|---|---|
| `tags` | `has_any`, `has_all`, `has_none` | matrice de ID-uri de etichete |
| `lists` | `in_any`, `not_in_any` | matrice de ID-uri de liste (**doar liste statice** — o listă inteligentă nu poate fi creată dintr-o altă listă inteligentă) |
| `channel` | `is_any`, `is_none` | matrice de canale |
| `status` | `is_any`, `is_none` | matrice de stări ale contactelor |
| `created_at`, `last_activity_at`, `last_incoming_message_at`, `last_outgoing_message_at`, `first_ai_interaction_at`, `last_ai_interaction_at` | `within_last`, `not_within_last` | `{ "amount": 1–3650, "unit": "hours" \| "days" }` |
| aceleași câmpuri de dată | `before`, `after` | dată ISO (`"2026-01-01"`, comparată ca zile întregi) sau dată-oră ISO completă (`"2026-01-01T14:30:00Z"`, comparată cu momentul exact) |
| aceleași câmpuri de dată | `is_set`, `not_set` | — |
| `has_interacted_with_ai` | `is` | `true` / `false` — `true` potrivește contactele cărora AI-ul le-a trimis cel puțin un mesaj (vreodată) |
| `is_bot_active`, `do_not_disturb`, `is_private`, `has_ever_responded` | `is` | `true` / `false` |
| `email`, `phone_number`, `first_name`, `last_name` | `is_set`, `not_set`, `contains`, `not_contains` | șir pentru formularele `contains` |
| `current_campaign_id`, `assigned_agent` | `is_any`, `is_none`, `is_set`, `not_set` | matrice de ID-uri pentru formularele `is_any` / `is_none` |
| `custom_field` (plus un `key`) | `eq`, `neq`, `contains`, `not_contains`, `is_set`, `not_set` | șir pentru formularele de valoare |

`not_within_last` potrivește, de asemenea, contactele pentru care data nu a fost setată niciodată ("mai mult de N în urmă, **sau niciodată**"), iar comparațiile de text ignoră diferența dintre literele mari și mici.

**Interacțiunea AI.** `has_interacted_with_ai` este indicatorul pe întreaga durată de viață: `true` pentru fiecare contact căruia AI-ul tău i-a trimis cel puțin un mesaj, `false` pentru toți ceilalți (inclusiv contactele la care a răspuns doar echipa ta). Acesta este marcat la primul mesaj al AI-ului către un contact și nu este șters niciodată, deci dezactivarea răspunsurilor AI pentru contact sau mutarea acestuia într-o altă campanie nu îl resetează. Pentru o *perioadă* — „contactele gestionate de AI-ul meu luna aceasta”, întrebarea obișnuită de facturare — folosește intervalul `last_ai_interaction_at`:

```json
{ "field": "last_ai_interaction_at", "op": "within_last", "value": { "amount": 30, "unit": "days" } }
```

Nu le confunda cu `is_bot_active` (AI-ul are *permisiunea* de a răspunde, nu înseamnă că a făcut-o) sau `has_ever_responded` (contactul a scris înapoi, oricui). Aceleași două marcaje sunt returnate pentru fiecare contact ca `first_ai_interaction_at` / `last_ai_interaction_at`, iar întregul set de reguli funcționează și pe `GET /contacts?rules=`, astfel încât poți număra potrivirile fără a crea o listă.

### Previzualizarea unui set de reguli

`POST /lists/preview`

Numără și eșantionează contactele pe care un set de reguli le-ar potrivi, fără a crea sau a modifica nimic. Folosiți această funcție pentru a verifica validitatea regulilor înainte de a le salva.

```bash
curl -X POST "<span data-t="apiBaseUrl">https://api.youraiconnector.com</span>/v1/lists/preview?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "smart_rules": { "match": "all", "conditions": [ { "field": "tags", "op": "has_any", "value": ["tagHotLead"] } ] } }'
```

**Răspuns**

```json
{
  "success": true,
  "count": 3,
  "sample": [
    {
      "id": "contact_abc123",
      "first_name": "Sofia",
      "last_name": "Martinez",
      "phone_number": "+31600000000",
      "email": "sofia@example.com",
      "channel": "whatsapp"
    }
  ]
}
```

`sample` reține până la 10 contacte, sortate descrescător după activitatea recentă.

### Rularea imediată a unei liste inteligente

`POST /lists/{listId}/evaluate`

Forțează o reevaluare imediată (același lucru pe care îl face **Reîmprospătare acum** în tabloul de bord). Listele inteligente se actualizează deja atunci când un contact se modifică și la fiecare 15 minute pentru regulile bazate pe timp, deci acest lucru este necesar doar atunci când doriți rezultatul *chiar acum*.

**Răspuns**

```json
{
  "success": true,
  "list_id": "list_abc123",
  "evaluation": { "added": 2, "removed": 1, "total": 4 }
}
```

`evaluation.skipped: true` înseamnă că o altă evaluare a aceleiași liste era deja în curs de desfășurare și acest apel nu a produs niciun efect.

### Listele inteligente refuză membrii selectați manual

Endpoint-urile de apartenență returnează **`409`** cu `"This is a smart list — its members are computed from its rules. Edit the rules instead."` atunci când lista țintă este inteligentă. Aceasta acoperă `POST /contacts/lists`, `DELETE /contacts/lists`, `POST /contacts/lists/batch`, `contact_ids` pe `POST /lists` și `PUT /lists/{listId}`, precum și alegerea unei liste inteligente ca țintă pentru importul CSV. Modificați regulile în schimb.

Apelarea `POST /lists/{listId}/evaluate` pe o listă **statică** este, de asemenea, o `409` — aceasta nu are reguli de rulat.

---

## Erori API Contacte

Endpoint-urile pentru contacte returnează plicul standard de eroare:

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

Unele endpoint-uri includ, de asemenea, `error_code`, care de obicei corespunde stării HTTP — singura excepție este cazul contactului duplicat de mai jos, unde starea HTTP este `200` și doar `error_code` poartă `409`. Codurile specifice endpoint-urilor de contact:

| Cod | Când apare pe un endpoint de contact |
|---|---|
| `400` | Cerere incorectă — un câmp lipsă/invalid, corp gol, cursor greșit sau peste 500 de ID-uri într-un lot. |
| `402` | Credite insuficiente pentru a finaliza o rulare de etichetare AI pe un contact (`error_code: "insufficient_credits"`). |
| `404` | Contactul, lista sau eticheta nu a fost găsită în contul tău. |
| `409` | Un contact cu acel număr de telefon există deja (la creare). Returnat ca `error_code` în corp cu un status HTTP de `200`, deci ramifică pe `error_code` aici. De asemenea, returnat când o rulare de etichetare automată în masă este deja în desfășurare (`error_code: "auto_tag_run_in_progress"`) sau când legarea unui contact la un alt canal ar uni două contacte deja legate la două persoane diferite. |
| `422` | Contactul nu poate primi un mesaj în acest moment (nu deranja, privat sau canal neacceptat). Pe endpoint-ul de legătură a canalului, acoperă de asemenea lipsa numărului de telefon, o asociere de canal neacceptată sau lipsa unui expeditor conectat pentru canalul țintă. |

Un `403` pe un endpoint de contact poate însemna, de asemenea, o problemă de limită de contacte sau de permisiune a listei, mai degrabă decât accesul la plan. Codurile partajate pe care orice endpoint le poate returna — `401`, `403` (planul tău nu include acces API), `429` (limită de rată) și `500` — sunt enumerate cu instrucțiuni de reîncercare în [Erori și Paginare](errors-and-pagination.md).

---

## Pașii următori

- [API Mesaje](messages.md) — trimite mesaje prin identitatea canalului și gestionează conversațiile.
- [Referință API](reference.md) — listă completă de endpoint-uri, inclusiv etichete și liste.
- [Acces API](../integrations/api-access.md) — autentificare, limite de rată și gestionarea erorilor.
