
# API di connessione ai canali

Questa guida mostra come connettere i canali di messaggistica a un account utilizzando l'API. È scritta per uno sviluppatore che sta creando un'integrazione o un wrapper, quindi si concentra sulle richieste esatte, sull'ordine in cui effettuarle e sulle risposte ricevute.

C'è un pattern che devi comprendere fin da subito, perché si applica a quasi tutti i canali qui presenti.

## Il pattern di connessione e polling

La maggior parte dei canali non può essere connessa con una singola chiamata API. Connettere WhatsApp, Instagram o Messenger significa che il titolare dell'account deve accedere al proprio account del provider e approvare l'accesso. **Non esiste un percorso headless (completamente automatizzato)** per tale approvazione: una persona reale deve aprire un URL in un browser o scansionare un codice QR con il proprio telefono.

Quindi il flusso è sempre:

1. **Avvia la connessione** con una `POST`. La risposta ti fornisce un URL da aprire o un codice QR da visualizzare.
2. **Passalo all'utente finale**: apri l'URL nel suo browser o visualizza il codice QR sullo schermo affinché possa scansionarlo.
3. **Esegui il polling dell'endpoint di stato** con `GET` a intervalli brevi (ogni pochi secondi) finché lo stato non raggiunge quello di connesso.

Il compito della tua integrazione è gestire questo ciclo: mostra l'URL o il QR, quindi esegui il polling fino al completamento. Progetta la tua interfaccia attorno al polling: uno spinner con un messaggio del tipo "in attesa del completamento nel browser" funziona bene.

::: note
**Nota:** Prima di iniziare, assicurati che l'accesso API sia abilitato sul piano e di avere una chiave API. Consulta [Accesso API](../integrations/api-access.md) per sapere come generarne una. Tutte le richieste seguenti utilizzano l'URL di base `https://api.youraiconnector.com/v1` ed è necessario autenticare ogni richiesta. Consulta [Autenticazione](authentication.md) per le quattro forme accettate: gli esempi qui utilizzano l'intestazione `X-API-Key`, con un esempio cURL per pagina che mostra la forma di query `?apiKey=` più semplice.
:::


---

## Instagram + Messenger (Meta)

Instagram e Messenger vengono connessi insieme in un unico flusso, poiché entrambi funzionano su una Pagina Facebook. Il titolare dell'account autorizza tramite Facebook, tu recuperi l'elenco delle Pagine che gestisce e scegli quale Pagina connettere.

### Passaggio 1 - Avvia la connessione Instagram + Messenger

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

Questo restituisce un URL di consenso. Nessuna credenziale viene inviata in questa richiesta: la connessione viene autorizzata interamente nel browser.

**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.
```

**Risposta**

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

Apri `oauth_url` nel browser dell'utente finale in modo che possa accedere a Facebook e approvare l'accesso. Il tentativo di connessione scade a `expires_at` (circa 30 minuti): se scade, ricomincia da capo. Tratta `state_token` come un segreto a breve termine e non registrarlo.

### Opzione più semplice per Instagram + Messenger: consegna `connect_url`

La risposta include anche un `connect_url` pronto all'uso: una pagina ospitata che esegue l'intero flusso per il titolare dell'account. L'utente la apre, accede a Facebook e, se possiede più di una Pagina, visualizza l'elenco e può scegliere quale collegare; dopodiché, la pagina segnala autonomamente l'esito positivo. Fornisci questo link al titolare dell'account invece di aprire `oauth_url` personalmente, creare un selettore di Pagine ed eseguire il polling. Il link è valido per circa 30 minuti (`connect_url_expires_at`); se scade, avvia una nuova connessione. I passaggi manuali riportati di seguito sono destinati alle integrazioni che desiderano gestire il flusso e visualizzare autonomamente il selettore di Pagine.

### Passaggio 2 - Esegui il polling dello stato finché le pagine non vengono caricate

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

Dopo che l'utente ha completato l'accesso a Facebook, esegui il polling di questo endpoint ogni pochi secondi. Il campo `status` attraversa queste fasi:

| `status` | Significato |
|---|---|
| `pending` | Consenso non ancora completato. Continua ad attendere. |
| `token_received` | Autorizzato, ma l'elenco delle Pagine è ancora in fase di caricamento. |
| `pages_loaded` | Le pagine sono disponibili - passa al passaggio 3. |
| `connected` | Una Pagina è stata selezionata e il canale è attivo. |

**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".
```

**Risposta (una volta caricate le pagine)**

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

### Passaggio 3 - Elenca le pagine (facoltativo)

Se preferisci recuperare l'elenco delle Pagine separatamente (ad esempio, per eseguire il rendering di un selettore), utilizza:

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

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

Restituisce lo stesso array `pages` dell'endpoint di stato. (L'endpoint `status` include già le pagine, quindi questa chiamata è solo una comodità.)

### Passaggio 4 - Seleziona la pagina da connettere

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

Invia l' `page_id` della Pagina scelta dall'utente. L'account Instagram collegato a tale Pagina viene connesso automaticamente; ti serve l'oggetto `instagram` solo se desideri sovrascrivere l'account Instagram da utilizzare.

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

**Risposta**

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

Il canale è ora connesso. Un `GET /channels/meta/status` di follow-up riporterà `status: "connected"`.

### Elenca i post della pagina connessa

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

Restituisce i post recenti della pagina che hai connesso: contenuti Instagram o post Facebook. È ciò da cui esegui il rendering di un selettore quando configuri un Punto di Ingresso che reagisce ai commenti su un post specifico.

| Parametro di query | Obbligatorio | Descrizione |
|---|---|---|
| `platform` | Sì | `instagram` o `facebook`. Qualsiasi altro valore restituisce un `400`. |
| `limit` | No | Quanti post restituire, `1`-`50`. Il valore predefinito è `25`. |
| `after` | No | Cursore per la pagina successiva: passa il valore `nextCursor` dalla risposta precedente. |

**cURL**

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

**Risposta**

```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` è l'etichetta propria di Instagram (`REELS`, `FEED`, `STORY`, o il formato - `IMAGE`, `VIDEO`, `CAROUSEL_ALBUM`); per Facebook è sempre `POST`. `nextCursor` è `null` nell'ultima pagina.

Se non è possibile elencare nulla, la chiamata restituisce comunque `200` con `connected: false` e un array `posts` vuoto, più un `reason` che indica il motivo:

| `reason` | Cosa fare |
|---|---|
| _(assente)_ | Nessuna pagina è ancora connessa: esegui prima il flusso di connessione. |
| `no_instagram_account` | Una Pagina Facebook è connessa ma nessun account aziendale Instagram è collegato ad essa. I post di Facebook vengono comunque elencati correttamente. |
| `token_expired` | Le credenziali della pagina memorizzate non funzionano più: riconnetti il canale. |

### Disconnetti Instagram + Messenger

```
DELETE /channels/meta
```

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

**Risposta**

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

Questo interrompe il routing in entrata sia per Instagram che per Messenger. È idempotente: chiamarlo quando non c'è nulla di connesso ha comunque esito positivo.

---

## WhatsApp Business

Questo collega un numero ufficiale WhatsApp Business. Il numero deve già esistere sull'account prima di richiamare la connessione. Come per Meta, il titolare dell'account autorizza nel proprio browser, quindi si esegue il polling finché il numero non riporta `ONLINE`.

### Passaggio 1 - Avvia la connessione 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.
```

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `phone_number` | Sì | Il numero da collegare, in formato E.164 (es. `+14155551234`). |
| `only_waba_sharing` | No | Limita l'autorizzazione alla condivisione di un account WhatsApp Business esistente, saltando la configurazione del nuovo mittente. Il valore predefinito è `false`. |
| `retry` | No | Esegue nuovamente l'autorizzazione per un numero il cui tentativo precedente non è stato completato. Il valore predefinito è `false`. |
| `business_name` | No | Sovrascrittura estetica per il nome dell'attività mostrato solo nella schermata di consenso (max 256 caratteri). Non memorizzato. |
| `description` | No | Sovrascrittura estetica per la descrizione dell'attività mostrata solo nella schermata di consenso (max 256 caratteri). Non memorizzato. |

**Risposta**

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

Apri `oauth_url` nel browser del titolare dell'account per autorizzare. Una volta approvato, la registrazione viene completata in background.

### Passaggio 2 - Eseguire il polling dello stato fino a ONLINE

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

Esegui il polling finché `status` non è `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".
```

**Risposta**

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

Il campo `status` può essere:

| `status` | Significato |
|---|---|
| `PENDING` | Autorizzato, approvazione ancora in corso. Continua il polling. |
| `ONLINE` | Connesso e pronto per l'invio. |
| `RATE_LIMITED` | Troppi tentativi: attendere prima di riprovare. |
| `REGISTRATION_FAILED` | Impossibile completare la configurazione. |
| `DELETED` | La registrazione non esiste più. |

`live: true` significa che lo stato è stato verificato presso il provider in tempo reale; `false` significa che proviene dall'ultimo stato memorizzato nella cache.

### Disconnetti un numero 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"
```

**Risposta**

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

Il numero rimane sull'account, quindi è possibile ricollegarlo in seguito.

---

## WhatsApp Web

WhatsApp Web collega un normale numero WhatsApp scansionando un codice QR, proprio come quando si collega un dispositivo nell'app WhatsApp. Il flusso è: avviare la sessione, recuperare il codice QR e mostrarlo, quindi eseguire il polling fino a quando lo stato è `connected`.

### Passaggio 1 - Avvia una sessione di accoppiamento 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()
```

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `phone_number` | Sì | Il numero WhatsApp da collegare, in formato E.164. |
| `proxy_country` | No | Codice paese ISO 3166-1 alpha-2 per la regione di instradamento. Rilevato automaticamente dal numero se omesso. |
| `force_new` | No | Elimina qualsiasi sessione esistente e avvia una nuova associazione. Il valore predefinito è `false`. |
| `import_contacts` | No | Importa i contatti esistenti del dispositivo alla prima connessione. Il valore predefinito è `false`. |
| `pause_ai_for_imported_contacts` | No | Durante l'importazione dei contatti, mantieni le risposte automatiche in pausa per loro. Il valore predefinito è `true`. |
| `import_existing_chats` | No | Importa la cronologia chat esistente (richiede `import_contacts: true`). Il valore predefinito è `false`. |

**Risposta**

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

### Opzione più semplice per WhatsApp Web: consegna `connect_url`

La risposta include un `connect_url` pronto all'uso: una pagina ospitata che mostra il codice QR, lo aggiorna automaticamente man mano che ruota e passa a un messaggio di successo nel momento in cui il numero viene collegato. Basta fornire questo link al titolare dell'account (aprilo in un browser, invialo o mostralo come QR/pulsante) e farglielo scansionare con WhatsApp: non è necessario recuperare il QR o eseguire il polling autonomamente. Il link funziona per circa 30 minuti (`connect_url_expires_at`); se scade prima che abbiano terminato, avvia una nuova connessione per ottenerne uno nuovo.

Questo è il percorso consigliato quando una persona può aprire un link. I passaggi manuali di seguito (recuperare il QR autonomamente, eseguire il polling dello stato) sono destinati alle integrazioni che desiderano invece visualizzare il QR all'interno della propria interfaccia.

La risposta fornisce anche l'esatto `poll_qr_path` e `poll_status_path` da utilizzare, così non dovrai crearli da solo.

### Passaggio 2 - Recuperare il codice QR e mostrarlo

```
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.
```

**Risposta**

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

Visualizza il QR affinché l'utente possa scansionarlo con il proprio telefono (WhatsApp > Dispositivi collegati > Collega un dispositivo):

- `qr_data_url` è un'immagine pronta all'uso: inseriscila direttamente in un `<img src>`.
- `qr_code` è il payload grezzo se preferisci generare l'immagine da solo.

Il QR ha una durata breve. Se chiami questo metodo subito dopo aver avviato la sessione, potresti ricevere un `404` con "Codice QR non ancora disponibile": attendi un momento e riprova. Se ricevi un `410` ("Codice QR scaduto"), riavvia la connessione per ottenere un nuovo codice.

### Passaggio 3 - Eseguire il polling dello stato fino alla connessione

```
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").
```

**Risposta**

```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` | Significato |
|---|---|
| `not_initialized` | Nessuna sessione ancora (errore terminale). |
| `qr_pending` | In attesa della scansione del QR. |
| `connecting` | Scansionato, completamento configurazione. |
| `connected` / `open` | Collegato e attivo: questo è il successo. |
| `disconnected` | Sessione terminata (errore terminale). |

### Disconnetti una sessione 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"
```

**Risposta**

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

Questo scollega il dispositivo e rimuove la connessione. Pulisce sempre lo stato locale, quindi è idempotente anche se la sessione sottostante era già terminata.

---

## Telegram

> **Disponibilità:** Telegram si connette come qualsiasi altro canale ed è aperto a tutti gli account; non è necessario che venga attivato per te. Gli endpoint di Telegram riportati di seguito possono comunque restituire `403` se Telegram non è incluso nel piano dell'account; in tal caso, l'errore indica `"This channel is not included in your current plan. Upgrade to unlock it."`.

Telegram connette un account personale tramite numero di telefono più un codice di accesso monouso (e una password a due fattori, se l'account ne ha una impostata). Il flusso è: avviare la sessione, inviare il codice, facoltativamente inviare la password, quindi confermare tramite lo stato.

### Passaggio 1 - Avvia una sessione di connessione Telegram

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

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `phone_number` | Sì | Il numero di telefono dell'account da connettere, in formato E.164. |
| `mode` | No | `code` (predefinito) invia un codice di accesso monouso all'account; `qr` restituisce un token di accesso e un URL QR da visualizzare. |
| `proxy_country` | No | Codice paese ISO 3166-1 alpha-2 per il percorso di rete in uscita. |
| `force_new` | No | Quando `true`, elimina qualsiasi sessione esistente e ne avvia una nuova. |

**Risposta**

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

In modalità `code` l'account riceve un codice di accesso su Telegram e `status` è `code_required`. (In modalità `qr` la risposta include anche `login_token` e `qr_url` da visualizzare per la scansione, e `status` è `qr_required`.)

### Opzione più semplice per Telegram: consegna `connect_url`

La risposta include un `connect_url` pronto all'uso: una pagina ospitata che completa la connessione autonomamente. In modalità `code`, il titolare dell'account inserisce il codice di accesso e, se l'account ne è dotato, la password di verifica in due passaggi. In modalità `qr`, la pagina mostra un QR code che si aggiorna automaticamente, da scansionare tramite l'app Telegram. In entrambi i casi, la pagina segnala il successo dell'operazione, quindi puoi semplicemente fornire questo link al titolare dell'account invece di creare un'interfaccia personalizzata e gestire il polling. Il link è valido per circa 30 minuti (`connect_url_expires_at`); se scade, avvia una nuova connessione per ottenerne uno nuovo.

I passaggi manuali riportati di seguito (raccogliere il codice autonomamente, inviarlo, eseguire il polling dello stato; oppure eseguire il rendering di `qr_url` ed eseguire il polling) sono destinati alle integrazioni che desiderano gestire autonomamente il rendering dell'interfaccia utente.

### Passaggio 2 - Inviare il codice di accesso

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

**Risposta**

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

Se `status` è `connected`, hai finito. Se l'account ha l'autenticazione a due fattori abilitata, `status` sarà `password_required` - procedi al passaggio 3.

### Passaggio 3 - Inviare la password a due fattori (solo se necessario)

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

Chiama questo metodo solo quando il passaggio 2 ha restituito `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()
```

**Risposta**

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

### Controlla lo stato di Telegram

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

**Risposta**

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

`status` può essere `connected`, `code_required`, `password_required`, `initializing`, `disconnected`, `not_initialized` o `error`.

### Disconnetti Telegram

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

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

**Risposta**

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

Idempotente: le chiamate ripetute hanno successo.

---

## Instagram (account personale)

> Beta a disponibilità limitata, abilitata per singolo account. Questa funzione collega un account Instagram personale effettuando l'accesso con nome utente e password (non tramite l'API Business ufficiale). Se l'account non è abilitato per la beta, la chiamata di connessione restituisce un errore di autorizzazione.

Poiché questa procedura richiede le credenziali Instagram del titolare dell'account, la soluzione più semplice consiste nel fornire il `connect_url` ospitato e lasciare che inserisca le proprie credenziali lì: la tua integrazione non gestirà mai la password.

### Passaggio 1 - Avvia una connessione Instagram (personale)

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

Invia l'Instagram `username` e `password`.

**Risposta**

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

Se l'account ha l'autenticazione a due fattori o Instagram presenta un checkpoint, `status` viene restituito come `two_factor_required` o `challenge_required`: invia il codice a `/connect/{id}/verify-2fa` o `/connect/{id}/verify-challenge` qui sotto, quindi esegui il polling di `/connect/{id}/status` finché non diventa `connected`. `{id}` è il nome utente Instagram normalizzato restituito come `account_id`/`username` nella risposta sopra: usalo in ogni passaggio qui sotto.

### Passaggio 2 - Invia il codice a due fattori (se richiesto)

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

Chiama questo endpoint solo quando il passaggio 1 (o il passaggio 3) ha restituito `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" }'
```

**Risposta**

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

`status` può tornare come `connected` (fatto), `two_factor_required` (codice errato, riprova), o `challenge_required` (Instagram richiede anche un codice di checkpoint: vai al passaggio 3).

### Passaggio 3 - Invia il codice di conferma del checkpoint (se richiesto)

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

Chiama questo endpoint solo quando un passaggio precedente ha restituito `challenge_required`. Stessa forma di richiesta e risposta del passaggio 2 sopra.

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

### Controlla lo stato di Instagram (personale)

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

Esegui il polling di questo endpoint finché `status` non è `connected`, o finché non segnala un errore terminale.

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

**Risposta**

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

`status` può essere `connected`, `two_factor_required`, `challenge_required`, `initializing`, `disconnected`, `not_initialized`, o `error`. `live: true` significa che questo valore è stato letto in tempo reale dal worker di connessione anziché essere un valore memorizzato nella cache.

### Opzione più semplice per Instagram (personale): consegna `connect_url`

La risposta include un `connect_url`: una pagina ospitata in cui il titolare dell'account inserisce il proprio nome utente e password di Instagram (e un codice 2FA o di checkpoint se richiesto da Instagram), che segnala autonomamente l'esito positivo. Le credenziali vengono inviate direttamente a Instagram e non vengono memorizzate. Fornisci questo link al titolare dell'account invece di raccogliere la sua password nella tua interfaccia. Il link è valido per circa 30 minuti (`connect_url_expires_at`).

### Disconnetti Instagram (personale)

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

Idempotente: le chiamate ripetute hanno successo.

### Sincronizza follower

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

Attiva manualmente una sincronizzazione dei follower per un account collegato: lo stesso processo che viene eseguito automaticamente in background, qui esposto come azione "Aggiorna follower" su richiesta. Recupera l'elenco attuale dei follower dell'account, registra i nuovi arrivati e (quando una campagna Live ha attivato il contatto dei follower) invia ai nuovi follower un messaggio diretto di apertura, fino a un limite giornaliero.

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

**Risposta**

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

> Questi cinque campi sono l'unico punto in questa pagina che restituisce `camelCase` invece di `snake_case`: è così che questo endpoint è configurato oggi, non è un errore di battitura. `isBaselineSeed: true` significa che questa è stata la primissima sincronizzazione dopo la connessione, che registra solo l'elenco iniziale dei follower e non invia mai messaggi diretti di contatto (quindi `dmsSent` è sempre `0` durante quell'esecuzione).

La primissima chiamata per un account può richiedere del tempo (scorrere l'intero elenco dei follower); le chiamate successive sono più veloci poiché vengono analizzati solo i nuovi follower. `404` significa che l'account non è collegato; `412` significa che l'inizializzazione della connessione non è ancora terminata: attendi e riprova.

---

## LINE

LINE è il canale più semplice da collegare perché non richiede reindirizzamenti del browser o polling. Il cliente crea un canale Messaging API nella console LINE Developers, copia due valori e tu li invii in un'unica chiamata. Successivamente, fornisci loro un URL webhook da incollare nella console.

### Passaggio 1 - Connetti con le credenziali del canale

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

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `channel_access_token` | Sì | Il token di accesso al canale Messaging API a lunga durata dell'Account Ufficiale. Utilizzato per inviare e ricevere messaggi. |
| `channel_secret` | Sì | Il segreto del canale Messaging API, utilizzato per verificare le firme degli eventi in entrata. |
| `channel_id` | No | L'ID numerico del canale. Solo a scopo informativo. |

**Risposta**

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

Due campi sono importanti per le operazioni successive:

- **`webhook_url`** - il cliente deve incollarlo nel campo **Webhook URL** del proprio canale LINE nella console LINE Developers (e abilitare "Use webhook"). Finché non lo farà, non arriveranno messaggi in entrata. Mostralo chiaramente.
- **`chat_mode_ok`** - quando `false`, l'Account Ufficiale è in modalità "chat" e non riceverà né invierà messaggi finché non verrà impostato in modalità "bot" nel LINE Official Account Manager. Subordina l'onboarding a questo flag e comunica al cliente di cambiare modalità.

> Il `channel_access_token` e il `channel_secret` non vengono mai restituiti da alcun endpoint. Conservali da parte se ti servono di nuovo; in caso contrario, copiali nuovamente dalla console LINE.

Il `bot_user_id` restituito qui è l'identificativo di connessione che utilizzi nelle chiamate di stato, verifica e disconnessione riportate di seguito.

### Passaggio 2 - Verifica nuovamente dopo la configurazione del webhook

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

Dopo che il cliente ha terminato di configurare l'URL del webhook e passa alla modalità bot, chiama questa funzione per riconvalidare il token memorizzato e aggiornare la modalità chat memorizzata nella cache.

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

**Risposta**

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

Se `token_valid` è `false`, il token di accesso memorizzato non autentica più: chiedi al cliente di riemetterlo nella console e chiama nuovamente `POST /channels/line` con il nuovo token.

### Controlla lo stato di LINE

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

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

**Risposta**

```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 non dispone di un feed di stato in tempo reale, quindi `live` qui è sempre `false`: i valori riflettono lo stato acquisito al momento della connessione (o dell'ultima verifica).

### Disconnetti LINE

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

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

**Risposta**

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

---

## Viber

Viber si collega nello stesso modo di LINE (incollando il token di autenticazione del bot dal Pannello di amministrazione di Viber in una chiamata), con una differenza importante: la connessione REGISTRA anche il nostro webhook sul tuo bot in quel momento, quindi non c'è alcun passaggio separato nella console in seguito. Ciò significa anche che un tentativo di connessione può fallire se il nostro ingresso non riesce a rispondere al controllo sincrono del webhook di Viber, non solo se il token stesso è errato.

### Passaggio 1 - Connetti con il token di autenticazione del bot

```
POST /channels/viber
```

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `auth_token` | Sì | Il token di autenticazione del bot, dal Pannello di amministrazione di Viber (Impostazioni del mio bot). |

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

**Risposta**

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

Il token di autenticazione non viene mai restituito da alcun endpoint: salvalo da parte se dovessi aver bisogno di reincollarlo. `bot_id` è l'identificatore di connessione utilizzato dalle chiamate di stato, verifica e disconnessione di seguito.

### Controlla lo stato di Viber

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

Riporta lo stato della connessione memorizzato. Aggiungi `?live=true` per ricontrollare anche il bot su Viber e aggiornare la registrazione del webhook memorizzata nella cache: utile prima di presumere che un bot silenzioso sia effettivamente rotto.

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

**Risposta**

```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` significa che il webhook del bot non punta più a noi: i messaggi in entrata sono persi. Di solito significa che un altro strumento ha collegato lo stesso bot in seguito (la registrazione del webhook di Viber segue la logica "l'ultimo che scrive vince"). Risolvi il problema con la chiamata di riverifica qui sotto, non c'è bisogno di chiedere al cliente di reincollare il proprio token. `live` è `false` quando la risposta è l'ultimo stato memorizzato nella cache anziché un controllo aggiornato su Viber.

### Registra nuovamente il webhook

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

L'azione di riparazione per `webhook_ok: false`: registra nuovamente il nostro webhook sul bot utilizzando il token di autenticazione già memorizzato.

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

**Risposta**

```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` significa che il token memorizzato non funziona più: riconnettiti con `POST /channels/viber` e un nuovo token.

### Disconnetti Viber

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

Annulla la registrazione del nostro webhook lato Viber (best-effort) e rimuove la connessione.

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

**Risposta**

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

---

## TikTok

> **Disponibilità:** Beta a disponibilità limitata, abilitata per account. La connessione a TikTok restituisce un errore di autorizzazione finché l'account non viene abilitato.

TikTok Business Messaging è un canale OAuth completo come Meta, ma più semplice per quanto riguarda il polling: non c'è un passaggio dedicato di polling dello stato da implementare, poiché l'account connesso appare autonomamente una volta che TikTok reindirizza l'utente e la connessione viene scritta. L'endpoint di stato sottostante esiste per confermare lo stato su richiesta (strumenti di supporto, controlli di integrità), non come qualcosa su cui è necessario eseguire un ciclo durante la connessione.

### Passaggio 1 - Avvia la connessione a TikTok

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

Non richiede credenziali: il titolare dell'account autorizza interamente tramite il proprio browser.

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

**Risposta**

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

Apri `oauth_url` nel browser del titolare dell'account in modo che possa accedere a TikTok e approvare l'accesso. Lo stato scade a `expires_at` (circa 30 minuti) - se scade, ricomincia da capo. Non esiste una scorciatoia di pagina ospitata `connect_url` per TikTok; aprire `oauth_url` personalmente è l'unico percorso possibile.

### Controlla lo stato di TikTok

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

`openId` è l'open_id dell'account TikTok Business, noto una volta eseguito il callback OAuth.

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

**Risposta**

```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 non dispone di un controllo di integrità live economico, quindi `live` qui è sempre `false`: i campi riflettono ciò che è stato scritto dalla connessione (o dall'ultimo aggiornamento del token). `status: "reauth_required"` con `status_reason` impostato significa che l'account deve ripetere la connessione; i token TikTok vengono aggiornati automaticamente con una rotazione annuale, e questo è ciò che appare se tale rotazione dovesse fallire.

### Disconnetti TikTok

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

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

**Risposta**

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

---

## GoHighLevel

GoHighLevel (GHL) è un'integrazione CRM, non un canale di messaggistica: connetterlo non consuma uno slot canale nel piano, poiché sfrutta i canali esistenti dell'account invece di aggiungerne uno nuovo. È anche l'unica integrazione in questa pagina in grado di gestire **più di una connessione alla volta**: ogni sotto-account GHL ("posizione") su cui il cliente installa l'app ottiene la propria voce.

### Passaggio 1 - Avvia la connessione GHL

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

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `brand` | No | Quale inserzione nel marketplace GHL utilizzare per l'autorizzazione. L'impostazione predefinita è l'inserzione standard: è rilevante solo se la tua distribuzione ha più di un'app marketplace configurata. |

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

**Risposta**

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

Apri `oauth_url` nel browser del titolare dell'account in modo che possa scegliere una posizione GHL e approvare l'accesso. Lo stato scade alle `expires_at` (circa 30 minuti).

### Elenca le connessioni GHL

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

A differenza di altri canali, questo non è lo stato di una singola connessione: elenca ogni posizione che l'account ha collegato.

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

**Risposta**

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

### Disconnetti una posizione GHL

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

Elimina la connessione qui, interrompendo ogni sincronizzazione e trigger per quella posizione. Questo non disinstalla l'app dal lato GHL: il cliente la rimuove dalle installazioni del proprio marketplace GHL se desidera farlo anche lì.

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

**Risposta**

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

---

## Numeri di telefono (acquisto e rilascio)

Invece di collegare un numero esistente, puoi acquistare direttamente un nuovo numero compatibile con WhatsApp. Cerca i numeri disponibili, acquistane uno, quindi esegui il polling finché il provisioning non è completato.

::: note
**Nota:** I numeri acquistati qui sono compatibili con WhatsApp. La registrazione del mittente WhatsApp viene eseguita in background dopo l'acquisto, quindi è necessario eseguire il polling dello stato finché non raggiunge `ONLINE` prima di inviare. I crediti vengono detratti al momento dell'acquisto e **non** vengono rimborsati quando si rilascia il numero.
:::


### Passaggio 1 - Cerca numeri disponibili

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

| Parametro di query | Obbligatorio | Descrizione |
|---|---|---|
| `country_code` | Sì | Codice paese ISO 3166-1 alpha-2 in cui effettuare la ricerca (es. `US`, `GB`, `NL`). |
| `type` | No | Classe di numero preferita, `local` o `mobile`. Entrambe le classi potrebbero comunque essere restituite. |

**Risposta**

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

Ogni risultato mostra il costo una tantum `purchase_credits` e quello ricorrente `monthly_credits`. Un numero fornito dalla piattaforma costa almeno 50 crediti al mese, aumentando in base al prezzo mensile del gestore, addebitato all'acquisto e a ogni rinnovo. Cita il `purchase_credits` / `monthly_credits` restituito dalla ricerca; non calcolare mai il prezzo autonomamente. La prima ricerca su un nuovo account fornisce alcune risorse sottostanti, quindi potrebbe essere leggermente più lenta rispetto alle ricerche successive.

### Passaggio 2 - Acquista un numero

```
POST /phone-numbers
```

Utilizza un `phone_number` dai risultati della ricerca.

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

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `phone_number` | Sì | Un numero restituito dalla ricerca dei numeri disponibili, nel formato E.164. |
| `country_code` | Sì | Codice paese ISO 3166-1 alpha-2 (es. `US`). |
| `display_name` | No | Un'etichetta descrittiva. Per impostazione predefinita è il numero di telefono. |
| `category` | No | Etichetta di categoria opzionale. |

**Risposta**

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

Il numero inizia nello stato `PURCHASED`. La registrazione a WhatsApp procede quindi in background: `PURCHASED` -> `PENDING` -> `ONLINE`.

> Se l'acquisto non riesce perché manca un indirizzo aziendale o non è impostato un altro dettaglio richiesto, riceverai un `400` con un `error` descrittivo. Configura il dettaglio mancante e riprova.

### Passaggio 3 - Esegui il polling fino allo stato ONLINE

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

Questo è l'endpoint condiviso per lo stato del numero di telefono: funziona sia per i numeri WhatsApp acquistati che per gli altri numeri collegati.

**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".
```

**Risposta**

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

### Passaggio 4 - Rilascia un numero

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

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

**Risposta**

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

Ciò che accade dipende dall'appartenenza del numero.

Per un numero **noleggiato tramite la piattaforma**, si tratta di un rilascio effettivo: il mittente WhatsApp viene deregistrato, il numero viene restituito all'operatore e rimosso dall'account, viene applicato un periodo di raffreddamento di 7 giorni durante il quale il numero non può essere riacquistato da nessuno e non vengono rimborsati crediti.

Per un numero **gestito direttamente dall'account** (il proprio account Twilio, la propria app Meta o account WhatsApp Business, o un gateway SMS Android), la stessa chiamata lo rimuove solo dall'account. Nulla viene rilasciato presso il provider a monte e non viene scritto alcun periodo di raffreddamento, quindi il numero può essere riconnesso immediatamente. La sua registrazione come mittente WhatsApp, se presente, potrebbe sopravvivere o meno: la procedura di rimozione tenta di eliminare il mittente utilizzando le credenziali Twilio gestite dalla piattaforma dell'account. Su un account ancora con la configurazione gestita, tali credenziali sono valide e il mittente viene eliminato, quindi riconnetterlo significa registrarlo nuovamente. Su un account che è passato al proprio Twilio, l'eliminazione non può autenticarsi e il mittente rimane registrato in quell'account; la riconnessione consiste quindi semplicemente nel riassociare il mittente esistente.

### Aggiungi un numero che già possiedi (BYO)

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

Salta completamente il flusso di ricerca e acquisto sopra descritto. Usalo quando l'account porta il proprio numero (il proprio Twilio, il proprio account Meta WhatsApp Business o un gateway SMS Android) invece di noleggiarne uno tramite la piattaforma. Questo registra solo il numero: non vengono addebitati crediti e non viene effettuato alcun provisioning con un provider. Il numero rimane inattivo finché il titolare dell'account non completa l'OAuth di WhatsApp per registrare un mittente su di esso (lo stesso flusso avviato dal pulsante "Porta il tuo numero" della dashboard).

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `phone_number` | Sì | Il numero da aggiungere, in formato E.164 (es. `+14155551234`). |
| `country_code` | Sì | Codice paese ISO 3166-1 alpha-2 (es. `US`). |
| `display_name` | No | Un'etichetta descrittiva. L'impostazione predefinita è il numero di telefono. |
| `category` | No | Etichetta di categoria opzionale. |

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

**Risposta** (`201 Created`):

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

Un `phone_number` che non è un numero E.164 reale (o che sembra il numero di test WhatsApp di Meta, che non può mai inviare messaggi a clienti reali) restituisce `400`. L'aggiunta di un numero già esistente nell'account, anche se scritto in modo leggermente diverso, come le forme `+52` e `+521` del Messico, restituisce `409` invece di creare una riga duplicata.

### Imposta un numero come primario

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

Imposta un numero su `is_active: true` e tutti gli altri numeri dell'account su `is_active: false`, in modo atomico: l'account non si ritroverà mai con due numeri attivi, o nessuno, a metà richiesta. `is_active` non può essere impostato tramite l'endpoint di aggiornamento generale di proposito; questa chiamata dedicata è l'unico modo per modificare quale numero è primario.

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

**Risposta**

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

`phone_number` qui è l'oggetto numero completo (la stessa forma restituita da `GET /phone-numbers`), non solo la stringa. Un `phoneNumber` non presente nell'account restituisce `404`.

### Rimuovi il record di un numero (senza rilasciarlo)

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

Una semplice eliminazione del record del numero su questo account: nessun rilascio o de-registrazione lato provider e nessun periodo di raffreddamento di 7 giorni come quello applicato per la procedura di rilascio sopra descritta. Usalo per cancellare record BYO, WhatsApp Web, Telegram o LINE, o una voce obsoleta, senza passare attraverso il flusso di rilascio gestito. A differenza di un rilascio, eliminare un numero che non è presente nell'account è un `404`, non un successo silenzioso.

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

**Risposta**

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

---

## Instradare un canale verso una campagna

La connessione di un canale porta i messaggi **all'interno** dell'account. Non decide **quale Agente IA risponderà**.

L'instradamento è gestito dai **Punti di Ingresso** (Entry Points) su un Agente IA, non dalle campagne. Ogni canale ha un Punto di Ingresso predefinito che indica l'Agente che risponde ai nuovi contatti sconosciuti su quel canale:

| Cosa vuoi fare | Chiamata |
|---|---|
| Puntare un canale verso l'Agente che dovrebbe rispondere | `PUT /entry-points/channel-defaults` con corpo `{ "channel": "instagram", "agent_id": "AGENT_ID" }` |
| Controllare se la gerarchia dei Punti di Ingresso è attiva per l'account | `GET /entry-points/routing-status`, che restituisce `{ "success": true, "cutover_enabled": true }` una volta che i Punti di Ingresso decidono l'instradamento dell'account |
| Lasciare un canale senza alcun Agente che risponda | `DELETE /entry-points/channel-defaults?channel=instagram` |

Finché un canale non dispone di un Entry Point, un primo messaggio da qualcuno con cui non hai mai parlato viene comunque archiviato, ma nulla lo preleva e nessun assistente risponde. Questo è il passaggio che manca alla maggior parte delle integrazioni: collegare Instagram e creare un Agente non è sufficiente di per sé — devi anche indirizzare il canale verso l'Agente. L'insieme completo di chiamate — inclusi un Agente per numero WhatsApp, parole chiave e regole per i commenti — si trova nell'[API degli Entry Point](entry-points.md).

`POST /channels/campaign` scrive ancora la mappa di instradamento legacy delle campagne per canale, documentata di seguito, ma tale mappa non viene più consultata per l'instradamento in entrata su nessun account; è conservata solo per il rollback. Non basare lo sviluppo su di essa.

### Instrada uno o più canali (mappa di instradamento legacy delle campagne)

`POST /channels/campaign`

**Campi della richiesta**

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `campaign_id` | Sì | La campagna che dovrebbe rispondere ai nuovi contatti su questi canali. Deve appartenere all'account. |
| `channels` | Sì | Un array non vuoto di canali da instradare. Consentiti: `whatsapp`, `whatsapp_web`, `telegram`, `instagram`, `messenger`, `chat_widget`, `custom_channel`, `sms`, `email`. |

Lo slot di instradamento e l'elenco `enabled_channels` della campagna vengono aggiornati insieme in un'unica operazione atomica, in modo che non possano mai divergere. Un canale già instradato verso una campagna diversa viene semplicemente reindirizzato verso questa.

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

**Risposta**

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

### Condizioni necessarie affinché l'instradamento si attivi effettivamente

Su un account che legge ancora la mappa di instradamento legacy delle campagne, l'instradamento ha successo come chiamata API, ma tre elementi sulla campagna decidono se un messaggio in entrata reale riceverà risposta. Controllali tutti e tre quando un canale instradato rimane silenzioso.

| Requisito | Cosa succede altrimenti |
|---|---|
| `type` è `Incoming from Unknown Contacts` o `Combined` | La richiesta viene rifiutata con `400`. Le campagne in uscita e le campagne con parole chiave non possono occupare uno slot di instradamento. |
| `status` è `Live` | L'instradamento viene memorizzato ma non prende mai nulla in carico. Una campagna `Draft` è la causa più comune di "l'ho instradato e non succede nulla". |
| `ai_mode` è `true` | Il contatto viene creato e il messaggio archiviato, ma l'assistente non risponde mai. |

La corrispondenza delle parole chiave ora risiede nei Punti di Ingresso: crea un Punto di Ingresso di tipo `keyword` sull'Agente IA che dovrebbe rispondere.

### Una campagna per canale

Ogni canale detiene esattamente uno slot di instradamento legacy. L'instradamento di una seconda campagna sullo stesso canale ripunta silenziosamente lo slot e restituisce `200`: non c'è alcun errore di conflitto. La campagna precedente continua a gestire i contatti che ha già; smette semplicemente di riceverne di nuovi.

### Cancella il routing di un canale

`DELETE /channels/campaign/{channel}`

Rimuove il routing per un singolo canale, indipendentemente dalla campagna a cui punta attualmente, e rimuove il canale dal `enabled_channels` di quella campagna. I nuovi contatti sconosciuti sul canale non vengono più presi in carico da alcuna campagna. I contatti già presenti nella campagna continuano come prima.

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

**Risposta**

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

È idempotente: cancellare un canale che non è mai stato instradato restituisce comunque `200`, con `cleared: false` e `campaign_id: null`. Questo endpoint richiede la funzionalità **campagne in entrata** nel piano; senza di essa si ottiene un `403`.


---

## Usa la tua app Meta (Instagram + Messenger)

Per impostazione predefinita, la connessione Instagram + Messenger viene eseguita tramite l'app Meta della piattaforma, quindi il nome di tale app è ciò che il titolare dell'account vede nella schermata di consenso di Facebook. Se desideri che la schermata di consenso mostri invece il **tuo** brand, puoi registrare la tua app Meta e instradare l'intero flusso attraverso di essa. Una volta configurata, si applicherà al tuo account: nulla cambia nelle chiamate di connessione sopra indicate, eccetto il branding.

> **Questo riguarda solo Instagram + Messenger.** Le connessioni a WhatsApp, WhatsApp Web, Telegram e LINE non sono influenzate da un'app Meta personalizzata.

### Di cosa ha bisogno la tua app per iniziare

Questa è la parte che richiede tempo e avviene interamente lato Meta:

1. **Un'app** di tipo Business, con i prodotti Messenger e Instagram aggiunti.
2. **Accesso avanzato** (tramite Meta App Review) per: `pages_show_list`, `pages_messaging`, `pages_manage_metadata`, `pages_read_engagement`, `instagram_basic`, `instagram_manage_messages`. Senza l'accesso avanzato, solo le persone che ricoprono un ruolo nella tua app possono completare la connessione: le connessioni dei tuoi clienti falliranno. L'App Review richiede solitamente alcune settimane e la verifica dell'attività commerciale (Business Verification).
3. **Una configurazione di Facebook Login for Business** creata all'interno della tua app, che conceda le stesse autorizzazioni. Il suo ID di configurazione numerico è specifico per ogni app, quindi devi crearne uno tuo.

Se alla tua app manca una delle autorizzazioni richieste, la connessione fallisce al momento del collegamento con un errore chiaro che indica cosa manca (visibile nel poll `/status` come `byo_app_missing_permissions`), invece di sembrare funzionante e fallire al primo messaggio.

### Passaggio 1 - Salva la tua app

`PUT /account-config/meta-app`

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `app_id` | Sì | Il tuo ID app Meta (Impostazioni → Base). |
| `app_secret` | Sì | Il tuo segreto dell'app Meta. Verificato su Meta prima di essere archiviato, quindi crittografato. Non viene mai restituito da alcun endpoint. |
| `config_id` | Sì | L'ID numerico della configurazione di Facebook Login for Business all'interno della tua app. |

Tutti e tre sono necessari per il flusso di accesso a Facebook. Se esegui solo la corsia di push del token di accesso a Instagram descritta più avanti, puoi ometterli completamente.

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

**Risposta**

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

### Passaggio 2 - Configura la tua app per comunicare con noi

Nella dashboard della tua app Meta:

1. **Webhooks** - per entrambi i prodotti Instagram e Messenger, imposta l'URL di callback sul valore `webhook_urls` corrispondente dalla risposta e il token di verifica su `verify_token`. Iscriviti ai campi `messages`, `messaging_postbacks` e `comments`.
2. **URI di reindirizzamento OAuth validi** - aggiungi `https://api.youraiconnector.com/v1/auth-meta-callback-handler` in modo che il flusso di consenso possa tornare indietro.

`GET /account-config/meta-app` restituisce sempre lo stesso materiale di configurazione; `DELETE /account-config/meta-app` rimuove l'app (le connessioni future torneranno all'app della piattaforma; rimuovi anche l'iscrizione al webhook all'interno della tua app).

### Passaggio 3 - Connetti come di consueto

Nient'altro cambia. `POST /channels/meta/connect` (e la pagina `connect_url` ospitata) utilizza automaticamente la tua app per il tuo account; il `uses_byo_meta_app: true` della risposta conferma quale app mostrerà la schermata di consenso. L'invio di messaggi, la selezione della pagina e le disconnessioni funzionano in modo identico.

## Utilizza la tua app di accesso Instagram (push del token)

La sezione precedente descrive il flusso di accesso a Facebook, in cui l'account si connette tramite una Pagina Facebook. Meta offre anche l'**API di Instagram con accesso a Instagram** (Business Login for Instagram): il titolare dell'account si autentica direttamente su Instagram, senza coinvolgere alcun account o Pagina Facebook.

Se la tua piattaforma utilizza già la propria app Meta con quel prodotto, non hai bisogno di alcun flusso OAuth da parte nostra. I tuoi clienti autorizzano la **tua** app e tu ci invii le credenziali completate per ogni account:

1. Salvi le credenziali della tua app Instagram una sola volta (così possiamo verificare i tuoi webhook).
2. Per ogni account, invii l'ID dell'account professionale Instagram + il token utente Instagram a lunga durata ottenuto dalla tua app.
3. Indirizzi il webhook di messaggistica Instagram della tua app verso di noi. Gli eventi per gli account che non hai mai inviato vengono riconosciuti e ignorati.
4. Gestisci tu il ciclo di vita del token: aggiorna i token nel tuo sistema e invia ogni token aggiornato con la stessa chiamata. Noi non aggiorniamo mai un token inviato.

### Di cosa ha bisogno la tua app per iniziare

- Il prodotto **Instagram** ("API setup with Instagram login") aggiunto alla tua app Meta. Quel prodotto ha la sua **coppia di App ID e App Secret**, distinta dall'App ID/Secret di Facebook: li trovi nel pannello di configurazione del prodotto.
- **Accesso avanzato** (tramite Meta App Review) per `instagram_business_basic` e `instagram_business_manage_messages` (aggiungi `instagram_business_manage_comments` se utilizzi l'automazione dei commenti). Senza di esso, solo le persone con un ruolo nella tua app possono autorizzarla.

### Passaggio 1 - Salva le credenziali della tua app Instagram

Stesso endpoint di cui sopra: invia la coppia Instagram a `PUT /account-config/meta-app`. I campi Facebook non sono necessari per questa corsia: invia la coppia da sola se esegui solo l'accesso a Instagram, oppure insieme ai campi Facebook se li esegui entrambi. Un salvataggio descrive sempre l'intera impostazione, quindi qualsiasi set tu ometta verrà rimosso.

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `instagram_app_id` | Insieme | L'App ID numerico del prodotto Instagram (non l'App ID di Facebook). |
| `instagram_app_secret` | Insieme | L'App Secret del prodotto Instagram. Crittografato a riposo, mai restituito. |

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

**Risposta** — contiene l'URL del webhook di accesso a Instagram (gli URL `instagram` e `messenger` appaiono solo quando vengono archiviati anche i campi Facebook):

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

Nel pannello **Webhooks** della tua app per il prodotto Instagram, imposta il Callback URL su `webhook_urls.instagram_login`, il Verify token su `verify_token` e iscriviti ai campi `messages` e `comments`.

### Passaggio 2 - Invia un token per account

`PUT /channels/instagram-login/token`

Funziona con `sub_account_id` come ogni altro percorso, quindi una chiave di agenzia può eseguire il provisioning dell'intera flotta.

| Campo | Obbligatorio | Descrizione |
|---|---|---|
| `ig_user_id` | Sì | L'**ID dell'account professionale Instagram** — il campo `user_id` da `GET https://graph.instagram.com/v21.0/me?fields=user_id,username`. Questo è lo stesso ID che i webhook di Instagram riportano come `entry.id`. ⚠️ **Non** è il campo `id` da `/me`: quello è limitato all'app e varia a seconda dell'app Meta. L'invio dell'ID limitato all'app restituisce un `400` che indica l'errore. |
| `access_token` | Sì | Il token utente Instagram a lunga durata ottenuto dalla tua app per quell'account. Convalidato in tempo reale su Instagram prima di essere archiviato: il token deve funzionare e deve appartenere a `ig_user_id`. |
| `expires_at` | No | Scadenza ISO-8601 del token. In alternativa, invia `expires_in` (secondi). Il valore predefinito è 60 giorni. |
| `username` | No | L'@handle dell'account; lo leggiamo comunque da Instagram. |

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

**Risposta**

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

Come parte dell'invio, iscriviamo la tua app ai webhook di quell'account (`subscribed_apps` con il token inviato), in modo che i messaggi inizino a fluire senza alcuna chiamata aggiuntiva da parte tua.

**Aggiornamento** - invia il token aggiornato allo stesso endpoint con lo stesso `ig_user_id`; aggiorna il token memorizzato e la scadenza sul posto.

**Conflitti** - un account Instagram non è mai attivo su due connessioni. Se l'account è già connesso altrove, o su questo stesso account tramite il flusso della Pagina Facebook, il push restituisce un `409` che indica quale connessione disconnettere per prima. Una connessione tramite flusso Facebook non viene mai sostituita automaticamente, poiché potrebbe servire anche Messenger.

### Passaggio 3 - Disconnetti quando un client esce

`DELETE /channels/instagram-login/token` (stessa autenticazione e `sub_account_id`) annulla l'iscrizione ai webhook al meglio delle possibilità e rimuove la credenziale memorizzata. Ha sempre successo, anche quando il token è già scaduto — e una volta rimossa la credenziale, gli eventi webhook di quell'account vengono ignorati.

---

## Suggerimenti per creare un wrapper affidabile

- **Esegui il polling con moderazione.** Ogni pochi secondi è sufficiente. Fermati una volta raggiunto uno stato terminale (`connected` / `ONLINE`, o uno stato di errore) e imposta un timeout complessivo sensato sul ciclo (i passaggi del browser/QR scadono, vedi ogni `expires_at`).
- **Codifica URL i numeri di telefono nel percorso.** Il `+` iniziale deve essere inviato come `%2B`. Gli endpoint recuperano anche le cifre nude, ma la codifica è l'impostazione predefinita sicura.
- **Non aspettarti mai di ricevere segreti.** I token di accesso, i segreti del canale e i token di pagina vengono accettati o archiviati, ma non vengono mai restituiti in alcuna risposta.
- **Gestisci il blocco di autenticazione.** Un `403` significa che l'accesso API non è incluso nel piano, o che il canale che stai collegando non è incluso nel piano dell'account. Vedi [Accesso API](../integrations/api-access.md).
- **Rispetta il limite di frequenza.** Le richieste autenticate sono limitate a 300 al minuto; un `429` significa attendere e riprovare. Vedi [Autenticazione](authentication.md).

## Passaggi successivi

- [Autenticazione](authentication.md) - le quattro forme di autenticazione accettate e il formato di errore.
- [Accesso API](../integrations/api-access.md) - generazione e gestione della tua chiave API.
