
# API de connexion de canal

Ce guide vous montre comment connecter des canaux de messagerie à un compte en utilisant l'API. Il est destiné aux développeurs créant une intégration ou un wrapper, il se concentre donc sur les requêtes exactes, l'ordre dans lequel les effectuer et les réponses que vous recevez.

Il y a un modèle que vous devez comprendre dès le départ, car il s'applique à presque tous les canaux présentés ici.

## Le modèle de connexion puis interrogation (poll)

La plupart des canaux ne peuvent pas être connectés avec un seul appel API. Connecter WhatsApp, Instagram ou Messenger signifie que le titulaire du compte doit se connecter à son propre compte fournisseur et approuver l'accès. Il n'existe **pas de chemin sans interface (entièrement automatisé)** pour cette approbation - une personne réelle doit ouvrir une URL dans un navigateur ou scanner un code QR avec son téléphone.

Le flux est donc toujours le suivant :

1. **Initiez la connexion** avec une `POST`. La réponse vous donne soit une URL à ouvrir, soit un code QR à afficher.
2. **Transmettez cela à l'utilisateur final** - ouvrez l'URL dans son navigateur ou affichez le code QR à l'écran pour qu'il le scanne.
3. **Interrogez le point de terminaison de statut** avec `GET` à court intervalle (toutes les quelques secondes) jusqu'à ce que le statut atteigne un état connecté.

Le travail de votre intégration consiste à piloter cette boucle : afficher l'URL ou le code QR, puis interroger jusqu'à ce que ce soit terminé. Planifiez votre interface utilisateur autour de l'interrogation - un indicateur de chargement avec un message du type « en attente de votre action dans votre navigateur » fonctionne bien.

::: note
**Remarque :** Avant de commencer, assurez-vous que l'accès à l'API est activé sur votre forfait et que vous disposez d'une clé API. Consultez [Accès à l'API](../integrations/api-access.md) pour savoir comment en générer une. Toutes les requêtes ci-dessous utilisent l'URL de base `https://api.youraiconnector.com/v1` et vous devez authentifier chaque requête. Consultez [Authentification](authentication.md) pour connaître les quatre formes acceptées - les exemples ici utilisent l'en-tête `X-API-Key`, avec un exemple cURL par page montrant la forme de requête `?apiKey=` plus simple.
:::


---

## Instagram + Messenger (Meta)

Instagram et Messenger sont connectés ensemble dans un seul flux, car ils fonctionnent tous deux sur une page Facebook. Le titulaire du compte s'autorise via Facebook, vous récupérez la liste des pages qu'il gère, et vous choisissez la page à connecter.

### Étape 1 - Démarrer la connexion Instagram + Messenger

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

Cela renvoie une URL de consentement. Aucune information d'identification n'est envoyée dans cette requête - la connexion est entièrement autorisée dans le navigateur.

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

**Réponse**

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

Ouvrez `oauth_url` dans le navigateur de l'utilisateur final afin qu'il puisse se connecter à Facebook et approuver l'accès. La tentative de connexion expire à `expires_at` (environ 30 minutes) - si elle expire, recommencez. Considérez `state_token` comme un secret à courte durée de vie et ne le consignez pas dans les journaux.

### Option la plus simple pour Instagram + Messenger : confier `connect_url`

La réponse inclut également une `connect_url` prête à l'emploi : une page hébergée qui exécute l'intégralité du flux pour le titulaire du compte. Il l'ouvre, se connecte à Facebook, et lorsqu'il possède plus d'une Page, elle affiche la liste et lui permet de choisir celle à connecter - puis elle signale la réussite par elle-même. Donnez ce lien au titulaire du compte au lieu d'ouvrir vous-même `oauth_url`, de créer un sélecteur de Page et d'interroger le statut. Le lien est valide pendant environ 30 minutes (`connect_url_expires_at`) ; s'il expire, démarrez une nouvelle connexion. Les étapes manuelles ci-dessous sont destinées aux intégrations qui souhaitent piloter le flux et afficher elles-mêmes le sélecteur de Page.

### Étape 2 - Interroger le statut jusqu'au chargement des pages

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

Une fois que l'utilisateur a terminé la connexion Facebook, interrogez ce point de terminaison toutes les quelques secondes. Le champ `status` suit ces étapes :

| `status` | Signification |
|---|---|
| `pending` | Consentement non encore terminé. Continuez d'attendre. |
| `token_received` | Autorisé, mais la liste des pages est toujours en cours de chargement. |
| `pages_loaded` | Les pages sont disponibles - passez à l'étape 3. |
| `connected` | Une page a été sélectionnée et le canal est actif. |

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

**Réponse (une fois les pages chargées)**

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

### Étape 3 - Lister les pages (optionnel)

Si vous préférez récupérer la liste des pages séparément (par exemple, pour afficher un sélecteur), utilisez :

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

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

Il renvoie le même tableau `pages` que le point de terminaison de statut. (Le point de terminaison `status` inclut déjà les pages, cet appel est donc simplement une commodité.)

### Étape 4 - Sélectionner la page à connecter

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

Envoyez le `page_id` de la page choisie par l'utilisateur. Le compte Instagram lié à cette page est connecté automatiquement ; vous n'avez besoin de l'objet `instagram` que si vous souhaitez remplacer le compte Instagram à utiliser.

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

**Réponse**

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

Le canal est maintenant connecté. Un `GET /channels/meta/status` de suivi indiquera `status: "connected"`.

### Lister les publications de la page connectée

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

Renvoie les publications récentes de la page que vous avez connectée - médias Instagram ou publications Facebook. C'est à partir de ces éléments que vous générez un sélecteur lorsque vous configurez un point d'entrée qui réagit aux commentaires sur une publication spécifique.

| Paramètre de requête | Requis | Description |
|---|---|---|
| `platform` | Oui | `instagram` ou `facebook`. Toute autre valeur renvoie une `400`. |
| `limit` | Non | Nombre de publications à renvoyer, `1`-`50`. La valeur par défaut est `25`. |
| `after` | Non | Curseur pour la page suivante - transmettez la valeur `nextCursor` de la réponse précédente. |

**cURL**

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

**Réponse**

```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` est le libellé propre à Instagram (`REELS`, `FEED`, `STORY`, ou le format - `IMAGE`, `VIDEO`, `CAROUSEL_ALBUM`) ; pour Facebook, il s'agit toujours de `POST`. `nextCursor` est `null` sur la dernière page.

Si rien ne peut être listé, l'appel renvoie tout de même `200` avec `connected: false` et un tableau `posts` vide, ainsi qu'un `reason` expliquant la raison :

| `reason` | Que faire |
|---|---|
| _(absent)_ | Aucune page n'est encore connectée - exécutez d'abord le flux de connexion. |
| `no_instagram_account` | Une page Facebook est connectée, mais aucun compte professionnel Instagram n'y est associé. Les publications Facebook sont listées normalement. |
| `token_expired` | Les identifiants de page stockés ne fonctionnent plus - reconnectez le canal. |

### Déconnecter Instagram + Messenger

```
DELETE /channels/meta
```

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

**Réponse**

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

Cela arrête le routage entrant pour Instagram et Messenger. C'est idempotent - l'appeler alors que rien n'est connecté réussit tout de même.

---

## WhatsApp Business

Ceci connecte un numéro WhatsApp Business officiel. Le numéro doit déjà exister sur le compte avant que vous n'appeliez la connexion. Comme pour Meta, le titulaire du compte autorise dans son navigateur, puis vous interrogez jusqu'à ce que le numéro indique `ONLINE`.

### Étape 1 - Démarrer la connexion 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.
```

| Champ | Requis | Description |
|---|---|---|
| `phone_number` | Oui | Le numéro à connecter, au format E.164 (par ex. `+14155551234`). |
| `only_waba_sharing` | Non | Restreindre l'autorisation au partage d'un compte WhatsApp Business existant, en ignorant la configuration d'un nouvel expéditeur. Par défaut à `false`. |
| `retry` | Non | Relancer l'autorisation pour un numéro dont la tentative précédente n'a pas abouti. Par défaut à `false`. |
| `business_name` | Non | Remplacement cosmétique pour le nom de l'entreprise affiché sur l'écran de consentement uniquement (max 256 caractères). Non stocké. |
| `description` | Non | Remplacement cosmétique pour la description de l'entreprise affichée sur l'écran de consentement uniquement (max 256 caractères). Non stocké. |

**Réponse**

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

Ouvrez `oauth_url` dans le navigateur du titulaire du compte pour autoriser. Une fois approuvé, l'enregistrement se termine en arrière-plan.

### Étape 2 - Interroger le statut jusqu'à ONLINE

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

Interrogez ceci jusqu'à ce que `status` soit `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".
```

**Réponse**

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

Le champ `status` peut être :

| `status` | Signification |
|---|---|
| `PENDING` | Autorisé, approbation toujours en cours. Continuez à interroger. |
| `ONLINE` | Connecté et prêt à envoyer. |
| `RATE_LIMITED` | Trop de tentatives - attendez avant de réessayer. |
| `REGISTRATION_FAILED` | La configuration n'a pas pu être terminée. |
| `DELETED` | L'enregistrement n'existe plus. |

`live: true` signifie que le statut a été vérifié auprès du fournisseur en temps réel ; `false` signifie qu'il provient du dernier état mis en cache.

### Déconnecter un numéro 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"
```

**Réponse**

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

Le numéro lui-même reste sur le compte, vous pouvez donc le reconnecter plus tard.

---

## WhatsApp Web

WhatsApp Web associe un numéro WhatsApp standard en scannant un code QR, tout comme l'association d'un appareil dans l'application WhatsApp. Le processus est le suivant : démarrer la session, récupérer le code QR et l'afficher, puis interroger le statut jusqu'à ce qu'il soit `connected`.

### Étape 1 - Démarrer une session de jumelage 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()
```

| Champ | Requis | Description |
|---|---|---|
| `phone_number` | Oui | Le numéro WhatsApp à connecter, au format E.164. |
| `proxy_country` | Non | Code pays ISO 3166-1 alpha-2 pour la région de routage. Détecté automatiquement à partir du numéro si omis. |
| `force_new` | Non | Ignorer toute session existante et recommencer une nouvelle association. Par défaut à `false`. |
| `import_contacts` | Non | Importer les contacts existants de l'appareil lors de la première connexion. Par défaut à `false`. |
| `pause_ai_for_imported_contacts` | Non | Lors de l'importation des contacts, maintenir les réponses automatiques en pause pour eux. Par défaut à `true`. |
| `import_existing_chats` | Non | Importer l'historique des discussions existant (nécessite `import_contacts: true`). Par défaut à `false`. |

**Réponse**

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

### Option la plus simple pour WhatsApp Web : confier `connect_url`

La réponse inclut un `connect_url` prêt à l'emploi : une page hébergée qui affiche le code QR, l'actualise automatiquement lorsqu'il pivote et affiche un message de réussite dès que le numéro est lié. Il vous suffit de transmettre ce lien au titulaire du compte (ouvrez-le dans un navigateur, envoyez-le-lui ou affichez-le sous forme de QR/bouton) et demandez-lui de le scanner avec WhatsApp - vous n'avez pas besoin de récupérer le QR ou d'interroger quoi que ce soit vous-même. Le lien est valide pendant environ 30 minutes (`connect_url_expires_at`) ; s'il expire avant qu'ils n'aient terminé, démarrez une nouvelle connexion pour en obtenir un nouveau.

C'est la méthode recommandée lorsqu'une personne peut ouvrir un lien. Les étapes manuelles ci-dessous (récupérer le QR vous-même, interroger le statut) sont destinées aux intégrations qui souhaitent afficher le QR dans leur propre interface.

La réponse vous fournit également le `poll_qr_path` et le `poll_status_path` exacts à utiliser, afin que vous n'ayez pas à les créer vous-même.

### Étape 2 - Récupérer le code QR et l'afficher

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

**Réponse**

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

Affichez le QR pour que l'utilisateur puisse le scanner avec son téléphone (WhatsApp > Appareils connectés > Connecter un appareil) :

- `qr_data_url` est une image prête à l'emploi - insérez-la directement dans une balise `<img src>`.
- `qr_code` est la charge utile brute si vous préférez générer l'image vous-même.

Le QR a une durée de vie limitée. Si vous appelez cette fonction juste après le démarrage de la session, vous pourriez recevoir une `404` avec le message "QR code not available yet" - attendez simplement un instant et réessayez. Si vous recevez une `410` ("QR code expired"), recommencez la connexion pour obtenir un nouveau code.

### Étape 3 - Interroger le statut jusqu'à la connexion

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

**Réponse**

```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` | Signification |
|---|---|
| `not_initialized` | Aucune session pour le moment (échec terminal). |
| `qr_pending` | En attente du scan du QR. |
| `connecting` | Scanné, finalisation de la configuration. |
| `connected` / `open` | Connecté et actif - c'est un succès. |
| `disconnected` | Session terminée (échec terminal). |

### Déconnecter une session 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"
```

**Réponse**

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

Ceci dissocie l'appareil et supprime la connexion. L'état local est toujours nettoyé, ce qui rend l'opération idempotente même si la session sous-jacente a déjà disparu.

---

## Telegram

> **Disponibilité :** Telegram se connecte comme n'importe quel autre canal et est ouvert à tous les comptes — vous n'avez pas besoin qu'il soit activé pour vous. Les points de terminaison Telegram ci-dessous peuvent toujours renvoyer `403` si Telegram n'est pas inclus dans le forfait du compte, auquel cas l'erreur indique `"This channel is not included in your current plan. Upgrade to unlock it."`.

Telegram connecte un compte personnel via un numéro de téléphone et un code de connexion à usage unique (ainsi qu'un mot de passe à deux facteurs, si le compte en possède un). Le processus est le suivant : démarrer la session, soumettre le code, soumettre éventuellement le mot de passe, puis confirmer via le statut.

### Étape 1 - Démarrer une session de connexion 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()
```

| Champ | Requis | Description |
|---|---|---|
| `phone_number` | Oui | Le numéro de téléphone du compte à connecter, au format E.164. |
| `mode` | Non | `code` (par défaut) envoie un code de connexion à usage unique au compte ; `qr` renvoie un jeton de connexion et une URL QR à afficher. |
| `proxy_country` | Non | Code pays ISO 3166-1 alpha-2 pour la route réseau sortante. |
| `force_new` | Non | Lorsque `true`, ignore toute session existante et repart à zéro. |

**Réponse**

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

En mode `code`, le compte reçoit un code de connexion dans Telegram et `status` est `code_required`. (En mode `qr`, la réponse inclut également `login_token` et `qr_url` à afficher pour la numérisation, et `status` est `qr_required`.)

### Option la plus simple pour Telegram : confier `connect_url`

La réponse inclut un `connect_url` prêt à l'emploi : une page hébergée qui finalise la connexion d'elle-même. En mode `code`, le titulaire du compte saisit le code de connexion - ainsi qu'un mot de passe de vérification en deux étapes si son compte en possède un. En mode `qr`, la page affiche un QR code qui s'actualise automatiquement pour qu'il puisse le scanner depuis l'application Telegram. Dans les deux cas, elle signale la réussite par elle-même ; vous pouvez donc simplement transmettre ce lien au titulaire du compte au lieu de créer votre propre interface et d'effectuer des interrogations (polling). Le lien est valide pendant environ 30 minutes (`connect_url_expires_at`) ; s'il expire, démarrez une nouvelle connexion pour en obtenir un nouveau.

Les étapes manuelles ci-dessous (collecter le code vous-même, le soumettre, interroger le statut ; ou afficher `qr_url` et interroger) sont destinées aux intégrations qui souhaitent afficher l'interface elles-mêmes.

### Étape 2 - Soumettre le code de connexion

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

**Réponse**

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

Si `status` est `connected`, vous avez terminé. Si le compte a la double authentification activée, `status` sera `password_required` à la place - passez à l'étape 3.

### Étape 3 - Soumettre le mot de passe à deux facteurs (uniquement si nécessaire)

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

N'appelez ceci que lorsque l'étape 2 a renvoyé `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()
```

**Réponse**

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

### Vérifier le statut de 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"
```

**Réponse**

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

`status` peut être `connected`, `code_required`, `password_required`, `initializing`, `disconnected`, `not_initialized` ou `error`.

### Déconnecter Telegram

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

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

**Réponse**

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

Idempotent - les appels répétés réussissent.

---

## Instagram (compte personnel)

> Bêta à disponibilité limitée, activée par compte. Cela permet de connecter un compte Instagram personnel en se connectant avec son nom d'utilisateur et son mot de passe (et non via l'API Business officielle). Si le compte n'est pas activé pour la bêta, l'appel de connexion renvoie une erreur de permission.

Comme cela nécessite les identifiants Instagram du titulaire du compte, le chemin le plus simple consiste à lui fournir la `connect_url` hébergée et à le laisser saisir ses identifiants à cet endroit - votre intégration ne gère jamais le mot de passe.

### Étape 1 - Démarrer une connexion Instagram (personnel)

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

Envoyez l'`username` et le `password` Instagram.

**Réponse**

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

Si le compte utilise l'authentification à deux facteurs ou si Instagram présente un point de contrôle, `status` revient sous la forme `two_factor_required` ou `challenge_required` - soumettez le code à `/connect/{id}/verify-2fa` ou `/connect/{id}/verify-challenge` ci-dessous, puis interrogez `/connect/{id}/status` jusqu'à ce que `connected`. `{id}` est le nom d'utilisateur Instagram normalisé renvoyé sous la forme `account_id`/`username` dans la réponse ci-dessus - utilisez-le à chaque étape ci-dessous.

### Étape 2 - Soumettre le code à deux facteurs (si demandé)

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

N'appelez cette fonction que lorsque l'étape 1 (ou l'étape 3) a renvoyé `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" }'
```

**Réponse**

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

`status` peut renvoyer `connected` (terminé), `two_factor_required` (code erroné, réessayez), ou `challenge_required` (Instagram demande également un code de point de contrôle - passez à l'étape 3).

### Étape 3 - Soumettre le code de confirmation du point de contrôle (si demandé)

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

N'appelez cette fonction que lorsqu'une étape précédente a renvoyé `challenge_required`. La structure de la requête et de la réponse est identique à celle de l'étape 2 ci-dessus.

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

### Vérifier le statut d'Instagram (personnel)

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

Interrogez cette fonction jusqu'à ce que `status` soit `connected`, ou jusqu'à ce qu'elle signale une erreur terminale.

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

**Réponse**

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

`status` peut être `connected`, `two_factor_required`, `challenge_required`, `initializing`, `disconnected`, `not_initialized`, ou `error`. `live: true` signifie que cette valeur a été lue en direct depuis le processus de connexion plutôt qu'à partir d'une valeur mise en cache.

### Option la plus simple pour Instagram (personnel) : confier `connect_url`

La réponse inclut une `connect_url` : une page hébergée où le titulaire du compte saisit son nom d'utilisateur et son mot de passe Instagram (ainsi qu'un code 2FA ou de point de contrôle si Instagram le demande), et qui signale la réussite par elle-même. Les identifiants sont envoyés directement à Instagram et ne sont pas stockés. Donnez ce lien au titulaire du compte au lieu de collecter son mot de passe dans votre propre interface. Le lien est valide pendant environ 30 minutes (`connect_url_expires_at`).

### Déconnecter Instagram (personnel)

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

Idempotent - les appels répétés réussissent.

### Synchroniser les abonnés

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

Déclenche manuellement une synchronisation des abonnés pour un compte connecté - la même tâche que celle qui s'exécute automatiquement en arrière-plan, exposée ici pour une action « Actualiser les abonnés » à la demande. Elle récupère la liste actuelle des abonnés du compte, enregistre les nouveaux venus et (lorsqu'une campagne en direct a activé la prospection des abonnés) envoie aux nouveaux abonnés un message direct d'ouverture, dans la limite d'un plafond quotidien.

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

**Réponse**

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

> Ces cinq champs sont le seul endroit sur cette page qui renvoie `camelCase` au lieu de `snake_case` - c'est ainsi que ce point de terminaison est configuré aujourd'hui, ce n'est pas une erreur. `isBaselineSeed: true` signifie qu'il s'agissait de la toute première synchronisation après la connexion, qui enregistre uniquement la liste initiale des abonnés et n'envoie jamais de messages directs de prospection (donc `dmsSent` est toujours `0` lors de cette exécution).

Le tout premier appel pour un compte peut prendre un certain temps (parcours de la liste complète des abonnés) ; les appels ultérieurs sont plus rapides car seuls les nouveaux abonnés sont comparés. `404` signifie que le compte n'est pas connecté ; `412` signifie que la connexion n'a pas encore fini de s'initialiser - attendez et réessayez.

---

## LINE

LINE est le canal le plus simple à connecter car il n'y a ni redirection de navigateur ni interrogation (polling). Le client crée un canal Messaging API dans la console LINE Developers, copie deux valeurs, et vous les soumettez en un seul appel. Vous leur fournissez ensuite une URL de webhook à coller dans la console.

### Étape 1 - Connexion avec les identifiants du canal

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

| Champ | Requis | Description |
|---|---|---|
| `channel_access_token` | Oui | Le jeton d'accès au canal Messaging API à longue durée de vie du compte officiel. Utilisé pour envoyer et recevoir des messages. |
| `channel_secret` | Oui | Le secret du canal Messaging API, utilisé pour vérifier les signatures des événements entrants. |
| `channel_id` | Non | L'identifiant numérique du canal. À titre informatif uniquement. |

**Réponse**

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

Deux champs sont importants pour la suite de vos opérations :

- **`webhook_url`** - le client doit le coller dans le champ **Webhook URL** de son canal LINE dans la console LINE Developers (et activer "Use webhook"). Tant qu'il ne le fait pas, aucun message entrant n'arrivera. Affichez-le bien en évidence.
- **`chat_mode_ok`** - lorsque `false`, le compte officiel est en mode "chat" et ne recevra ni n'enverra de messages tant qu'il ne sera pas basculé en mode "bot" dans le LINE Official Account Manager. Conditionnez votre intégration à cet indicateur et demandez au client de changer de mode.

> Le `channel_access_token` et le `channel_secret` ne sont jamais renvoyés par aucun point de terminaison. Stockez-les de votre côté si vous en avez besoin à nouveau ; sinon, copiez-les à nouveau depuis la console LINE.

Le `bot_user_id` renvoyé ici est l'identifiant de connexion que vous utilisez dans les appels de statut, de vérification et de déconnexion ci-dessous.

### Étape 2 - Revérification après la configuration du webhook

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

Une fois que le client a fini de configurer l'URL du webhook et est passé en mode bot, appelez cette fonction pour revalider le jeton stocké et actualiser le mode de chat mis en cache.

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

**Réponse**

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

Si `token_valid` est `false`, le jeton d'accès stocké ne permet plus l'authentification - demandez au client de le réémettre dans la console et d'appeler à nouveau `POST /channels/line` avec le nouveau jeton.

### Vérifier le statut de LINE

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

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

**Réponse**

```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 ne disposant pas de flux de statut en direct, `live` est toujours `false` ici - les valeurs reflètent l'état capturé au moment de la connexion (ou de la dernière vérification).

### Déconnecter LINE

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

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

**Réponse**

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

---

## Viber

Viber se connecte de la même manière que LINE - collez le jeton d'authentification du bot depuis le panneau d'administration Viber en un seul appel - avec une différence importante : la connexion ENREGISTRE également notre webhook sur votre bot immédiatement, il n'y a donc pas d'étape de console distincte par la suite. Cela signifie également qu'une tentative de connexion peut échouer si notre entrée ne peut pas répondre à la vérification synchrone du webhook de Viber, et pas seulement si le jeton lui-même est incorrect.

### Étape 1 - Se connecter avec le jeton d'authentification du bot

```
POST /channels/viber
```

| Champ | Requis | Description |
|---|---|---|
| `auth_token` | Oui | Le jeton d'authentification du bot, depuis le panneau d'administration Viber (Paramètres de mon 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" }'
```

**Réponse**

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

Le jeton d'authentification n'est jamais renvoyé par aucun point de terminaison - stockez-le de votre côté si vous devez le recoller. `bot_id` est l'identifiant de connexion utilisé par les appels d'état, de vérification et de déconnexion ci-dessous.

### Vérifier l'état de Viber

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

Rapporte l'état de connexion stocké. Ajoutez `?live=true` pour revérifier également le bot auprès de Viber et actualiser l'enregistrement du webhook mis en cache - utile avant de supposer qu'un bot silencieux est réellement en panne.

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

**Réponse**

```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` signifie que le webhook du bot ne pointe plus vers nous - les messages entrants sont perdus. Cela signifie généralement qu'un autre outil a connecté le même bot par la suite (l'enregistrement du webhook de Viber privilégie la dernière écriture). Corrigez cela avec l'appel de revérification ci-dessous, inutile de demander au client de recoller son jeton. `live` est `false` lorsque la réponse est le dernier état mis en cache plutôt qu'une nouvelle vérification auprès de Viber.

### Réenregistrer le webhook

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

L'action de réparation pour `webhook_ok: false` - réenregistre notre webhook sur le bot en utilisant le jeton d'authentification déjà stocké.

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

**Réponse**

```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` signifie que le jeton stocké ne fonctionne plus - reconnectez-vous avec `POST /channels/viber` et un nouveau jeton.

### Déconnecter Viber

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

Désenregistre notre webhook du côté de Viber (au mieux) et supprime la connexion.

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

**Réponse**

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

---

## TikTok

> **Disponibilité :** Bêta à disponibilité limitée, activée par compte. La connexion à TikTok renvoie une erreur de permission tant que le compte n'a pas été activé pour cette fonctionnalité.

TikTok Business Messaging est un canal OAuth complet comme Meta, mais plus simple côté interrogation : il n'y a pas d'étape dédiée d'interrogation du statut à développer, car le compte connecté apparaît de lui-même une fois que TikTok redirige l'utilisateur et que la connexion est enregistrée. Le point de terminaison de statut ci-dessous existe pour confirmer l'état à la demande (outils de support, vérifications de santé), et non comme quelque chose sur lequel vous devez boucler pendant la connexion.

### Étape 1 - Démarrer la connexion TikTok

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

Ne nécessite aucune information d'identification - le titulaire du compte autorise entièrement l'accès dans son navigateur.

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

**Réponse**

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

Ouvrez `oauth_url` dans le navigateur du titulaire du compte afin qu'il puisse se connecter à TikTok et approuver l'accès. L'état expire à `expires_at` (environ 30 minutes) - s'il expire, recommencez. Il n'existe pas de raccourci de page hébergée `connect_url` pour TikTok ; ouvrir `oauth_url` vous-même est le seul chemin possible.

### Vérifier le statut TikTok

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

`openId` est l'open_id du compte TikTok Business, connu une fois que le rappel OAuth a été exécuté.

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

**Réponse**

```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 ne propose pas de vérification de santé en direct peu coûteuse, donc `live` est toujours `false` ici - les champs reflètent ce que la connexion (ou le dernier rafraîchissement de jeton) a écrit. `status: "reauth_required"` avec `status_reason` défini signifie que le compte doit repasser par la connexion ; les jetons TikTok sont rafraîchis automatiquement lors d'une rotation annuelle, et c'est ce qui apparaît si cette rotation échoue.

### Déconnecter TikTok

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

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

**Réponse**

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

---

## GoHighLevel

GoHighLevel (GHL) est une intégration CRM, pas un canal de messagerie - sa connexion n'utilise pas de slot de canal dans le forfait, car elle utilise les canaux existants du compte au lieu d'en ajouter un nouveau. C'est également la seule intégration sur cette page qui peut gérer **plus d'une connexion à la fois** : chaque sous-compte GHL (« emplacement ») sur lequel le client installe l'application obtient sa propre entrée.

### Étape 1 - Démarrer la connexion GHL

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

| Champ | Requis | Description |
|---|---|---|
| `brand` | Non | Quelle liste de marketplace GHL utiliser pour l'autorisation. La valeur par défaut est la liste standard - utile uniquement si votre déploiement a plus d'une application marketplace configurée. |

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

**Réponse**

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

Ouvrez `oauth_url` dans le navigateur du titulaire du compte afin qu'il puisse choisir un emplacement GHL et approuver l'accès. L'état expire à `expires_at` (environ 30 minutes).

### Lister les connexions GHL

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

Contrairement aux autres canaux, il ne s'agit pas du statut d'une seule connexion - cela liste chaque emplacement que le compte a connecté.

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

**Réponse**

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

### Déconnecter un emplacement GHL

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

Supprime la connexion ici, ce qui arrête toute synchronisation et tout déclencheur pour cet emplacement. Cela ne désinstalle pas l'application du côté GHL - le client la supprime de ses installations marketplace GHL s'il le souhaite également.

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

**Réponse**

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

---

## Numéros de téléphone (achat et libération)

Au lieu de connecter un numéro existant, vous pouvez acheter directement un nouveau numéro compatible WhatsApp. Recherchez les numéros disponibles, achetez-en un, puis interrogez le statut jusqu'à ce que le provisionnement soit terminé.

::: note
**Remarque :** Les numéros achetés ici sont compatibles avec WhatsApp. L'enregistrement de l'expéditeur WhatsApp s'exécute en arrière-plan après l'achat ; vous devez donc interroger le statut jusqu'à ce qu'il atteigne `ONLINE` avant d'envoyer des messages. Les crédits sont déduits lors de l'achat et ne sont **pas** remboursés lorsque vous libérez le numéro.
:::


### Étape 1 - Rechercher les numéros disponibles

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

| Paramètre de requête | Requis | Description |
|---|---|---|
| `country_code` | Oui | Code pays ISO 3166-1 alpha-2 dans lequel effectuer la recherche (par ex. `US`, `GB`, `NL`). |
| `type` | Non | Classe de numéro préférée, `local` ou `mobile`. Les deux classes peuvent tout de même être renvoyées. |

**Réponse**

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

Chaque résultat affiche le montant unique `purchase_credits` et le montant récurrent `monthly_credits`. Un numéro fourni par la plateforme coûte au moins 50 crédits par mois, montant qui augmente en fonction du prix mensuel de l'opérateur, facturé lors de l'achat et à chaque renouvellement. Utilisez le `purchase_credits` / `monthly_credits` renvoyé par la recherche ; ne calculez jamais un prix vous-même. La première recherche sur un nouveau compte provisionne certaines ressources sous-jacentes, elle peut donc être un peu plus lente que les recherches ultérieures.

### Étape 2 - Acheter un numéro

```
POST /phone-numbers
```

Utilisez un `phone_number` parmi les résultats de recherche.

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

| Champ | Requis | Description |
|---|---|---|
| `phone_number` | Oui | Un numéro renvoyé par la recherche de numéros disponibles, au format E.164. |
| `country_code` | Oui | Code pays ISO 3166-1 alpha-2 (par ex. `US`). |
| `display_name` | Non | Une étiquette conviviale. Par défaut, il s'agit du numéro de téléphone. |
| `category` | Non | Étiquette de catégorie facultative. |

**Réponse**

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

Le numéro commence dans l'état `PURCHASED`. L'enregistrement WhatsApp se poursuit ensuite en arrière-plan : `PURCHASED` -> `PENDING` -> `ONLINE`.

> Si l'achat échoue parce qu'une adresse professionnelle est manquante ou qu'un autre détail requis n'est pas défini, vous recevrez une `400` avec un `error` descriptif. Configurez le détail manquant et réessayez.

### Étape 3 - Interroger jusqu'à l'état ONLINE

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

Il s'agit du point de terminaison partagé pour le statut des numéros de téléphone - il fonctionne aussi bien pour les numéros WhatsApp achetés que pour vos autres numéros connectés.

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

**Réponse**

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

### Étape 4 - Libérer un numéro

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

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

**Réponse**

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

L'action effectuée dépend du propriétaire du numéro.

Pour un numéro **loué via la plateforme**, il s'agit d'une véritable libération : l'expéditeur WhatsApp est désenregistré, le numéro est restitué à l'opérateur et supprimé du compte, une période de refroidissement de 7 jours est appliquée pendant laquelle le numéro ne peut être racheté par personne, et aucun crédit n'est remboursé.

Pour un numéro **dont le compte a apporté sa propre configuration** (son propre compte Twilio, sa propre application Meta ou compte WhatsApp Business, ou une passerelle SMS Android), le même appel le supprime simplement du compte. Rien n'est libéré chez le fournisseur en amont et aucun délai de refroidissement n'est enregistré, le numéro peut donc être reconnecté immédiatement. Son enregistrement d'expéditeur WhatsApp, s'il en avait un, peut survivre ou non : la procédure de suppression tente de supprimer l'expéditeur en utilisant les identifiants Twilio gérés par la plateforme du compte. Sur un compte toujours dans la configuration gérée, ces identifiants sont valides et l'expéditeur est supprimé, donc la reconnexion implique de l'enregistrer à nouveau. Sur un compte qui est passé à son propre Twilio, la suppression ne peut pas s'authentifier et l'expéditeur reste enregistré dans ce compte — la reconnexion consiste alors simplement à rattacher l'expéditeur existant.

### Ajouter un numéro que vous possédez déjà (BYO)

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

Ignore entièrement le flux de recherche et d'achat ci-dessus. Utilisez ceci lorsque le compte apporte son propre numéro (son propre Twilio, son propre compte Meta WhatsApp Business, ou une passerelle SMS Android) au lieu d'en louer un via la plateforme. Cela enregistre uniquement le numéro - aucun crédit n'est facturé, et rien n'est provisionné auprès d'un fournisseur ici. Le numéro reste inactif jusqu'à ce que le titulaire du compte termine l'OAuth WhatsApp pour enregistrer un expéditeur dessus (le même flux que le bouton "Apporter votre propre numéro" du tableau de bord lance).

| Champ | Requis | Description |
|---|---|---|
| `phone_number` | Oui | Le numéro à ajouter, au format E.164 (par ex. `+14155551234`). |
| `country_code` | Oui | Code pays ISO 3166-1 alpha-2 (par ex. `US`). |
| `display_name` | Non | Une étiquette conviviale. Par défaut, le numéro de téléphone. |
| `category` | Non | Étiquette de catégorie optionnelle. |

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

**Réponse** (`201 Created`) :

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

Un `phone_number` qui n'est pas un vrai numéro E.164 (ou qui ressemble au numéro de test WhatsApp de Meta, qui ne peut jamais envoyer de messages à de vrais clients) renvoie `400`. L'ajout d'un numéro qui existe déjà sur le compte - même orthographié légèrement différemment, comme les formes `+52` vs `+521` du Mexique - renvoie `409` au lieu de créer une ligne en double.

### Définir un numéro comme principal

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

Passe un numéro à `is_active: true` et tous les autres numéros du compte à `is_active: false`, de manière atomique - le compte ne se retrouve jamais avec deux numéros actifs, ou aucun, au milieu de la requête. `is_active` ne peut pas être défini via le point de terminaison de mise à jour général volontairement ; cet appel dédié est le seul moyen de changer quel numéro est principal.

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

**Réponse**

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

`phone_number` ici est l'objet numéro complet (la même forme que `GET /phone-numbers` renvoie), pas seulement la chaîne. Un `phoneNumber` qui n'est pas sur le compte renvoie `404`.

### Supprimer l'enregistrement d'un numéro (sans le libérer)

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

Une suppression simple de l'enregistrement du numéro sur ce compte - aucune libération ou désenregistrement côté fournisseur, et aucun délai de refroidissement de 7 jours comme l'étape de libération ci-dessus ne s'applique. Utilisez ceci pour effacer les enregistrements BYO, WhatsApp Web, Telegram ou LINE, ou une entrée obsolète, sans passer par le flux de libération géré. Contrairement à une libération, supprimer un numéro qui n'est pas sur le compte est une `404`, pas un succès silencieux.

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

**Réponse**

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

---

## Acheminer un canal vers une campagne

La connexion d'un canal permet de recevoir des messages **dans** le compte. Cela ne détermine pas **quel agent IA y répond**.

Le routage est géré par les **Points d'entrée** d'un agent IA, et non par les campagnes. Chaque canal possède un point d'entrée par défaut qui désigne l'agent répondant aux nouveaux contacts inconnus sur ce canal :

| Ce que vous voulez faire | Appel |
|---|---|
| Diriger un canal vers l'agent qui doit y répondre | `PUT /entry-points/channel-defaults` avec le corps `{ "channel": "instagram", "agent_id": "AGENT_ID" }` |
| Vérifier si la hiérarchie des points d'entrée est active pour le compte | `GET /entry-points/routing-status`, qui renvoie `{ "success": true, "cutover_enabled": true }` une fois que les points d'entrée déterminent le routage de ce compte |
| Laisser un canal sans agent pour y répondre | `DELETE /entry-points/channel-defaults?channel=instagram` |

Tant qu'un canal n'a pas de point d'entrée (Entry Point), un premier message provenant d'une personne à qui vous n'avez jamais parlé est stocké, mais rien ne le récupère et aucun assistant ne répond. C'est l'étape que la plupart des intégrations oublient : connecter Instagram et créer un agent ne suffit pas en soi — vous devez également diriger le canal vers l'agent. L'ensemble complet des appels — incluant un agent par numéro WhatsApp, les mots-clés et les règles de commentaires — se trouve dans l'[API des points d'entrée](entry-points.md).

`POST /channels/campaign` écrit toujours la carte de routage de campagne héritée par canal, documentée ci-dessous, mais cette carte n'est plus consultée pour le routage entrant sur aucun compte ; elle est conservée uniquement pour la restauration. Ne développez pas en vous basant sur celle-ci.

### Router un ou plusieurs canaux (carte de routage de campagne héritée)

`POST /channels/campaign`

**Champs de la requête**

| Champ | Requis | Description |
|---|---|---|
| `campaign_id` | Oui | La campagne qui doit répondre aux nouveaux contacts sur ces canaux. Doit appartenir au compte. |
| `channels` | Oui | Un tableau non vide de canaux à acheminer. Autorisé : `whatsapp`, `whatsapp_web`, `telegram`, `instagram`, `messenger`, `chat_widget`, `custom_channel`, `sms`, `email`. |

L'emplacement d'acheminement et la liste `enabled_channels` de la campagne sont mis à jour ensemble en une seule opération atomique, de sorte qu'ils ne peuvent jamais diverger. Un canal déjà acheminé vers une campagne différente est simplement redirigé vers celle-ci.

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

**Réponse**

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

### Conditions nécessaires pour que l'acheminement soit effectif

Sur un compte qui lit toujours la carte de routage de campagne héritée, le routage réussit en tant qu'appel API, mais trois éléments de la campagne déterminent si un message entrant réel reçoit une réponse. Vérifiez ces trois points lorsqu'un canal routé reste silencieux.

| Exigence | Ce qui se passe sinon |
|---|---|
| `type` est `Incoming from Unknown Contacts` ou `Combined` | La requête est rejetée avec `400`. Les campagnes sortantes et par mots-clés ne peuvent pas occuper un emplacement de routage. |
| `status` est `Live` | Le routage est stocké mais ne récupère jamais rien. Une campagne `Draft` est la cause la plus fréquente de "J'ai routé le canal et rien ne se passe". |
| `ai_mode` est `true` | Le contact est créé et le message stocké, mais l'assistant ne répond jamais. |

La correspondance par mots-clés se trouve désormais dans les points d'entrée — créez un point d'entrée de type `keyword` sur l'agent IA qui doit répondre.

### Une campagne par canal

Chaque canal détient exactement un emplacement de routage hérité. Router une seconde campagne vers le même canal redirige silencieusement l'emplacement et renvoie `200` — il n'y a pas d'erreur de conflit. La campagne précédente continue de gérer les contacts qu'elle possède déjà ; elle cesse simplement d'en recevoir de nouveaux.

### Effacer le routage d'un canal

`DELETE /channels/campaign/{channel}`

Supprime le routage pour un canal unique, quelle que soit la campagne vers laquelle il pointe actuellement, et retire le canal de la `enabled_channels` de cette campagne. Les nouveaux contacts inconnus sur le canal ne sont plus pris en charge par aucune campagne. Les contacts déjà présents dans la campagne continuent comme avant.

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

**Réponse**

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

C'est idempotent : effacer un canal qui n'a jamais été routé renvoie également `200`, avec `cleared: false` et `campaign_id: null`. Ce point de terminaison nécessite la fonctionnalité **campagnes entrantes** sur le forfait ; sans cela, vous recevrez une `403`.


---

## Utiliser votre propre application Meta (Instagram + Messenger)

Par défaut, la connexion Instagram + Messenger passe par l'application Meta de la plateforme. C'est donc le nom de cette application que le titulaire du compte voit sur l'écran de consentement Facebook. Si vous souhaitez que l'écran de consentement affiche **votre** marque à la place, vous pouvez enregistrer votre propre application Meta et faire passer tout le flux par celle-ci. Une fois configuré, cela s'applique à votre compte ; rien ne change dans les appels de connexion ci-dessus, hormis l'image de marque.

> **Ceci ne concerne que Instagram + Messenger.** Les connexions WhatsApp, WhatsApp Web, Telegram et LINE ne sont pas affectées par une application Meta personnalisée.

### Ce dont votre application a besoin en priorité

C'est l'étape qui prend du temps, et elle se déroule entièrement du côté de Meta :

1. **Une application** de type Business, avec les produits Messenger et Instagram ajoutés.
2. **Un accès avancé** (via l'examen de l'application Meta) pour : `pages_show_list`, `pages_messaging`, `pages_manage_metadata`, `pages_read_engagement`, `instagram_basic`, `instagram_manage_messages`. Sans accès avancé, seules les personnes ayant un rôle sur votre application peuvent finaliser la connexion — les connexions de vos clients échoueront. L'examen de l'application prend généralement quelques semaines et nécessite une vérification de l'entreprise.
3. **Une configuration de connexion Facebook pour les entreprises** créée au sein de votre application, accordant les mêmes autorisations. Son identifiant de configuration numérique est propre à chaque application, vous devez donc créer le vôtre.

Si votre application manque de l'une des autorisations requises, la connexion échoue au moment de l'appel avec une erreur claire indiquant ce qui manque (visible dans le sondage `/status` sous la forme `byo_app_missing_permissions`) — plutôt que de sembler fonctionner et d'échouer au premier message.

### Étape 1 - Enregistrez votre application

`PUT /account-config/meta-app`

| Champ | Requis | Description |
|---|---|---|
| `app_id` | Oui | Votre identifiant d'application Meta (Paramètres → Général). |
| `app_secret` | Oui | Votre clé secrète d'application Meta. Vérifiée auprès de Meta avant d'être stockée, puis chiffrée. Jamais renvoyée par aucun point de terminaison. |
| `config_id` | Oui | L'identifiant numérique de la configuration de connexion Facebook pour les entreprises au sein de votre application. |

Les trois sont requis pour le flux de connexion Facebook. Si vous n'exécutez que la voie de transfert de jeton de connexion Instagram décrite plus bas, vous pouvez les omettre entièrement.

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

**Réponse**

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

### Étape 2 - Configurez votre application pour communiquer avec nous

Dans le tableau de bord de votre application Meta :

1. **Webhooks** - pour les produits Instagram et Messenger, définissez l'URL de rappel (Callback URL) sur la valeur `webhook_urls` correspondante issue de la réponse, et le jeton de vérification (Verify token) sur `verify_token`. Abonnez-vous aux champs `messages`, `messaging_postbacks` et `comments`.
2. **URI de redirection OAuth valides** - ajoutez `https://api.youraiconnector.com/v1/auth-meta-callback-handler` afin que le flux de consentement puisse revenir.

`GET /account-config/meta-app` renvoie les mêmes informations de configuration à tout moment ; `DELETE /account-config/meta-app` supprime l'application (les futures connexions reviendront à l'application de la plateforme — supprimez également l'abonnement au webhook dans votre application).

### Étape 3 - Connectez-vous comme d'habitude

Rien d'autre ne change. `POST /channels/meta/connect` (ainsi que la page `connect_url` hébergée) utilise automatiquement votre application pour votre compte ; le `uses_byo_meta_app: true` de la réponse confirme quelle application l'écran de consentement affichera. L'envoi de messages, la sélection de pages et les déconnexions fonctionnent de manière identique.

## Apportez votre propre application de connexion Instagram (push de jeton)

La section ci-dessus couvre le flux de connexion Facebook, où le compte se connecte via une page Facebook. Meta propose également l'**API Instagram avec connexion Instagram** (connexion professionnelle pour Instagram) : le titulaire du compte s'authentifie sur Instagram lui-même, sans compte ni page Facebook impliqués.

Si votre plateforme utilise déjà sa propre application Meta avec ce produit, vous n'avez besoin d'aucun flux OAuth de notre côté. Vos clients autorisent **votre** application, et vous nous envoyez le justificatif final par compte :

1. Vous enregistrez les identifiants de votre application Instagram une seule fois (afin que nous puissions vérifier vos webhooks).
2. Pour chaque compte, vous envoyez l'ID du compte professionnel Instagram + le jeton utilisateur Instagram de longue durée obtenu par votre application.
3. Vous pointez le webhook de messagerie Instagram de votre application vers nous. Les événements pour les comptes que vous n'avez jamais envoyés sont reconnus et ignorés.
4. Vous gérez le cycle de vie du jeton : actualisez les jetons dans votre propre système et envoyez chaque jeton actualisé avec le même appel. Nous n'actualisons jamais un jeton envoyé.

### Ce dont votre application a besoin en priorité

- Le produit **Instagram** (« Configuration de l'API avec connexion Instagram ») ajouté à votre application Meta. Ce produit possède sa **propre paire d'ID d'application et de clé secrète d'application**, distincte de l'ID/clé secrète de l'application Facebook — vous les trouverez dans le panneau de configuration du produit.
- **Accès avancé** (via l'examen de l'application Meta) pour `instagram_business_basic` et `instagram_business_manage_messages` (ajoutez `instagram_business_manage_comments` si vous utilisez des automatisations de commentaires). Sans cela, seules les personnes ayant un rôle sur votre application peuvent l'autoriser.

### Étape 1 - Enregistrer les identifiants de votre application Instagram

Même point de terminaison que ci-dessus — envoyez la paire Instagram à `PUT /account-config/meta-app`. Les champs Facebook ne sont pas nécessaires pour cette voie : envoyez la paire seule si vous n'utilisez que la connexion Instagram, ou avec les champs Facebook si vous utilisez les deux. Une sauvegarde décrit toujours l'ensemble du paramètre, donc tout ensemble que vous omettez est supprimé.

| Champ | Requis | Description |
|---|---|---|
| `instagram_app_id` | Ensemble | L'ID d'application numérique du produit Instagram (pas l'ID d'application Facebook). |
| `instagram_app_secret` | Ensemble | La clé secrète d'application du produit Instagram. Chiffrée au repos, jamais renvoyée. |

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

**Réponse** — contient l'URL du webhook de connexion Instagram (les URL `instagram` et `messenger` n'apparaissent que lorsque les champs Facebook sont également stockés) :

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

Dans le panneau **Webhooks** de votre application pour le produit Instagram, définissez l'URL de rappel sur `webhook_urls.instagram_login`, le jeton de vérification sur `verify_token`, et abonnez-vous aux champs `messages` et `comments`.

### Étape 2 - Envoyer un jeton par compte

`PUT /channels/instagram-login/token`

Fonctionne avec `sub_account_id` comme n'importe quelle autre route, afin qu'une clé d'agence puisse provisionner l'ensemble de son parc.

| Champ | Requis | Description |
|---|---|---|
| `ig_user_id` | Oui | L'**ID du compte professionnel Instagram** — le champ `user_id` provenant de `GET https://graph.instagram.com/v21.0/me?fields=user_id,username`. Il s'agit du même ID que celui transmis par les webhooks Instagram en tant que `entry.id`. ⚠️ Ce n'est **pas** le champ `id` provenant de `/me` — celui-ci est limité à l'application et diffère selon l'application Meta. L'envoi de l'ID limité à l'application renvoie une erreur `400` indiquant l'erreur. |
| `access_token` | Oui | Le jeton utilisateur Instagram de longue durée que votre application a obtenu pour ce compte. Validé en direct auprès d'Instagram avant d'être stocké : le jeton doit fonctionner et appartenir à `ig_user_id`. |
| `expires_at` | Non | Expiration ISO-8601 du jeton. Alternativement, envoyez `expires_in` (secondes). Par défaut à 60 jours. |
| `username` | Non | Le @handle du compte ; nous le lisons de toute façon depuis 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"
  }'
```

**Réponse**

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

Dans le cadre de l'envoi, nous abonnons votre application aux webhooks de ce compte (`subscribed_apps` avec le jeton envoyé), afin que les messages commencent à circuler sans aucun appel supplémentaire de votre côté.

**Actualisation** - envoyez le jeton actualisé vers le même point de terminaison avec le même `ig_user_id` ; cela met à jour le jeton stocké et sa date d'expiration sur place.

**Conflits** - un compte Instagram ne peut jamais être actif sur deux connexions. Si le compte est déjà connecté ailleurs, ou sur ce même compte via le flux de Page Facebook, l'envoi renvoie un `409` vous indiquant quelle connexion déconnecter en premier. Une connexion via le flux Facebook n'est jamais remplacée automatiquement, car elle peut également servir à Messenger.

### Étape 3 - Déconnecter lorsqu'un client part

`DELETE /channels/instagram-login/token` (même authentification et `sub_account_id`) désabonne les webhooks au mieux et supprime les identifiants stockés. Cela réussit toujours, même lorsque le jeton a déjà expiré — et une fois les identifiants supprimés, les événements de webhook de ce compte sont ignorés.

---

## Conseils pour créer un wrapper fiable

- **Interrogez avec modération.** Quelques secondes suffisent. Arrêtez-vous une fois que vous atteignez un état terminal (`connected` / `ONLINE`, ou un statut d'échec), et définissez un délai d'expiration global raisonnable pour la boucle (les étapes du navigateur/QR expirent, voir chaque `expires_at`).
- **Encodez les numéros de téléphone en URL dans le chemin.** Le `+` initial doit être envoyé sous la forme `%2B`. Les points de terminaison récupèrent également les chiffres bruts, mais l'encodage est l'option la plus sûre.
- **N'attendez jamais de secrets en retour.** Les jetons d'accès, les secrets de canal et les jetons de page sont acceptés ou stockés mais ne sont jamais renvoyés dans aucune réponse.
- **Gérez le contrôle d'authentification.** Un `403` signifie que l'accès à l'API n'est pas inclus dans le forfait, ou que le canal que vous connectez n'est pas inclus dans le forfait du compte. Voir [Accès API](../integrations/api-access.md).
- **Respectez la limite de débit.** Les requêtes authentifiées sont limitées à 300 par minute ; un `429` signifie qu'il faut ralentir et réessayer. Voir [Authentification](authentication.md).

## Étapes suivantes

- [Authentification](authentication.md) - les quatre formes d'authentification acceptées et le format d'erreur.
- [Accès à l'API](../integrations/api-access.md) - génération et gestion de votre clé API.
