
# API połączenia kanałów

Ten przewodnik pokazuje, jak łączyć kanały komunikacyjne z kontem za pomocą API. Jest przeznaczony dla programistów tworzących integrację lub wrapper, dlatego skupia się na dokładnych żądaniach, kolejności ich wykonywania oraz otrzymywanych odpowiedziach.

Istnieje jeden wzorzec, który musisz zrozumieć na wstępie, ponieważ ma on zastosowanie do prawie każdego kanału opisanego tutaj.

## Wzorzec połączenia z odpytywaniem (connect-then-poll)

Większości kanałów nie można połączyć za pomocą pojedynczego wywołania API. Połączenie WhatsApp, Instagrama lub Messengera oznacza, że właściciel konta musi zalogować się na swoje konto u dostawcy i zatwierdzić dostęp. **Nie istnieje ścieżka bezobsługowa (w pełni zautomatyzowana)** dla tego zatwierdzenia – prawdziwa osoba musi otworzyć adres URL w przeglądarce lub zeskanować kod QR telefonem.

Zatem przepływ zawsze wygląda następująco:

1. **Rozpocznij połączenie** za pomocą `POST`. Odpowiedź zawiera adres URL do otwarcia lub kod QR do wyświetlenia.
2. **Przekaż to użytkownikowi końcowemu** – otwórz adres URL w jego przeglądarce lub wyświetl kod QR na ekranie, aby mógł go zeskanować.
3. **Odpytuj punkt końcowy statusu** za pomocą `GET` w krótkich odstępach czasu (co kilka sekund), aż status osiągnie stan połączenia.

Zadaniem Twojej integracji jest obsługa tej pętli: wyświetlenie adresu URL lub kodu QR, a następnie odpytywanie aż do zakończenia. Zaplanuj interfejs użytkownika wokół odpytywania – dobrze sprawdza się wskaźnik ładowania z komunikatem „czekam na zakończenie w przeglądarce”.

::: note
**Uwaga:** Zanim zaczniesz, upewnij się, że dostęp do API jest włączony w planie i posiadasz klucz API. Zobacz [Dostęp do API](../integrations/api-access.md), aby dowiedzieć się, jak go wygenerować. Wszystkie poniższe żądania używają bazowego adresu URL `https://api.youraiconnector.com/v1` i musisz uwierzytelniać każde żądanie. Zobacz [Uwierzytelnianie](authentication.md), aby poznać cztery akceptowane formy – przykłady tutaj używają nagłówka `X-API-Key`, z jednym przykładem cURL na stronę pokazującym prostszą formę zapytania `?apiKey=`.
:::


---

## Instagram + Messenger (Meta)

Instagram i Messenger są łączone w jednym przepływie, ponieważ oba działają na Stronie na Facebooku. Właściciel konta autoryzuje dostęp przez Facebooka, Ty pobierasz listę Stron, którymi zarządza, i wybierasz, którą Stronę połączyć.

### Krok 1 – Rozpocznij połączenie Instagram + Messenger

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

To zwraca adres URL zgody. W tym żądaniu nie są przesyłane żadne dane uwierzytelniające – połączenie jest autoryzowane w całości w przeglądarce.

**cURL**

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

**JavaScript**

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

**Python**

```python
import requests

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

**Odpowiedź**

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

Otwórz `oauth_url` w przeglądarce użytkownika końcowego, aby mógł zalogować się do Facebooka i zatwierdzić dostęp. Próba połączenia wygasa o `expires_at` (około 30 minut) – jeśli wygaśnie, zacznij od nowa. Traktuj `state_token` jako krótkotrwały sekret i nie loguj go.

### Najprostsza opcja dla Instagram + Messenger: przekaż `connect_url`

Odpowiedź zawiera również gotowe rozwiązanie `connect_url`: hostowaną stronę, która przeprowadza posiadacza konta przez cały proces. Otwiera on ją, loguje się do Facebooka, a jeśli posiada więcej niż jedną stronę, wyświetla się lista umożliwiająca wybór tej, którą chce połączyć – następnie strona sama zgłasza powodzenie. Przekaż ten link posiadaczowi konta zamiast samodzielnego otwierania `oauth_url`, budowania selektora stron i odpytywania o status. Link działa przez około 30 minut (`connect_url_expires_at`); jeśli wygaśnie, rozpocznij nowe połączenie. Poniższe kroki ręczne są przeznaczone dla integracji, które chcą samodzielnie sterować procesem i renderować selektor stron.

### Krok 2 – Odpytywanie o status do momentu załadowania stron

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

Po zakończeniu logowania do Facebooka przez użytkownika, odpytuj ten punkt końcowy co kilka sekund. Pole `status` przechodzi przez następujące etapy:

| `status` | Znaczenie |
|---|---|
| `pending` | Zgoda nie została jeszcze udzielona. Czekaj dalej. |
| `token_received` | Autoryzowano, ale lista stron nadal się ładuje. |
| `pages_loaded` | Strony są dostępne – przejdź do kroku 3. |
| `connected` | Strona została wybrana, a kanał jest aktywny. |

**cURL**

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

**JavaScript**

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

**Python**

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

**Odpowiedź (po załadowaniu stron)**

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

### Krok 3 – Wyświetlenie listy stron (opcjonalnie)

Jeśli wolisz pobrać listę stron samodzielnie (na przykład w celu wyrenderowania selektora), użyj:

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

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

Zwraca ona tę samą tablicę `pages` co punkt końcowy statusu. (Punkt końcowy `status` zawiera już strony, więc to wywołanie jest jedynie udogodnieniem.)

### Krok 4 – Wybór strony do połączenia

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

Wyślij `page_id` strony wybranej przez użytkownika. Konto na Instagramie powiązane z tą stroną zostanie połączone automatycznie; obiekt `instagram` jest potrzebny tylko wtedy, gdy chcesz zmienić konto na Instagramie, które ma zostać użyte.

**cURL**

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

**JavaScript**

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

**Python**

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

**Odpowiedź**

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

Kanał jest teraz połączony. Kolejne wywołanie `GET /channels/meta/status` zgłosi `status: "connected"`.

### Wyświetl posty połączonej strony

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

Zwraca ostatnie posty połączonej strony – multimedia z Instagrama lub posty z Facebooka. Jest to element, z którego generujesz selektor podczas konfigurowania punktu wejścia (Entry Point), który reaguje na komentarze pod konkretnym postem.

| Parametr zapytania | Wymagany | Opis |
|---|---|---|
| `platform` | Tak | `instagram` lub `facebook`. Każda inna wartość zwróci `400`. |
| `limit` | Nie | Liczba postów do zwrócenia, `1`-`50`. Domyślnie `25`. |
| `after` | Nie | Kursor dla następnej strony – przekaż wartość `nextCursor` z poprzedniej odpowiedzi. |

**cURL**

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

**Odpowiedź**

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

`mediaType` to własna etykieta Instagrama (`REELS`, `FEED`, `STORY` lub format – `IMAGE`, `VIDEO`, `CAROUSEL_ALBUM`); dla Facebooka jest to zawsze `POST`. `nextCursor` to `null` na ostatniej stronie.

Jeśli nie można wyświetlić żadnych elementów, wywołanie nadal zwraca `200` z `connected: false` oraz pustą tablicę `posts`, a także `reason` z informacją o przyczynie:

| `reason` | Co zrobić |
|---|---|
| _(brak)_ | Żadna strona nie jest jeszcze połączona – najpierw uruchom proces łączenia. |
| `no_instagram_account` | Strona na Facebooku jest połączona, ale nie jest z nią powiązane konto firmowe na Instagramie. Posty z Facebooka wyświetlają się poprawnie. |
| `token_expired` | Zapisane dane uwierzytelniające strony już nie działają – połącz kanał ponownie. |

### Rozłącz Instagram + Messenger

```
DELETE /channels/meta
```

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

**Odpowiedź**

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

To działanie zatrzymuje routing przychodzący zarówno dla Instagrama, jak i Messengera. Jest idempotentne – wywołanie go, gdy nic nie jest połączone, również zakończy się sukcesem.

---

## WhatsApp Business

To działanie łączy oficjalny numer WhatsApp Business. Numer musi już istnieć na koncie przed wywołaniem połączenia. Podobnie jak w przypadku Meta, posiadacz konta dokonuje autoryzacji w przeglądarce, a następnie należy odpytywać o status, aż numer zgłosi `ONLINE`.

### Krok 1 – Rozpocznij połączenie WhatsApp Business

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

**cURL**

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

**JavaScript**

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

**Python**

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

| Pole | Wymagane | Opis |
|---|---|---|
| `phone_number` | Tak | Numer do połączenia w formacie E.164 (np. `+14155551234`). |
| `only_waba_sharing` | Nie | Ogranicz autoryzację do udostępnienia istniejącego konta WhatsApp Business, pomijając konfigurację nowego nadawcy. Domyślnie `false`. |
| `retry` | Nie | Ponownie uruchom autoryzację dla numeru, którego poprzednia próba nie została zakończona. Domyślnie `false`. |
| `business_name` | Nie | Kosmetyczne zastąpienie nazwy firmy wyświetlanej tylko na ekranie zgody (maks. 256 znaków). Nie jest zapisywane. |
| `description` | Nie | Kosmetyczne zastąpienie opisu firmy wyświetlanego tylko na ekranie zgody (maks. 256 znaków). Nie jest zapisywane. |

**Odpowiedź**

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

Otwórz `oauth_url` w przeglądarce właściciela konta, aby autoryzować. Po zatwierdzeniu rejestracja zostanie zakończona w tle.

### Krok 2 – Sprawdzaj status, aż będzie ONLINE

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

Sprawdzaj to, dopóki `status` nie będzie `ONLINE`.

**cURL**

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

**JavaScript**

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

**Python**

```python
import urllib.parse

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

**Odpowiedź**

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

Pole `status` może przyjmować wartości:

| `status` | Znaczenie |
|---|---|
| `PENDING` | Autoryzowano, zatwierdzanie w toku. Kontynuuj sprawdzanie. |
| `ONLINE` | Połączono i gotowe do wysyłania. |
| `RATE_LIMITED` | Zbyt wiele prób – odczekaj przed ponowieniem. |
| `REGISTRATION_FAILED` | Nie udało się ukończyć konfiguracji. |
| `DELETED` | Rejestracja już nie istnieje. |

`live: true` oznacza, że status został sprawdzony u dostawcy w czasie rzeczywistym; `false` oznacza, że pochodzi z ostatniego zapisanego stanu.

### Rozłącz numer WhatsApp Business

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

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

**Odpowiedź**

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

Sam numer pozostaje na koncie, więc możesz go później ponownie połączyć.

---

## WhatsApp Web

WhatsApp Web łączy zwykły numer WhatsApp poprzez zeskanowanie kodu QR, podobnie jak łączenie urządzenia w aplikacji WhatsApp. Proces wygląda następująco: rozpocznij sesję, pobierz kod QR i wyświetl go, a następnie sprawdzaj status, aż będzie `connected`.

### Krok 1 – Rozpocznij sesję parowania WhatsApp Web

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

**cURL**

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

**JavaScript**

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

**Python**

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

| Pole | Wymagane | Opis |
|---|---|---|
| `phone_number` | Tak | Numer WhatsApp do połączenia w formacie E.164. |
| `proxy_country` | Nie | Kod kraju ISO 3166-1 alpha-2 dla regionu routingu. Automatycznie wykrywany z numeru, jeśli zostanie pominięty. |
| `force_new` | Nie | Odrzuć istniejącą sesję i rozpocznij nowe parowanie. Domyślnie `false`. |
| `import_contacts` | Nie | Zaimportuj istniejące kontakty urządzenia przy pierwszym połączeniu. Domyślnie `false`. |
| `pause_ai_for_imported_contacts` | Nie | Podczas importowania kontaktów wstrzymaj dla nich automatyczne odpowiedzi. Domyślnie `true`. |
| `import_existing_chats` | Nie | Zaimportuj istniejącą historię czatów (wymaga `import_contacts: true`). Domyślnie `false`. |

**Odpowiedź**

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

### Najprostsza opcja dla WhatsApp Web: przekaż `connect_url`

Odpowiedź zawiera gotowy `connect_url`: hostowaną stronę, która wyświetla kod QR, odświeża go automatycznie w miarę rotacji i przełącza się na komunikat o sukcesie w momencie powiązania numeru. Wystarczy przekazać ten link właścicielowi konta (otworzyć go w przeglądarce, wysłać mu go lub pokazać jako kod QR/przycisk) i poprosić o zeskanowanie go za pomocą WhatsApp – nie musisz samodzielnie pobierać kodu QR ani odpytywać o status. Link działa przez około 30 minut (`connect_url_expires_at`); jeśli wygaśnie przed zakończeniem procesu, rozpocznij nowe połączenie, aby uzyskać świeży link.

Jest to zalecana ścieżka, gdy użytkownik może otworzyć link. Poniższe kroki ręczne (samodzielne pobranie kodu QR, odpytywanie o status) są przeznaczone dla integracji, które chcą wyświetlić kod QR bezpośrednio we własnym interfejsie.

Odpowiedź dostarcza również dokładny `poll_qr_path` oraz `poll_status_path`, których należy użyć, więc nie musisz ich samodzielnie tworzyć.

### Krok 2 – Pobierz kod QR i wyświetl go

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

**cURL**

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

**JavaScript**

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

**Python**

```python
import urllib.parse

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

**Odpowiedź**

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

Wyświetl kod QR, aby użytkownik mógł go zeskanować telefonem (WhatsApp > Połączone urządzenia > Połącz urządzenie):

- `qr_data_url` to gotowy do użycia obraz – wstaw go bezpośrednio do `<img src>`.
- `qr_code` to surowy ładunek (payload), jeśli wolisz samodzielnie wygenerować obraz.

Kod QR jest krótkotrwały. Jeśli wywołasz to zaraz po rozpoczęciu sesji, możesz otrzymać `404` z komunikatem „QR code not available yet” – po prostu odczekaj chwilę i spróbuj ponownie. Jeśli otrzymasz `410` („QR code expired”), rozpocznij połączenie od nowa, aby uzyskać świeży kod.

### Krok 3 – Odpytuj o status do momentu połączenia

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

**cURL**

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

**JavaScript**

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

**Python**

```python
import urllib.parse

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

**Odpowiedź**

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

| `status` | Znaczenie |
|---|---|
| `not_initialized` | Brak sesji (błąd krytyczny). |
| `qr_pending` | Oczekiwanie na zeskanowanie kodu QR. |
| `connecting` | Zeskanowano, kończenie konfiguracji. |
| `connected` / `open` | Połączono i działa – to oznacza sukces. |
| `disconnected` | Sesja zakończona (błąd krytyczny). |

### Rozłącz sesję WhatsApp Web

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

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

**Odpowiedź**

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

To działanie odłącza urządzenie i usuwa połączenie. Zawsze czyści stan lokalny, więc jest idempotentne, nawet jeśli sesja bazowa już nie istniała.

---

## Telegram

> **Dostępność:** Telegram łączy się tak samo jak każdy inny kanał i jest dostępny dla każdego konta — nie musisz go dla siebie włączać. Poniższe punkty końcowe Telegrama mogą nadal zwracać `403`, jeśli Telegram nie jest uwzględniony w planie konta; w takim przypadku błąd brzmi `"This channel is not included in your current plan. Upgrade to unlock it."`.

Telegram łączy konto osobiste za pomocą numeru telefonu oraz jednorazowego kodu logowania (i hasła dwuetapowego, jeśli zostało ustawione na koncie). Proces wygląda następująco: rozpocznij sesję, wprowadź kod, opcjonalnie wprowadź hasło, a następnie potwierdź status.

### Krok 1 – Rozpocznij sesję połączenia z Telegramem

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

**cURL**

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

**JavaScript**

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

**Python**

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

| Pole | Wymagane | Opis |
|---|---|---|
| `phone_number` | Tak | Numer telefonu konta do połączenia w formacie E.164. |
| `mode` | Nie | `code` (domyślnie) wysyła jednorazowy kod logowania na konto; `qr` zwraca token logowania oraz adres URL kodu QR do wyświetlenia. |
| `proxy_country` | Nie | Kod kraju ISO 3166-1 alpha-2 dla wychodzącej trasy sieciowej. |
| `force_new` | Nie | Gdy `true`, odrzuca wszelkie istniejące sesje i rozpoczyna od nowa. |

**Odpowiedź**

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

W trybie `code` konto otrzymuje kod logowania w Telegramie, a `status` ma wartość `code_required`. (W trybie `qr` odpowiedź zawiera również `login_token` oraz `qr_url` do wyświetlenia w celu zeskanowania, a `status` ma wartość `qr_required`.)

### Najprostsza opcja dla Telegrama: przekaż `connect_url`

Odpowiedź zawiera gotowy `connect_url`: hostowaną stronę, która samodzielnie kończy proces łączenia. W trybie `code` właściciel konta wprowadza kod logowania – oraz hasło weryfikacji dwuetapowej, jeśli konto je posiada. W trybie `qr` strona wyświetla kod QR, który odświeża się automatycznie, aby użytkownik mógł go zeskanować z poziomu aplikacji Telegram. W obu przypadkach strona samodzielnie zgłasza sukces, więc możesz po prostu przekazać ten link właścicielowi konta, zamiast budować własny interfejs i odpytywać o status. Link działa przez około 30 minut (`connect_url_expires_at`); jeśli wygaśnie, rozpocznij nowe połączenie, aby uzyskać świeży link.

Poniższe kroki ręczne (samodzielne pobranie kodu, przesłanie go i odpytywanie o status; lub wyrenderowanie `qr_url` i odpytywanie) są przeznaczone dla integracji, które chcą samodzielnie renderować interfejs użytkownika.

### Krok 2 – Prześlij kod logowania

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

**cURL**

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

**JavaScript**

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

**Python**

```python
import urllib.parse

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

**Odpowiedź**

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

Jeśli `status` ma wartość `connected`, to wszystko. Jeśli konto ma włączoną weryfikację dwuetapową, `status` będzie miało wartość `password_required` – przejdź do kroku 3.

### Krok 3 – Prześlij hasło weryfikacji dwuetapowej (tylko jeśli jest wymagane)

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

Wywołuj to tylko wtedy, gdy krok 2 zwrócił `password_required`.

**cURL**

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

**JavaScript**

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

**Python**

```python
import urllib.parse

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

**Odpowiedź**

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

### Sprawdź status Telegrama

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

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

**Odpowiedź**

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

`status` może przyjmować wartości `connected`, `code_required`, `password_required`, `initializing`, `disconnected`, `not_initialized` lub `error`.

### Rozłącz Telegram

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

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

**Odpowiedź**

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

Idempotentne – wielokrotne wywołania kończą się powodzeniem.

---

## Instagram (konto osobiste)

> Beta o ograniczonej dostępności, włączana dla poszczególnych kont. Ta funkcja łączy osobiste konto na Instagramie poprzez zalogowanie się przy użyciu nazwy użytkownika i hasła (nie jest to oficjalne API biznesowe). Jeśli konto nie ma włączonej wersji beta, wywołanie połączenia zwróci błąd uprawnień.

Ponieważ wymaga to własnego loginu Instagrama posiadacza konta, najprostszą drogą jest przekazanie mu hostowanego `connect_url` i pozwolenie na wprowadzenie tam swoich danych uwierzytelniających – Twoja integracja nigdy nie obsługuje hasła.

### Krok 1 – Rozpocznij połączenie z Instagramem (osobistym)

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

Wyślij Instagram `username` oraz `password`.

**Odpowiedź**

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

Jeśli konto ma włączoną weryfikację dwuetapową lub Instagram wyświetla punkt kontrolny (checkpoint), `status` powróci jako `two_factor_required` lub `challenge_required` – prześlij kod do `/connect/{id}/verify-2fa` lub `/connect/{id}/verify-challenge` poniżej, a następnie odpytuj `/connect/{id}/status`, aż do uzyskania `connected`. `{id}` to znormalizowana nazwa użytkownika Instagrama zwrócona jako `account_id`/`username` w powyższej odpowiedzi – używaj jej na każdym poniższym kroku.

### Krok 2 – Prześlij kod weryfikacji dwuetapowej (jeśli jest wymagany)

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

Wywołuj to tylko wtedy, gdy krok 1 (lub krok 3) zwrócił `two_factor_required`.

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

**Odpowiedź**

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

`status` może zwrócić `connected` (gotowe), `two_factor_required` (błędny kod, spróbuj ponownie) lub `challenge_required` (Instagram wymaga również kodu punktu kontrolnego – przejdź do kroku 3).

### Krok 3 – Prześlij kod potwierdzenia punktu kontrolnego (jeśli jest wymagany)

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

Wywołuj to tylko wtedy, gdy poprzedni krok zwrócił `challenge_required`. Struktura żądania i odpowiedzi jest taka sama jak w kroku 2 powyżej.

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

### Sprawdź status Instagrama (osobistego)

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

Odpytuj to, aż `status` będzie równe `connected` lub do momentu zgłoszenia błędu krytycznego.

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

**Odpowiedź**

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

`status` może przyjmować wartości `connected`, `two_factor_required`, `challenge_required`, `initializing`, `disconnected`, `not_initialized` lub `error`. `live: true` oznacza, że wartość została odczytana na żywo z procesu połączenia, a nie z pamięci podręcznej.

### Najprostsza opcja dla Instagrama (osobistego): przekaż `connect_url`

Odpowiedź zawiera `connect_url`: hostowaną stronę, na której posiadacz konta wprowadza swoją nazwę użytkownika i hasło do Instagrama (oraz kod 2FA lub punktu kontrolnego, jeśli Instagram o to poprosi), która samodzielnie zgłasza sukces. Dane uwierzytelniające trafiają bezpośrednio do Instagrama i nie są przechowywane. Przekaż ten link posiadaczowi konta zamiast zbierać jego hasło we własnym interfejsie użytkownika. Link działa przez około 30 minut (`connect_url_expires_at`).

### Rozłącz Instagram (osobisty)

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

Idempotentne – wielokrotne wywołania kończą się powodzeniem.

### Synchronizacja obserwujących

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

Ręcznie wyzwala synchronizację obserwujących dla połączonego konta – to samo zadanie, które automatycznie działa w tle, udostępnione tutaj jako akcja „Odśwież obserwujących” na żądanie. Pobiera ono aktualną listę obserwujących konto, rejestruje nowe osoby i (gdy kampania na żywo ma włączony zasięg do obserwujących) wysyła nowym obserwującym wiadomość powitalną DM, do dziennego limitu.

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

**Odpowiedź**

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

> Te pięć pól to jedyne miejsce na tej stronie, które zwraca `camelCase` zamiast `snake_case` – tak właśnie działa ten punkt końcowy, to nie jest błąd w druku. `isBaselineSeed: true` oznacza, że była to pierwsza synchronizacja po połączeniu, która tylko rejestruje początkową listę obserwujących i nigdy nie wysyła wiadomości DM (dlatego `dmsSent` zawsze wynosi `0` podczas tego uruchomienia).

Pierwsze wywołanie dla konta może chwilę potrwać (przechodzenie przez pełną listę obserwujących); kolejne wywołania są szybsze, ponieważ sprawdzane są tylko różnice dla nowych obserwujących. `404` oznacza, że konto nie jest połączone; `412` oznacza, że inicjalizacja połączenia jeszcze się nie zakończyła – poczekaj i spróbuj ponownie.

---

## LINE

LINE to najprostszy kanał do połączenia, ponieważ nie wymaga przekierowania w przeglądarce ani odpytywania. Klient tworzy kanał Messaging API w konsoli LINE Developers, kopiuje dwie wartości, a Ty przesyłasz je w jednym wywołaniu. Następnie przekazujesz mu adres URL webhooka, który ma wkleić w konsoli.

### Krok 1 – Połączenie za pomocą danych uwierzytelniających kanału

```
POST /channels/line
```

**cURL**

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

**JavaScript**

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

**Python**

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

| Pole | Wymagane | Opis |
|---|---|---|
| `channel_access_token` | Tak | Długoterminowy token dostępu do kanału Messaging API oficjalnego konta. Używany do wysyłania i odbierania wiadomości. |
| `channel_secret` | Tak | Klucz tajny kanału Messaging API, używany do weryfikacji podpisów przychodzących zdarzeń. |
| `channel_id` | Nie | Numeryczny identyfikator kanału. Tylko informacyjnie. |

**Odpowiedź**

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

Dwa pola mają znaczenie dla tego, co zrobisz dalej:

- **`webhook_url`** – klient musi wkleić to w pole **Webhook URL** swojego kanału LINE w konsoli LINE Developers (i włączyć opcję „Use webhook”). Dopóki tego nie zrobi, żadne przychodzące wiadomości nie dotrą. Pokaż to klientowi w widocznym miejscu.
- **`chat_mode_ok`** – gdy `false`, oficjalne konto jest w trybie „czatu” i nie będzie odbierać ani wysyłać wiadomości, dopóki nie zostanie przełączone w tryb „bota” w menedżerze oficjalnych kont LINE (LINE Official Account Manager). Uzależnij swój proces wdrażania od tej flagi i poinstruuj klienta, aby zmienił tryb.

> `channel_access_token` i `channel_secret` nigdy nie są zwracane przez żaden punkt końcowy. Przechowuj je po swojej stronie, jeśli będziesz ich ponownie potrzebować; w przeciwnym razie wklej je ponownie z konsoli LINE.

`bot_user_id` zwrócony w tym miejscu to identyfikator połączenia, którego używasz w wywołaniach statusu, weryfikacji i rozłączenia poniżej.

### Krok 2 - Ponowna weryfikacja po konfiguracji webhooka

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

Po tym, jak klient zakończy konfigurowanie adresu URL webhooka i przełączy się na tryb bota, wywołaj to, aby ponownie zweryfikować zapisany token i odświeżyć zapisany w pamięci podręcznej tryb czatu.

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

**Odpowiedź**

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

Jeśli `token_valid` ma wartość `false`, zapisany token dostępu nie uwierzytelnia już połączenia – poproś klienta o ponowne wygenerowanie go w konsoli i ponowne wywołanie `POST /channels/line` z nowym tokenem.

### Sprawdź status LINE

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

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

**Odpowiedź**

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

LINE nie posiada kanału statusu na żywo, więc `live` zawsze ma tutaj wartość `false` – wartości odzwierciedlają stan zarejestrowany w momencie połączenia (lub ostatniej weryfikacji).

### Rozłącz LINE

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

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

**Odpowiedź**

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

---

## Viber

Viber łączy się w ten sam sposób co LINE – wklej token autoryzacyjny bota z panelu administratora Viber w jednym wywołaniu – z jedną różnicą, o której warto wiedzieć: połączenie jednocześnie REJESTRUJE nasz webhook na Twoim bocie, więc nie ma później osobnego kroku w konsoli. Oznacza to również, że próba połączenia może się nie udać, jeśli nasz system nie może odpowiedzieć na synchroniczne sprawdzenie webhooka przez Viber, a nie tylko wtedy, gdy sam token jest błędny.

### Krok 1 – Połącz za pomocą tokena autoryzacyjnego bota

```
POST /channels/viber
```

| Pole | Wymagane | Opis |
|---|---|---|
| `auth_token` | Tak | Token autoryzacyjny bota z panelu administratora Viber (Ustawienia mojego bota). |

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

**Odpowiedź**

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

Token autoryzacyjny nigdy nie jest zwracany przez żaden punkt końcowy – zapisz go u siebie, jeśli będziesz musiał go ponownie wkleić. `bot_id` to identyfikator połączenia używany przez poniższe wywołania statusu, weryfikacji i rozłączenia.

### Sprawdź status Viber

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

Raportuje zapisany stan połączenia. Dodaj `?live=true`, aby również ponownie sprawdzić bota w Viber i odświeżyć zapisaną w pamięci podręcznej rejestrację webhooka – przydatne, zanim założysz, że cichy bot jest faktycznie zepsuty.

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

**Odpowiedź**

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

`webhook_ok: false` oznacza, że webhook bota nie wskazuje już na nas – wiadomości przychodzące są tracone. Zazwyczaj oznacza to, że inne narzędzie połączyło tego samego bota później (w przypadku rejestracji webhooka w Viber wygrywa ostatni zapis). Napraw to za pomocą poniższego wywołania ponownej weryfikacji, nie ma potrzeby prosić klienta o ponowne wklejenie tokena. `live` wynosi `false`, gdy odpowiedź jest ostatnim stanem z pamięci podręcznej, a nie świeżym sprawdzeniem w Viber.

### Ponowna rejestracja webhooka

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

Akcja naprawcza dla `webhook_ok: false` – ponownie rejestruje nasz webhook na bocie przy użyciu już zapisanego tokena autoryzacyjnego.

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

**Odpowiedź**

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

`token_valid: false` oznacza, że zapisany token już nie działa – połącz ponownie za pomocą `POST /channels/viber` i nowego tokena.

### Rozłącz Viber

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

Wyrejestrowuje nasz webhook po stronie Vibera (w miarę możliwości) i usuwa połączenie.

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

**Odpowiedź**

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

---

## TikTok

> **Dostępność:** Wersja beta o ograniczonej dostępności, włączana dla poszczególnych kont. Łączenie z TikTokiem zwraca błąd uprawnień, dopóki konto nie zostanie do tego uprawnione.

TikTok Business Messaging to pełny kanał OAuth, podobnie jak Meta, ale prostszy pod względem odpytywania: nie ma dedykowanego kroku odpytywania o status, ponieważ połączone konto pojawia się samoistnie, gdy TikTok przekieruje użytkownika z powrotem, a połączenie zostanie zapisane. Poniższy punkt końcowy statusu służy do potwierdzania stanu na żądanie (narzędzia wsparcia, sprawdzanie kondycji), a nie jako coś, co trzeba zapętlać podczas łączenia.

### Krok 1 - Rozpocznij połączenie z TikTokiem

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

Nie wymaga żadnych danych uwierzytelniających - właściciel konta autoryzuje wszystko w swojej przeglądarce.

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

**Odpowiedź**

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

Otwórz `oauth_url` w przeglądarce właściciela konta, aby mógł się zalogować do TikToka i zatwierdzić dostęp. Stan wygasa po `expires_at` (około 30 minut) - jeśli upłynie, zacznij od nowa. Dla TikToka nie ma skrótu do strony hostowanej `connect_url`; jedyną drogą jest samodzielne otwarcie `oauth_url`.

### Sprawdź status TikToka

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

`openId` to open_id konta TikTok Business, znane po wykonaniu wywołania zwrotnego OAuth.

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

**Odpowiedź**

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

TikTok nie posiada taniego sprawdzania kondycji na żywo, więc `live` jest tutaj zawsze `false` - pola odzwierciedlają to, co zapisało połączenie (lub ostatnie odświeżenie tokena). `status: "reauth_required"` z ustawionym `status_reason` oznacza, że konto musi przejść przez proces łączenia ponownie; tokeny TikToka są odświeżane automatycznie w cyklu rocznym i to właśnie pojawia się, jeśli ta rotacja kiedykolwiek zawiedzie.

### Rozłącz TikToka

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

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

**Odpowiedź**

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

---

## GoHighLevel

GoHighLevel (GHL) to integracja CRM, a nie kanał komunikacji - połączenie z nim nie zużywa slotu kanału w planie, ponieważ korzysta z istniejących kanałów konta, zamiast dodawać nowy. Jest to również jedyna integracja na tej stronie, która może obsługiwać **więcej niż jedno połączenie jednocześnie**: każde subkonto GHL („lokalizacja”), na którym klient zainstaluje aplikację, otrzymuje własny wpis.

### Krok 1 - Rozpocznij połączenie z GHL

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

| Pole | Wymagane | Opis |
|---|---|---|
| `brand` | Nie | Z której oferty w marketplace GHL korzystać przy autoryzacji. Domyślnie używana jest oferta standardowa – ma to znaczenie tylko wtedy, gdy wdrożenie ma skonfigurowaną więcej niż jedną aplikację w marketplace. |

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

**Odpowiedź**

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

Otwórz `oauth_url` w przeglądarce właściciela konta, aby mógł on wybrać lokalizację GHL i zatwierdzić dostęp. Stan wygasa o `expires_at` (około 30 minut).

### Lista połączeń GHL

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

W przeciwieństwie do innych kanałów, nie jest to status pojedynczego połączenia – wyświetla listę wszystkich lokalizacji połączonych z kontem.

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

**Odpowiedź**

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

### Rozłącz lokalizację GHL

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

Usuwa połączenie w tym miejscu, co zatrzymuje każdą synchronizację i wyzwalacz dla tej lokalizacji. Nie powoduje to odinstalowania aplikacji po stronie GHL – klient usuwa ją ze swoich instalacji w marketplace GHL, jeśli chce to również zrobić.

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

**Odpowiedź**

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

---

## Numery telefonów (kupowanie i zwalnianie)

Zamiast łączyć istniejący numer, możesz kupić nowy numer obsługujący WhatsApp bezpośrednio. Wyszukaj dostępne numery, kup jeden, a następnie odpytuj o status, aż zakończy się proces udostępniania.

::: note
**Uwaga:** Zakupione tutaj numery obsługują WhatsApp. Rejestracja nadawcy WhatsApp odbywa się w tle po zakupie, dlatego należy odpytywać o status, aż osiągnie on wartość `ONLINE` przed wysłaniem wiadomości. Środki są pobierane w momencie zakupu i **nie** podlegają zwrotowi po zwolnieniu numeru.
:::


### Krok 1 - Wyszukaj dostępne numery

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

**cURL**

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

**JavaScript**

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

**Python**

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

| Parametr zapytania | Wymagany | Opis |
|---|---|---|
| `country_code` | Tak | Kod kraju ISO 3166-1 alpha-2, w którym chcesz wyszukiwać (np. `US`, `GB`, `NL`). |
| `type` | Nie | Preferowana klasa numeru, `local` lub `mobile`. Obie klasy mogą nadal zostać zwrócone. |

**Odpowiedź**

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

Każdy wynik pokazuje opłatę jednorazową `purchase_credits` oraz cykliczną `monthly_credits`. Numer dostarczony przez platformę kosztuje co najmniej 50 kredytów miesięcznie, a jego cena rośnie wraz z miesięczną opłatą operatora, pobieraną przy zakupie i przy każdym odnowieniu. Należy podać wartość `purchase_credits` / `monthly_credits` zwróconą przez wyszukiwanie; nigdy nie należy samodzielnie wyliczać ceny. Pierwsze wyszukiwanie na nowym koncie inicjuje pewne zasoby podstawowe, więc może być nieco wolniejsze niż kolejne.

### Krok 2 - Kup numer

```
POST /phone-numbers
```

Użyj `phone_number` z wyników wyszukiwania.

**cURL**

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

**JavaScript**

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

**Python**

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

| Pole | Wymagane | Opis |
|---|---|---|
| `phone_number` | Tak | Numer zwrócony przez wyszukiwanie dostępnych numerów, w formacie E.164. |
| `country_code` | Tak | Kod kraju ISO 3166-1 alpha-2 (np. `US`). |
| `display_name` | Nie | Przyjazna etykieta. Domyślnie jest to numer telefonu. |
| `category` | Nie | Opcjonalna etykieta kategorii. |

**Odpowiedź**

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

Numer zaczyna się w stanie `PURCHASED`. Rejestracja w WhatsApp przebiega następnie w tle: `PURCHASED` -> `PENDING` -> `ONLINE`.

> Jeśli zakup nie powiedzie się z powodu braku adresu firmy lub innych wymaganych szczegółów, otrzymasz `400` z opisowym `error`. Skonfiguruj brakujące szczegóły i spróbuj ponownie.

### Krok 3 - Odpytuj do momentu uzyskania stanu ONLINE

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

To jest wspólny punkt końcowy statusu numeru telefonu - działa zarówno dla zakupionych numerów WhatsApp, jak i innych podłączonych numerów.

**cURL**

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

**JavaScript**

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

**Python**

```python
import urllib.parse

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

**Odpowiedź**

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

### Krok 4 - Zwolnij numer

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

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

**Odpowiedź**

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

To, co się stanie, zależy od tego, czyj to numer.

W przypadku numeru **wynajętego za pośrednictwem platformy** jest to pełne zwolnienie: nadawca WhatsApp zostaje wyrejestrowany, numer jest zwracany operatorowi i usuwany z konta, a następnie nakładany jest 7-dniowy okres karencji, podczas którego nikt nie może ponownie wykupić tego numeru; środki nie podlegają zwrotowi.

W przypadku numeru, który **konto przyniosło ze sobą** (własne konto Twilio, własną aplikację Meta lub konto WhatsApp Business, albo bramkę SMS z systemem Android), to samo wywołanie jedynie usuwa go z konta. U dostawcy nadrzędnego nic nie jest zwalniane i nie jest nakładany żaden okres karencji, więc numer można ponownie podłączyć natychmiast. Rejestracja nadawcy w WhatsApp, jeśli istniała, może zostać zachowana lub nie: proces usuwania próbuje usunąć nadawcę przy użyciu poświadczeń Twilio zarządzanych przez platformę dla danego konta. Na koncie, które nadal korzysta z zarządzanej konfiguracji, te poświadczenia są ważne i nadawca zostaje usunięty, więc ponowne podłączenie oznacza konieczność ponownej rejestracji. Na koncie, które przeszło na własne Twilio, usunięcie nie może zostać uwierzytelnione, a nadawca pozostaje zarejestrowany na tym koncie — ponowne podłączenie polega wtedy jedynie na ponownym przypisaniu istniejącego nadawcy.

### Dodaj numer, który już posiadasz (BYO)

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

Całkowicie pomija powyższy proces wyszukiwania i zakupu. Użyj tej opcji, gdy konto korzysta z własnego numeru (własne Twilio, własne konto Meta WhatsApp Business lub bramka SMS z systemem Android) zamiast wynajmować go za pośrednictwem platformy. Ta opcja jedynie rejestruje numer – nie są pobierane żadne kredyty i nic nie jest udostępniane u dostawcy. Numer pozostaje nieaktywny, dopóki właściciel konta nie ukończy procesu OAuth WhatsApp, aby zarejestrować na nim nadawcę (ten sam proces, który uruchamia przycisk „Bring your own number” w panelu nawigacyjnym).

| Pole | Wymagane | Opis |
|---|---|---|
| `phone_number` | Tak | Numer do dodania w formacie E.164 (np. `+14155551234`). |
| `country_code` | Tak | Kod kraju ISO 3166-1 alpha-2 (np. `US`). |
| `display_name` | Nie | Przyjazna etykieta. Domyślnie używany jest numer telefonu. |
| `category` | Nie | Opcjonalna etykieta kategorii. |

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

**Odpowiedź** (`201 Created`):

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

`phone_number`, który nie jest prawdziwym numerem E.164 (lub który wygląda jak testowy numer WhatsApp firmy Meta, który nigdy nie może wysyłać wiadomości do prawdziwych klientów), zwraca `400`. Dodanie numeru, który już istnieje na koncie – nawet jeśli zapisany jest nieco inaczej, jak w przypadku meksykańskich form `+52` kontra `+521` – zwraca `409` zamiast tworzyć zduplikowany wiersz.

### Ustaw numer jako główny

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

Zmienia jeden numer na `is_active: true`, a wszystkie pozostałe numery na koncie na `is_active: false` w sposób atomowy – konto nigdy nie pozostaje z dwoma aktywnymi numerami lub żadnym w trakcie żądania. `is_active` nie może być ustawiony przez ogólny punkt końcowy aktualizacji celowo; to dedykowane wywołanie jest jedynym sposobem na zmianę numeru głównego.

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

**Odpowiedź**

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

`phone_number` tutaj to pełny obiekt numeru (taki sam kształt, jaki zwraca `GET /phone-numbers`), a nie tylko ciąg znaków. `phoneNumber`, którego nie ma na koncie, zwraca `404`.

### Usuń rekord numeru (bez jego zwalniania)

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

Zwykłe usunięcie rekordu numeru na tym koncie – bez zwalniania lub wyrejestrowywania po stronie dostawcy i bez 7-dniowego okresu karencji, jak w przypadku powyższego kroku zwalniania. Użyj tego, aby wyczyścić rekordy BYO, WhatsApp Web, Telegram lub LINE, albo nieaktualny wpis, bez przechodzenia przez zarządzany proces zwalniania. W przeciwieństwie do zwolnienia, usunięcie numeru, którego nie ma na koncie, jest `404`, a nie cichym sukcesem.

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

**Odpowiedź**

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

---

## Skieruj kanał do kampanii

Podłączenie kanału pozwala na przesyłanie wiadomości **do** konta. Nie decyduje to jednak o tym, **który Agent AI na nie odpowie**.

Routing jest obsługiwany przez **Punkty wejścia** (Entry Points) w Agencie AI, a nie przez kampanie. Każdy kanał posiada domyślny Punkt wejścia wskazujący Agenta, który odpowiada na nowe, nieznane kontakty w tym kanale:

| Co chcesz zrobić | Wywołanie |
|---|---|
| Skierować kanał do Agenta, który powinien go obsługiwać | `PUT /entry-points/channel-defaults` z treścią `{ "channel": "instagram", "agent_id": "AGENT_ID" }` |
| Sprawdzić, czy drabinka Punktów wejścia jest aktywna dla konta | `GET /entry-points/routing-status`, co zwraca `{ "success": true, "cutover_enabled": true }`, gdy Punkty wejścia decydują o routingu dla tego konta |
| Pozostawić kanał bez obsługi przez Agenta | `DELETE /entry-points/channel-defaults?channel=instagram` |

Dopóki kanał nie posiada punktu wejścia (Entry Point), pierwsza wiadomość od osoby, z którą nigdy nie rozmawiałeś, jest nadal przechowywana, ale nic jej nie odbiera i żaden asystent nie odpowiada. Jest to krok, który pomija większość integracji: samo połączenie Instagrama i utworzenie agenta nie wystarczy — musisz również wskazać kanałowi tego agenta. Pełny zestaw wywołań — w tym jeden agent na numer WhatsApp, słowa kluczowe i reguły komentarzy — znajduje się w [API punktów wejścia](entry-points.md).

`POST /channels/campaign` nadal zapisuje starszą mapę routingu kampanii dla poszczególnych kanałów, opisaną poniżej, ale mapa ta nie jest już brana pod uwagę przy routingu przychodzącym na żadnym koncie; jest zachowana wyłącznie w celu wycofania zmian. Nie należy budować rozwiązań w oparciu o nią.

### Skieruj jeden lub więcej kanałów (starsza mapa routingu kampanii)

`POST /channels/campaign`

**Pola żądania**

| Pole | Wymagane | Opis |
|---|---|---|
| `campaign_id` | Tak | Kampania, która powinna odpowiadać na nowe kontakty na tych kanałach. Musi należeć do konta. |
| `channels` | Tak | Niepusta tablica kanałów do skierowania. Dozwolone: `whatsapp`, `whatsapp_web`, `telegram`, `instagram`, `messenger`, `chat_widget`, `custom_channel`, `sms`, `email`. |

Miejsce routingu i lista `enabled_channels` kampanii są aktualizowane jednocześnie w ramach jednej operacji atomowej, dzięki czemu nigdy nie mogą się rozbiec. Kanał przypisany już do innej kampanii jest po prostu przekierowywany na tę nową.

**cURL**

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

**JavaScript**

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

**Python**

```python
import requests

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

**Odpowiedź**

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

### Co musi być spełnione, aby routing faktycznie zadziałał

Na koncie, które nadal odczytuje starszą mapę routingu kampanii, routing kończy się powodzeniem jako wywołanie API, ale trzy elementy kampanii decydują o tym, czy rzeczywista wiadomość przychodząca zostanie obsłużona. Sprawdź wszystkie trzy, jeśli skierowany kanał pozostaje nieaktywny.

| Wymaganie | Co dzieje się w przeciwnym razie |
|---|---|
| `type` to `Incoming from Unknown Contacts` lub `Combined` | Żądanie jest odrzucane z `400`. Kampanie wychodzące i słów kluczowych nie mogą zajmować miejsca routingu. |
| `status` to `Live` | Routing jest zapisany, ale niczego nie odbiera. Kampania `Draft` jest najczęstszą przyczyną sytuacji, w której "skierowałem routing, a nic się nie dzieje". |
| `ai_mode` to `true` | Kontakt jest tworzony, a wiadomość zapisywana, ale asystent nigdy nie odpowiada. |

Dopasowywanie słów kluczowych znajduje się teraz w Punktach wejścia — utwórz Punkt wejścia typu `keyword` dla Agenta AI, który powinien udzielać odpowiedzi.

### Jedna kampania na kanał

Każdy kanał posiada dokładnie jedno starsze miejsce routingu. Skierowanie drugiej kampanii na ten sam kanał po cichu zmienia przypisanie miejsca i zwraca `200` — nie występuje błąd konfliktu. Poprzednia kampania nadal obsługuje kontakty, które już posiada; po prostu przestaje otrzymywać nowe.

### Usuwanie routingu kanału

`DELETE /channels/campaign/{channel}`

Usuwa routing dla pojedynczego kanału, niezależnie od tego, na jaką kampanię obecnie wskazuje, i usuwa kanał z `enabled_channels` tej kampanii. Nowe nieznane kontakty na tym kanale nie są już przechwytywane przez żadną kampanię. Kontakty już znajdujące się w kampanii działają tak jak wcześniej.

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

**Odpowiedź**

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

Jest to operacja idempotentna: wyczyszczenie kanału, który nigdy nie był objęty routingiem, również zwraca `200`, z `cleared: false` i `campaign_id: null`. Ten punkt końcowy wymaga funkcji **kampanii przychodzących** w planie; bez niej otrzymasz `403`.


---

## Użyj własnej aplikacji Meta (Instagram + Messenger)

Domyślnie połączenie Instagram + Messenger przebiega przez aplikację Meta platformy, więc to nazwę tej aplikacji widzi właściciel konta na ekranie zgody Facebooka. Jeśli chcesz, aby na ekranie zgody wyświetlała się **Twoja** marka, możesz zarejestrować własną aplikację Meta i przekierować przez nią cały proces. Po skonfigurowaniu ustawienie to będzie miało zastosowanie do Twojego konta — w powyższych wywołaniach połączenia nic się nie zmienia poza brandingiem.

> **Dotyczy to tylko Instagrama + Messengera.** Połączenia WhatsApp, WhatsApp Web, Telegram i LINE pozostają bez zmian w przypadku użycia niestandardowej aplikacji Meta.

### Czego Twoja aplikacja potrzebuje na początku

To część, która wymaga czasu i odbywa się całkowicie po stronie Meta:

1. **Aplikacja** typu Business, z dodanymi produktami Messenger i Instagram.
2. **Zaawansowany dostęp** (poprzez Meta App Review) dla: `pages_show_list`, `pages_messaging`, `pages_manage_metadata`, `pages_read_engagement`, `instagram_basic`, `instagram_manage_messages`. Bez zaawansowanego dostępu tylko osoby posiadające rolę w Twojej aplikacji mogą ukończyć połączenie — połączenia Twoich klientów zakończą się niepowodzeniem. Proces App Review zazwyczaj trwa kilka tygodni i wymaga weryfikacji firmy (Business Verification).
3. **Konfiguracja Facebook Login for Business** utworzona wewnątrz Twojej aplikacji, przyznająca te same uprawnienia. Jej numeryczny identyfikator konfiguracji jest unikalny dla każdej aplikacji, więc musisz utworzyć własny.

Jeśli w Twojej aplikacji brakuje któregokolwiek z wymaganych uprawnień, połączenie nie powiedzie się w momencie nawiązywania z jasnym błędem wskazującym, czego brakuje (widocznym w `/status` jako `byo_app_missing_permissions`) — zamiast sprawiać wrażenie, że działa, a następnie zawieść przy pierwszej wiadomości.

### Krok 1 - Zapisz swoją aplikację

`PUT /account-config/meta-app`

| Pole | Wymagane | Opis |
|---|---|---|
| `app_id` | Tak | Twój identyfikator aplikacji Meta (Ustawienia → Podstawowe). |
| `app_secret` | Tak | Twój klucz tajny aplikacji Meta (App Secret). Weryfikowany w Meta przed zapisaniem, a następnie szyfrowany. Nigdy nie jest zwracany przez żaden punkt końcowy. |
| `config_id` | Tak | Numeryczny identyfikator konfiguracji Facebook Login for Business wewnątrz Twojej aplikacji. |

Wszystkie trzy są wymagane w procesie logowania przez Facebooka. Jeśli korzystasz tylko z opisanego poniżej mechanizmu przekazywania tokenów logowania przez Instagram, możesz je całkowicie pominąć.

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

**Odpowiedź**

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

### Krok 2 - Skonfiguruj swoją aplikację do komunikacji z nami

W panelu aplikacji Meta:

1. **Webhooks** - zarówno dla produktów Instagram, jak i Messenger, ustaw adres URL wywołania zwrotnego (Callback URL) na pasującą wartość `webhook_urls` z odpowiedzi, a token weryfikacyjny (Verify token) na `verify_token`. Zasubskrybuj pola `messages`, `messaging_postbacks` oraz `comments`.
2. **Prawidłowe identyfikatory URI przekierowania OAuth** - dodaj `https://api.youraiconnector.com/v1/auth-meta-callback-handler`, aby proces wyrażania zgody mógł powrócić.

`GET /account-config/meta-app` zwraca te same materiały konfiguracyjne w dowolnym momencie; `DELETE /account-config/meta-app` usuwa aplikację (przyszłe połączenia powrócą do aplikacji platformy — usuń również subskrypcję webhooka wewnątrz swojej aplikacji).

### Krok 3 - Połącz się jak zwykle

Nic więcej się nie zmienia. `POST /channels/meta/connect` (oraz hostowana strona `connect_url`) automatycznie używa Twojej aplikacji dla Twojego konta; `uses_byo_meta_app: true` w odpowiedzi potwierdza, którą aplikację pokaże ekran zgody. Wysyłanie wiadomości, wybór strony i rozłączanie działają identycznie.

## Użyj własnej aplikacji Instagram Login (przesyłanie tokenów)

Powyższa sekcja opisuje proces logowania przez Facebooka, w którym konto jest łączone za pośrednictwem strony na Facebooku. Meta oferuje również **Instagram API z Instagram Login** (logowanie biznesowe na Instagram): właściciel konta uwierzytelnia się bezpośrednio na Instagramie, bez udziału konta lub strony na Facebooku.

Jeśli Twoja platforma korzysta już z własnej aplikacji Meta z tym produktem, nie potrzebujesz żadnego procesu OAuth po naszej stronie. Twoi klienci autoryzują **Twoją** aplikację, a Ty przesyłasz nam gotowe dane uwierzytelniające dla każdego konta:

1. Zapisujesz dane uwierzytelniające swojej aplikacji Instagram (abyśmy mogli zweryfikować Twoje webhooki).
2. Dla każdego konta przesyłasz identyfikator konta profesjonalnego na Instagramie + długoterminowy token użytkownika Instagrama uzyskany przez Twoją aplikację.
3. Kierujesz webhook wiadomości Instagrama swojej aplikacji na nasz adres. Zdarzenia dla kont, których nie przesłałeś, są potwierdzane i ignorowane.
4. Zarządzasz cyklem życia tokena: odświeżasz tokeny we własnym systemie i przesyłasz każdy odświeżony token tym samym wywołaniem. Nigdy nie odświeżamy przesłanego tokena.

### Czego Twoja aplikacja potrzebuje na początku

- Produkt **Instagram** („API setup with Instagram login”) dodany do Twojej aplikacji Meta. Ten produkt ma **własną parę identyfikatora aplikacji (App ID) i klucza tajnego (App Secret)**, oddzielną od identyfikatora/klucza aplikacji Facebooka — znajdziesz je w panelu konfiguracji produktu.
- **Dostęp zaawansowany** (przez weryfikację aplikacji Meta) dla `instagram_business_basic` i `instagram_business_manage_messages` (dodaj `instagram_business_manage_comments`, jeśli używasz automatyzacji komentarzy). Bez tego tylko osoby z rolą w Twojej aplikacji mogą ją autoryzować.

### Krok 1 - Zapisz dane uwierzytelniające swojej aplikacji Instagram

Ten sam punkt końcowy co powyżej — wyślij parę Instagram do `PUT /account-config/meta-app`. Pola Facebooka nie są potrzebne dla tej ścieżki: wyślij samą parę, jeśli korzystasz tylko z logowania przez Instagram, lub razem z polami Facebooka, jeśli korzystasz z obu. Zapis zawsze opisuje całe ustawienie, więc każdy zestaw, który pominiesz, zostanie usunięty.

| Pole | Wymagane | Opis |
|---|---|---|
| `instagram_app_id` | Razem | Własny numeryczny identyfikator aplikacji (App ID) produktu Instagram (nie identyfikator aplikacji Facebooka). |
| `instagram_app_secret` | Razem | Własny klucz tajny (App Secret) produktu Instagram. Szyfrowany w spoczynku, nigdy nie zwracany. |

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

**Odpowiedź** — zawiera adres URL webhooka logowania przez Instagram (adresy URL `instagram` i `messenger` pojawiają się tylko wtedy, gdy zapisane są również pola Facebooka):

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

W panelu **Webhooks** swojej aplikacji dla produktu Instagram ustaw adres URL wywołania zwrotnego (Callback URL) na `webhook_urls.instagram_login`, token weryfikacyjny na `verify_token` i zasubskrybuj pola `messages` oraz `comments`.

### Krok 2 - Prześlij token dla każdego konta

`PUT /channels/instagram-login/token`

Działa z `sub_account_id` tak jak każda inna trasa, więc klucz agencji może obsłużyć całą jej flotę.

| Pole | Wymagane | Opis |
|---|---|---|
| `ig_user_id` | Tak | **Identyfikator konta profesjonalnego na Instagramie** — pole `user_id` z `GET https://graph.instagram.com/v21.0/me?fields=user_id,username`. Jest to ten sam identyfikator, który webhooki Instagrama przesyłają jako `entry.id`. ⚠️ To **nie** jest pole `id` z `/me` — jest ono ograniczone do aplikacji i różni się w zależności od aplikacji Meta. Przesłanie identyfikatora ograniczonego do aplikacji zwróci `400` wskazujący na błąd. |
| `access_token` | Tak | Długoterminowy token użytkownika Instagrama uzyskany przez Twoją aplikację dla tego konta. Walidowany na żywo w Instagramie przed zapisaniem: token musi działać i należeć do `ig_user_id`. |
| `expires_at` | Nie | Data wygaśnięcia tokena w formacie ISO-8601. Alternatywnie wyślij `expires_in` (sekundy). Domyślnie 60 dni. |
| `username` | Nie | @uchwyt (handle) konta; i tak odczytujemy go z Instagrama. |

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

**Odpowiedź**

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

W ramach przesyłania subskrybujemy Twoją aplikację do webhooków tego konta (`subscribed_apps` z przesłanym tokenem), więc wiadomości zaczynają napływać bez żadnego dodatkowego wywołania z Twojej strony.

**Odświeżanie** - wyślij odświeżony token do tego samego punktu końcowego z tym samym `ig_user_id`; aktualizuje on przechowywany token oraz datę wygaśnięcia w miejscu.

**Konflikty** - jedno konto na Instagramie nigdy nie jest aktywne w dwóch połączeniach jednocześnie. Jeśli konto jest już połączone w innym miejscu lub na tym samym koncie poprzez przepływ strony na Facebooku, operacja push zwraca `409` informujący, które połączenie należy najpierw rozłączyć. Połączenie typu Facebook-flow nigdy nie jest zastępowane automatycznie, ponieważ może ono również obsługiwać komunikator Messenger.

### Krok 3 - Rozłączanie, gdy klient odchodzi

`DELETE /channels/instagram-login/token` (ta sama autoryzacja i `sub_account_id`) anuluje subskrypcję webhooków w miarę możliwości i usuwa przechowywane dane uwierzytelniające. Operacja ta zawsze kończy się powodzeniem, nawet jeśli token już wygasł — a gdy dane uwierzytelniające zostaną usunięte, zdarzenia webhook dla tego konta są ignorowane.

---

## Wskazówki dotyczące budowania niezawodnego wrappera

- **Odpytuj delikatnie.** Wystarczy co kilka sekund. Zatrzymaj się, gdy osiągniesz stan końcowy (`connected` / `ONLINE` lub status błędu) i ustaw rozsądny ogólny limit czasu dla pętli (kroki przeglądarki/QR wygasają, zobacz każde `expires_at`).
- **Koduj numery telefonów w ścieżce (URL-encode).** Wiodący znak `+` powinien być wysłany jako `%2B`. Punkty końcowe odzyskują również same cyfry, ale kodowanie jest bezpiecznym domyślnym rozwiązaniem.
- **Nigdy nie oczekuj zwrotu sekretów.** Tokeny dostępu, sekrety kanałów i tokeny stron są akceptowane lub przechowywane, ale nigdy nie są zwracane w żadnej odpowiedzi.
- **Obsłuż bramkę autoryzacji.** `403` oznacza, że dostęp do API nie jest objęty planem lub że kanał, który próbujesz podłączyć, nie jest uwzględniony w planie konta. Zobacz [Dostęp do API](../integrations/api-access.md).
- **Pamiętaj o limicie zapytań (rate limit).** Uwierzytelnione żądania są ograniczone do 300 na minutę; `429` oznacza, że należy zwolnić i spróbować ponownie. Zobacz [Uwierzytelnianie](authentication.md).

## Następne kroki

- [Uwierzytelnianie](authentication.md) - cztery akceptowane formy uwierzytelniania oraz format błędów.
- [Dostęp do API](../integrations/api-access.md) - generowanie i zarządzanie kluczem API.
