
# Channel Connection API

Denne guide viser dig, hvordan du forbinder beskedkanaler til en konto ved hjælp af API'et. Den er skrevet til en udvikler, der bygger en integration eller wrapper, så den fokuserer på de præcise anmodninger, rækkefølgen de skal foretages i, og de svar, du får tilbage.

Der er ét mønster, du skal forstå på forhånd, fordi det gælder for næsten alle kanaler her.

## Forbind-og-pol-mønsteret

De fleste kanaler kan ikke forbindes med et enkelt API-kald. At forbinde WhatsApp, Instagram eller Messenger betyder, at kontohaveren skal logge ind på sin egen udbyderkonto og godkende adgang. Der er **ingen headless (fuldt automatiseret) vej** til denne godkendelse - en rigtig person skal åbne en URL i en browser eller scanne en QR-kode med sin telefon.

Så flowet er altid:

1. **Start forbindelsen** med en `POST`. Svaret giver dig enten en URL, der skal åbnes, eller en QR-kode, der skal vises.
2. **Giv dette videre til slutbrugeren** - åbn URL'en i deres browser, eller vis QR-koden på skærmen, så de kan scanne den.
3. **Pol status-endpointet** med `GET` med korte intervaller (hvert par sekunder), indtil status når en forbundet tilstand.

Din integrations opgave er at drive dette loop: vis URL'en eller QR-koden, og pol derefter, indtil det er færdigt. Planlæg din brugerflade omkring pollingen - en spinner med en besked som "venter på, at du bliver færdig i din browser" fungerer godt.

::: note
**Bemærk:** Før du starter, skal du sikre dig, at API-adgang er aktiveret på planen, og at du har en API-nøgle. Se [API-adgang](../integrations/api-access.md) for at lære, hvordan du genererer en. Alle anmodninger herunder bruger basis-URL'en `https://api.youraiconnector.com/v1`, og du skal godkende hver anmodning. Se [Godkendelse](authentication.md) for de fire accepterede former - eksemplerne her bruger `X-API-Key`-headeren, hvor ét cURL-eksempel pr. side viser den simplere `?apiKey=`-forespørgselsform.
:::


---

## Instagram + Messenger (Meta)

Instagram og Messenger forbindes sammen i ét flow, fordi de begge kører på en Facebook-side. Kontohaveren autoriserer via Facebook, du henter listen over sider, de administrerer, og du vælger, hvilken side der skal forbindes.

### Trin 1 - Start Instagram + Messenger-forbindelsen

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

Dette returnerer en samtykke-URL. Ingen legitimationsoplysninger sendes i denne anmodning - forbindelsen autoriseres udelukkende i browseren.

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

**Svar**

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

Åbn `oauth_url` i slutbrugerens browser, så de kan logge ind på Facebook og godkende adgang. Forbindelsesforsøget udløber ved `expires_at` (ca. 30 minutter) - hvis det udløber, skal du starte forfra. Behandl `state_token` som en kortlivet hemmelighed og log den ikke.

### Den nemmeste løsning for Instagram + Messenger: overdrag `connect_url`

Svaret indeholder også en færdiglavet `connect_url`: en hostet side, der kører hele flowet for kontohaveren. De åbner den, logger ind på Facebook, og når de har mere end én side, viser den listen og lader dem vælge, hvilken der skal forbindes - derefter rapporterer den selv succes. Giv dette link til kontohaveren i stedet for selv at åbne `oauth_url`, bygge en sidevælger og polle. Linket virker i cirka 30 minutter (`connect_url_expires_at`); hvis det udløber, skal du starte en ny forbindelse. De manuelle trin nedenfor er til integrationer, der selv ønsker at styre flowet og rendere sidevælgeren.

### Trin 2 - Forespørg status, indtil siderne er indlæst

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

Når brugeren har afsluttet Facebook-login, skal du forespørge dette slutpunkt med få sekunders mellemrum. Feltet `status` gennemgår disse trin:

| `status` | Betydning |
|---|---|
| `pending` | Samtykke er endnu ikke givet. Fortsæt med at vente. |
| `token_received` | Autoriseret, men listen over sider indlæses stadig. |
| `pages_loaded` | Sider er tilgængelige - gå videre til trin 3. |
| `connected` | En side er blevet valgt, og kanalen er aktiv. |

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

**Svar (når siderne er indlæst)**

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

### Trin 3 - Vis siderne (valgfrit)

Hvis du hellere vil hente sidelisten separat (f.eks. for at vise en vælger), skal du bruge:

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

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

Det returnerer det samme `pages`-array som status-slutpunktet. (`status`-slutpunktet indeholder allerede siderne, så dette kald er blot en bekvemmelighed.)

### Trin 4 - Vælg siden, der skal forbindes

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

Send `page_id` for den side, brugeren valgte. Instagram-kontoen, der er knyttet til den side, forbindes automatisk; du behøver kun `instagram`-objektet, hvis du vil tilsidesætte, hvilken Instagram-konto der skal bruges.

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

**Svar**

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

Kanalen er nu forbundet. En opfølgende `GET /channels/meta/status` vil rapportere `status: "connected"`.

### List den forbundne sides opslag

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

Returnerer de seneste opslag fra den side, du har forbundet - Instagram-medier eller Facebook-opslag. Dette er, hvad du gengiver en vælger fra, når du opsætter et indgangspunkt, der reagerer på kommentarer til ét specifikt opslag.

| Forespørgselsparameter | Påkrævet | Beskrivelse |
|---|---|---|
| `platform` | Ja | `instagram` eller `facebook`. Alt andet returnerer en `400`. |
| `limit` | Nej | Hvor mange opslag der skal returneres, `1`-`50`. Standard er `25`. |
| `after` | Nej | Markør for den næste side - send `nextCursor`-værdien fra det forrige svar. |

**cURL**

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

**Svar**

```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` er Instagrams egen etiket (`REELS`, `FEED`, `STORY` eller formatet - `IMAGE`, `VIDEO`, `CAROUSEL_ALBUM`); for Facebook er det altid `POST`. `nextCursor` er `null` på den sidste side.

Hvis intet kan listes, returnerer kaldet stadig `200` med `connected: false` og et tomt `posts`-array, plus en `reason`, der fortæller dig hvorfor:

| `reason` | Hvad du skal gøre |
|---|---|
| _(fraværende)_ | Ingen side er forbundet endnu - kør forbindelsesflowet først. |
| `no_instagram_account` | En Facebook-side er forbundet, men ingen Instagram-virksomhedskonto er knyttet til den. Facebook-opslag listes stadig fint. |
| `token_expired` | Den gemte sidelegitimationsoplysning virker ikke længere - forbind kanalen igen. |

### Afbryd Instagram + Messenger

```
DELETE /channels/meta
```

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

**Svar**

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

Dette stopper indgående routing for både Instagram og Messenger. Det er idempotent - kald af dette, når intet er forbundet, vil stadig lykkes.

---

## WhatsApp Business

Dette forbinder et officielt WhatsApp Business-nummer. Nummeret skal allerede eksistere på kontoen, før du kalder connect. Ligesom hos Meta godkender kontohaveren i sin browser, hvorefter du poller, indtil nummeret rapporterer `ONLINE`.

### Trin 1 - Start WhatsApp Business-forbindelsen

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

| Felt | Påkrævet | Beskrivelse |
|---|---|---|
| `phone_number` | Ja | Nummeret, der skal forbindes, i E.164-format (f.eks. `+14155551234`). |
| `only_waba_sharing` | Nej | Begræns godkendelsen til deling af en eksisterende WhatsApp Business-konto, og spring opsætning af ny afsender over. Standard er `false`. |
| `retry` | Nej | Kør godkendelse igen for et nummer, hvis tidligere forsøg ikke blev fuldført. Standard er `false`. |
| `business_name` | Nej | Kosmetisk overstyring af virksomhedsnavnet, der kun vises på samtykkeskærmen (maks. 256 tegn). Gemmes ikke. |
| `description` | Nej | Kosmetisk overstyring af virksomhedsbeskrivelsen, der kun vises på samtykkeskærmen (maks. 256 tegn). Gemmes ikke. |

**Svar**

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

Åbn `oauth_url` i kontohaverens browser for at godkende. Når de har godkendt, fuldføres registreringen i baggrunden.

### Trin 2 - Pol status, indtil den er ONLINE

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

Pol dette, indtil `status` er `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".
```

**Svar**

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

Feltet `status` kan være:

| `status` | Betydning |
|---|---|
| `PENDING` | Godkendt, godkendelse er stadig i gang. Fortsæt med at polle. |
| `ONLINE` | Forbundet og klar til at sende. |
| `RATE_LIMITED` | For mange forsøg - vent før du prøver igen. |
| `REGISTRATION_FAILED` | Opsætningen kunne ikke fuldføres. |
| `DELETED` | Registreringen eksisterer ikke længere. |

`live: true` betyder, at status blev tjekket mod udbyderen i realtid; `false` betyder, at den kom fra den seneste cachede tilstand.

### Afbryd et WhatsApp Business-nummer

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

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

**Svar**

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

Selve nummeret forbliver på kontoen, så du kan forbinde det igen senere.

---

## WhatsApp Web

WhatsApp Web linker et almindeligt WhatsApp-nummer ved at scanne en QR-kode, præcis ligesom når man linker en enhed i WhatsApp-appen. Flowet er: start sessionen, hent QR-koden og vis den, og poll derefter indtil status er `connected`.

### Trin 1 - Start en WhatsApp Web-parringssession

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

| Felt | Påkrævet | Beskrivelse |
|---|---|---|
| `phone_number` | Ja | Det WhatsApp-nummer, der skal forbindes, i E.164-format. |
| `proxy_country` | Nej | ISO 3166-1 alpha-2 landekode for routing-regionen. Registreres automatisk fra nummeret, hvis det udelades. |
| `force_new` | Nej | Slet enhver eksisterende session og start en ny parring. Standard er `false`. |
| `import_contacts` | Nej | Importér enhedens eksisterende kontakter ved første forbindelse. Standard er `false`. |
| `pause_ai_for_imported_contacts` | Nej | Ved import af kontakter, hold automatiske svar sat på pause for dem. Standard er `true`. |
| `import_existing_chats` | Nej | Importér eksisterende chathistorik (kræver `import_contacts: true`). Standard er `false`. |

**Svar**

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

### Den nemmeste løsning for WhatsApp Web: overdrag `connect_url`

Svaret indeholder en færdiglavet `connect_url`: en hostet side, der viser QR-koden, opdaterer den automatisk, mens den roterer, og skifter til en succesmeddelelse, så snart nummeret er linket. Giv blot dette link til kontohaveren (åbn det i en browser, send det til dem, eller vis det som en QR-kode/knap) og få dem til at scanne det med WhatsApp - du behøver ikke selv at hente QR-koden eller foretage polling. Linket virker i cirka 30 minutter (`connect_url_expires_at`); hvis det udløber, før de er færdige, skal du starte en ny forbindelse for at få et nyt.

Dette er den anbefalede fremgangsmåde, når en person kan åbne et link. De manuelle trin herunder (hent selv QR-koden, poll status) er til integrationer, der ønsker at rendere QR-koden inde i deres egen grænseflade i stedet.

Svaret giver dig også den præcise `poll_qr_path` og `poll_status_path`, som du skal bruge, så du ikke selv behøver at bygge dem.

### Trin 2 - Hent QR-koden og vis den

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

**Svar**

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

Gengiv QR-koden, så brugeren kan scanne den med sin telefon (WhatsApp > Tilknyttede enheder > Tilknyt en enhed):

- `qr_data_url` er et billede, der er klar til brug - indsæt det direkte i et `<img src>`.
- `qr_code` er den rå payload, hvis du hellere selv vil generere billedet.

QR-koden har en kort levetid. Hvis du kalder dette lige efter at have startet sessionen, kan du modtage en `404` med "QR code not available yet" - vent blot et øjeblik og prøv igen. Hvis du modtager en `410` ("QR code expired"), skal du starte forbindelsen forfra for at få en ny kode.

### Trin 3 - Poll status indtil der er forbindelse

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

**Svar**

```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` | Betydning |
|---|---|
| `not_initialized` | Ingen session endnu (terminal fejl). |
| `qr_pending` | Venter på at QR-koden scannes. |
| `connecting` | Scannet, afslutter opsætning. |
| `connected` / `open` | Linket og aktiv - dette er en succes. |
| `disconnected` | Session afsluttet (terminal fejl). |

### Afbryd en WhatsApp Web-session

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

**Svar**

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

Dette fjerner linket til enheden og sletter forbindelsen. Det rydder altid op i den lokale tilstand, så det er idempotent, selv hvis den underliggende session allerede var væk.

---

## Telegram

> **Tilgængelighed:** Telegram opretter forbindelse ligesom enhver anden kanal og er åben for alle konti — du behøver ikke at få den aktiveret. Telegram-slutpunkterne herunder kan stadig returnere `403`, hvis Telegram ikke er inkluderet i kontoens abonnement, i hvilket tilfælde fejlen lyder `"This channel is not included in your current plan. Upgrade to unlock it."`.

Telegram forbinder en personlig konto via telefonnummer plus en engangskode (og en to-faktor-adgangskode, hvis kontoen har en sådan). Flowet er: start sessionen, indsend koden, indsend eventuelt adgangskoden, og bekræft derefter via status.

### Trin 1 - Start en Telegram-forbindelsessession

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

| Felt | Påkrævet | Beskrivelse |
|---|---|---|
| `phone_number` | Ja | Kontoens telefonnummer, der skal forbindes, i E.164-format. |
| `mode` | Nej | `code` (standard) sender en engangskode til kontoen; `qr` returnerer et login-token og en QR-URL, der skal vises. |
| `proxy_country` | Nej | ISO 3166-1 alpha-2 landekode for den udgående netværksrute. |
| `force_new` | Nej | Når `true`, kasseres enhver eksisterende session, og der startes forfra. |

**Svar**

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

I `code`-tilstand modtager kontoen en login-kode i Telegram, og `status` er `code_required`. (I `qr`-tilstand inkluderer svaret også `login_token` og `qr_url`, der skal vises til scanning, og `status` er `qr_required`.)

### Den nemmeste løsning for Telegram: overdrag `connect_url`

Svaret indeholder en færdiglavet `connect_url`: en hostet side, der selv fuldfører forbindelsen. I `code`-tilstand indtaster kontohaveren login-koden - og en to-trins bekræftelsesadgangskode, hvis deres konto har en. I `qr`-tilstand viser siden en QR-kode, der opdaterer sig selv, så de kan scanne den fra Telegram-appen. Uanset hvad rapporterer den selv succes, så du kan blot give dette link til kontohaveren i stedet for at bygge din egen brugerflade og polle. Linket virker i cirka 30 minutter (`connect_url_expires_at`); hvis det udløber, skal du starte en ny forbindelse for at få et nyt.

De manuelle trin nedenfor (indsaml koden selv, indsend den, pol status; eller render `qr_url` og pol) er til integrationer, der selv ønsker at rendere brugerfladen.

### Trin 2 - Indsend login-koden

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

**Svar**

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

Hvis `status` er `connected`, er du færdig. Hvis kontoen har to-faktor aktiveret, vil `status` være `password_required` i stedet - gå til trin 3.

### Trin 3 - Indsend to-faktor-adgangskoden (kun hvis nødvendigt)

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

Kald kun dette, når trin 2 returnerede `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()
```

**Svar**

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

### Tjek Telegram-status

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

**Svar**

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

`status` kan være `connected`, `code_required`, `password_required`, `initializing`, `disconnected`, `not_initialized` eller `error`.

### Afbryd Telegram

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

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

**Svar**

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

Idempotent - gentagne kald lykkes.

---

## Instagram (personlig konto)

> Beta med begrænset tilgængelighed, aktiveret pr. konto. Dette forbinder en personlig Instagram-konto ved at logge ind med brugernavn og adgangskode (ikke den officielle Business API). Hvis kontoen ikke er aktiveret til betaen, returnerer forbindelsesopkaldet en tilladelsesfejl.

Da dette kræver kontohaverens eget Instagram-login, er den nemmeste vej at give dem den hostede `connect_url` og lade dem indtaste deres legitimationsoplysninger der - din integration håndterer aldrig adgangskoden.

### Trin 1 - Start en Instagram (personlig) forbindelse

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

Send Instagram `username` og `password`.

**Svar**

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

Hvis kontoen har to-faktor-godkendelse, eller Instagram præsenterer et kontrolpunkt, kommer `status` tilbage som `two_factor_required` eller `challenge_required` - indsend koden til `/connect/{id}/verify-2fa` eller `/connect/{id}/verify-challenge` nedenfor, og poll derefter `/connect/{id}/status` indtil `connected`. `{id}` er det normaliserede Instagram-brugernavn, der returneres som `account_id`/`username` i svaret ovenfor - brug det ved hvert trin nedenfor.

### Trin 2 - Indsend to-faktor-koden (hvis der bliver spurgt om det)

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

Kald kun dette, når trin 1 (eller trin 3) returnerede `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" }'
```

**Svar**

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

`status` kan komme tilbage som `connected` (færdig), `two_factor_required` (forkert kode, prøv igen) eller `challenge_required` (Instagram ønsker også en kontrolpunktskode - gå til trin 3).

### Trin 3 - Indsend kontrolpunktsbekræftelseskoden (hvis der bliver spurgt om det)

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

Kald kun dette, når et tidligere trin returnerede `challenge_required`. Samme anmodnings- og svarform som trin 2 ovenfor.

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

### Tjek Instagram (personlig) status

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

Poll dette indtil `status` er `connected`, eller indtil det rapporterer en terminal fejl.

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

**Svar**

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

`status` kan være `connected`, `two_factor_required`, `challenge_required`, `initializing`, `disconnected`, `not_initialized` eller `error`. `live: true` betyder, at dette blev læst live fra forbindelses-worker'en i stedet for en cachelagret værdi.

### Den nemmeste løsning for Instagram (personlig): overdrag `connect_url`

Svaret indeholder et `connect_url`: en hostet side, hvor kontohaveren indtaster sit Instagram-brugernavn og sin adgangskode (samt en 2FA- eller kontrolpunktkode, hvis Instagram beder om det), og som selv rapporterer succes. Legitimationsoplysningerne går direkte til Instagram og gemmes ikke. Giv dette link til kontohaveren i stedet for selv at indsamle deres adgangskode i din egen brugerflade. Linket virker i cirka 30 minutter (`connect_url_expires_at`).

### Afbryd Instagram (personlig)

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

Idempotent - gentagne kald lykkes.

### Synkroniser følgere

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

Udløser manuelt en synkronisering af følgere for en forbundet konto - det samme job, der kører automatisk i baggrunden, er her gjort tilgængeligt som en "Opdater følgere"-handling efter behov. Den henter kontoens aktuelle liste over følgere, registrerer nye personer og (når en Live-kampagne har aktiveret følger-outreach) sender nye følgere en indledende direkte besked, op til en daglig grænse.

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

**Svar**

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

> Disse fem felter er det eneste sted på denne side, der returnerer `camelCase` i stedet for `snake_case` - det er sådan, dette endpoint er konfigureret i dag, ikke en tastefejl. `isBaselineSeed: true` betyder, at dette var den allerførste synkronisering efter tilslutning, som kun registrerer den oprindelige liste over følgere og aldrig sender outreach-beskeder (så `dmsSent` er altid `0` ved den kørsel).

Det allerførste kald for en konto kan tage et stykke tid (gennemgang af hele følgerlisten); senere kald er hurtigere, da kun nye følgere bliver sammenlignet. `404` betyder, at kontoen ikke er forbundet; `412` betyder, at forbindelsen endnu ikke er færdig med at initialisere - vent og prøv igen.

---

## LINE

LINE er den enkleste kanal at forbinde, da der ikke er nogen browser-omdirigering eller polling. Kunden opretter en Messaging API-kanal i LINE Developers-konsollen, kopierer to værdier, og du indsender dem i et enkelt kald. Du giver dem derefter en webhook-URL, som de skal indsætte i konsollen.

### Trin 1 - Forbind med kanalens legitimationsoplysninger

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

| Felt | Påkrævet | Beskrivelse |
|---|---|---|
| `channel_access_token` | Ja | Den officielle kontos langlivede Messaging API-kanaladgangstoken. Bruges til at sende og modtage beskeder. |
| `channel_secret` | Ja | Messaging API-kanalsekretet, der bruges til at verificere indgående begivenhedssignaturer. |
| `channel_id` | Nej | Det numeriske kanal-id. Kun til informationsbrug. |

**Svar**

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

To felter er vigtige for det, du gør derefter:

- **`webhook_url`** - kunden skal indsætte dette i feltet **Webhook URL** for deres LINE-kanal i LINE Developers-konsollen (og aktivere "Use webhook"). Før de gør det, ankommer ingen indgående beskeder. Vis dette tydeligt til dem.
- **`chat_mode_ok`** - når `false`, er den officielle konto i "chat"-tilstand og vil ikke modtage eller sende beskeder, før den skiftes til "bot"-tilstand i LINE Official Account Manager. Gør din onboarding afhængig af dette flag og bed kunden om at skifte tilstand.

> `channel_access_token` og `channel_secret` returneres aldrig af noget endpoint. Gem dem hos dig selv, hvis du får brug for dem igen; ellers skal de indsættes igen fra LINE-konsollen.

Det `bot_user_id`, der returneres her, er forbindelsesidentifikatoren, som du bruger i status-, bekræftelses- og afbrydelsesopkaldene nedenfor.

### Trin 2 - Bekræft igen efter webhook-opsætning

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

Når kunden er færdig med at konfigurere webhook-URL'en og skifter til bot-tilstand, skal du kalde denne for at genvalidere det gemte token og opdatere den cachelagrede chattilstand.

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

**Svar**

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

Hvis `token_valid` er `false`, godkender det gemte adgangstoken ikke længere - få kunden til at udstede det på ny i konsollen og kald `POST /channels/line` igen med det nye token.

### Tjek LINE-status

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

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

**Svar**

```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 har intet live statusfeed, så `live` er altid `false` her - værdierne afspejler tilstanden, der blev registreret ved oprettelse af forbindelse (eller seneste verificering).

### Afbryd LINE

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

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

**Svar**

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

---

## Viber

Viber forbindes på samme måde som LINE - indsæt bottens godkendelsestoken fra Viber Admin Panel i ét kald - med én forskel, der er værd at vide: Tilslutning REGISTRERER også vores webhook på din bot med det samme, så der er ikke noget separat konsoltrin bagefter. Det betyder også, at et tilslutningsforsøg kan fejle, hvis vores ingress ikke kan besvare Vibers synkrone webhook-tjek, ikke kun hvis selve tokenet er forkert.

### Trin 1 - Forbind med bottens godkendelsestoken

```
POST /channels/viber
```

| Felt | Påkrævet | Beskrivelse |
|---|---|---|
| `auth_token` | Ja | Bottens godkendelsestoken fra Viber Admin Panel (My Bot Settings). |

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

**Svar**

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

Godkendelsestokenet bliver aldrig returneret af noget endpoint - gem det hos dig selv, hvis du får brug for at indsætte det igen. `bot_id` er forbindelsesidentifikatoren, der bruges af status-, bekræftelses- og afbrydelseskaldene nedenfor.

### Tjek Viber-status

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

Rapporterer den gemte forbindelsestilstand. Tilføj `?live=true` for også at gen-tjekke botten mod Viber og opdatere den cachede webhook-registrering - nyttigt før man antager, at en tavs bot faktisk er gået i stykker.

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

**Svar**

```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` betyder, at bottens webhook ikke længere peger på os - indgående beskeder er gået tabt. Dette betyder normalt, at et andet værktøj har forbundet den samme bot efterfølgende (Vibers webhook-registrering følger princippet om "sidste skrivning vinder"). Løs det med genbekræftelseskaldet nedenfor, der er ingen grund til at bede kunden om at indsætte deres token igen. `live` er `false`, når svaret er den sidst cachede tilstand frem for et frisk tjek mod Viber.

### Genregistrer webhooken

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

Reparationshandlingen for `webhook_ok: false` - genregistrerer vores webhook på botten ved hjælp af det allerede gemte godkendelsestoken.

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

**Svar**

```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` betyder, at det gemte token ikke længere virker - forbind igen med `POST /channels/viber` og et nyt token.

### Afbryd Viber

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

Afregistrerer vores webhook hos Viber (best-effort) og fjerner forbindelsen.

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

**Svar**

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

---

## TikTok

> **Tilgængelighed:** Begrænset beta, aktiveret pr. konto. Forbindelse til TikTok returnerer en tilladelsesfejl, indtil kontoen er aktiveret til det.

TikTok Business Messaging er en fuld OAuth-kanal ligesom Meta, men enklere hvad angår polling: Der er ikke noget dedikeret status-polling-trin, der skal bygges op, da den forbundne konto dukker op af sig selv, når TikTok omdirigerer tilbage, og forbindelsen er skrevet. Status-endpointet nedenfor findes til bekræftelse af tilstand efter behov (supportværktøjer, sundhedstjek), ikke som noget, du behøver at køre i en løkke under forbindelsen.

### Trin 1 - Start TikTok-forbindelsen

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

Kræver ingen legitimationsoplysninger - kontohaveren godkender det hele i sin browser.

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

**Svar**

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

Åbn `oauth_url` i kontohaverens browser, så de kan logge ind på TikTok og godkende adgang. Tilstanden udløber ved `expires_at` (ca. 30 minutter) - hvis den udløber, skal du starte forfra. Der er ingen `connect_url` hosted-page genvej til TikTok; at åbne `oauth_url` selv er den eneste vej.

### Tjek TikTok-status

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

`openId` er TikTok Business-kontoens open_id, som kendes, når OAuth-callbacket er kørt.

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

**Svar**

```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 har ikke noget billigt live-sundhedstjek, så `live` er altid `false` her - felterne afspejler, hvad connect (eller den sidste token-opdatering) skrev. `status: "reauth_required"` med `status_reason` sat betyder, at kontoen skal igennem connect igen; TikTok-tokens opdateres automatisk med en årlig rotation, og dette er, hvad der vises, hvis den rotation nogensinde fejler.

### Afbryd TikTok

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

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

**Svar**

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

---

## GoHighLevel

GoHighLevel (GHL) er en CRM-integration, ikke en beskedkanal - at forbinde den bruger ikke en kanalplads i planen, fordi den benytter kontoens eksisterende kanaler i stedet for at tilføje en ny. Det er også den eneste integration på denne side, der kan have **mere end én forbindelse ad gangen**: hver GHL-underkonto ("lokation"), som kunden installerer appen på, får sin egen post.

### Trin 1 - Start GHL-forbindelsen

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

| Felt | Påkrævet | Beskrivelse |
|---|---|---|
| `brand` | Nej | Hvilken GHL-markedsplads-fortegnelse der skal godkendes igennem. Standard er standardfortegnelsen - kun relevant, hvis din implementering har mere end én markedsplads-app konfigureret. |

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

**Svar**

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

Åbn `oauth_url` i kontohaverens browser, så de kan vælge en GHL-lokation og godkende adgang. Tilstanden udløber ved `expires_at` (ca. 30 minutter).

### List GHL-forbindelser

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

I modsætning til andre kanaler er dette ikke status for én enkelt forbindelse - den viser hver lokation, som kontoen har forbundet.

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

**Svar**

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

### Afbryd en GHL-lokation

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

Sletter forbindelsen her, hvilket stopper enhver synkronisering og trigger for den lokation. Dette afinstallerer ikke appen på GHL-siden - kunden fjerner den fra deres GHL-markedspladsinstallationer, hvis de også ønsker det.

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

**Svar**

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

---

## Telefonnumre (køb og frigiv)

I stedet for at forbinde et eksisterende nummer kan du købe et nyt WhatsApp-kompatibelt nummer direkte. Søg efter tilgængelige numre, køb et, og foretag derefter forespørgsler, indtil klargøringen er fuldført.

::: note
**Bemærk:** Numre købt her er WhatsApp-kompatible. WhatsApp-afsenderregistrering kører i baggrunden efter købet, så du skal polle status, indtil den når `ONLINE`, før du sender. Kreditter trækkes ved køb og refunderes **ikke**, når du frigiver nummeret.
:::


### Trin 1 - Søg efter tilgængelige numre

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

| Forespørgselsparameter | Påkrævet | Beskrivelse |
|---|---|---|
| `country_code` | Ja | ISO 3166-1 alpha-2 landekode, der skal søges i (f.eks. `US`, `GB`, `NL`). |
| `type` | Nej | Foretrukken nummerklasse, `local` eller `mobile`. Begge klasser kan stadig blive returneret. |

**Svar**

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

Hvert resultat viser engangsbeløbet `purchase_credits` og det tilbagevendende `monthly_credits`. Et platform-leveret nummer koster mindst 50 credits om måneden, stigende med operatørens egen månedlige pris, som opkræves ved køb og ved hver fornyelse. Angiv det `purchase_credits` / `monthly_credits`, som søgningen returnerer; beregn aldrig selv en pris. Den første søgning på en ny konto klargør nogle underliggende ressourcer, så den kan være lidt langsommere end senere søgninger.

### Trin 2 - Køb et nummer

```
POST /phone-numbers
```

Brug et `phone_number` fra søgeresultaterne.

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

| Felt | Påkrævet | Beskrivelse |
|---|---|---|
| `phone_number` | Ja | Et nummer returneret af søgningen efter tilgængelige numre, i E.164-format. |
| `country_code` | Ja | ISO 3166-1 alpha-2 landekode (f.eks. `US`). |
| `display_name` | Nej | Et brugervenligt navn. Som standard bruges telefonnummeret. |
| `category` | Nej | Valgfri kategorimærkat. |

**Svar**

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

Nummeret starter i tilstanden `PURCHASED`. WhatsApp-registreringen fortsætter derefter i baggrunden: `PURCHASED` -> `PENDING` -> `ONLINE`.

> Hvis købet mislykkes, fordi en virksomhedsadresse mangler, eller en anden påkrævet detalje ikke er angivet, modtager du en `400` med en beskrivende `error`. Konfigurer den manglende detalje og prøv igen.

### Trin 3 - Polling indtil ONLINE

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

Dette er det delte slutpunkt for telefonnummerstatus - det fungerer både til købte WhatsApp-numre og dine andre tilsluttede numre.

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

**Svar**

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

### Trin 4 - Frigiv et nummer

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

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

**Svar**

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

Hvad dette gør, afhænger af, hvis nummer det er.

For et nummer, der er **lejet gennem platformen**, er der tale om en reel frigivelse: WhatsApp-afsenderen afregistreres, nummeret leveres tilbage til udbyderen og fjernes fra kontoen, og der pålægges en 7-dages nedkølingsperiode, hvor nummeret ikke kan genkøbes af nogen, og der refunderes ingen kreditter.

For et nummer, hvor **kontoen medbragte sit eget** (sin egen Twilio-konto, sin egen Meta-app eller WhatsApp Business-konto, eller en Android SMS-gateway), fjerner det samme kald det blot fra kontoen. Intet frigives hos den opstrøms leverandør, og der skrives ingen nedkølingsperiode, så nummeret kan genforbindes med det samme. Dets WhatsApp-afsenderregistrering, hvis det havde en, overlever muligvis eller muligvis ikke: nedbrydningen forsøger at slette afsenderen ved hjælp af kontoens platformstyrede Twilio-legitimationsoplysninger. På en konto, der stadig er på den styrede opsætning, er disse legitimationsoplysninger gyldige, og afsenderen slettes, så genforbindelse betyder, at den skal registreres igen. På en konto, der er skiftet til sin egen Twilio, kan sletningen ikke godkendes, og afsenderen forbliver registreret på den konto – genforbindelse er derefter blot at gen-tilknytte den eksisterende afsender.

### Tilføj et nummer, du allerede ejer (BYO)

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

Springer søg-og-køb-flowet ovenfor helt over. Brug dette, når kontoen medbringer sit eget nummer (deres egen Twilio, deres egen Meta WhatsApp Business-konto eller en Android SMS-gateway) i stedet for at leje et gennem platformen. Dette registrerer kun nummeret - ingen kreditter debiteres, og intet klargøres hos en udbyder her. Nummeret forbliver inaktivt, indtil kontohaveren gennemfører WhatsApp OAuth for at registrere en afsender på det (det samme flow, som dashboardets "Bring your own number"-knap starter).

| Felt | Påkrævet | Beskrivelse |
|---|---|---|
| `phone_number` | Ja | Nummeret, der skal tilføjes, i E.164-format (f.eks. `+14155551234`). |
| `country_code` | Ja | ISO 3166-1 alpha-2 landekode (f.eks. `US`). |
| `display_name` | Nej | Et brugervenligt navn. Standard er telefonnummeret. |
| `category` | Nej | Valgfri kategorietiket. |

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

**Svar** (`201 Created`):

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

Et `phone_number`, der ikke er et rigtigt E.164-nummer (eller som ligner Metas WhatsApp-testnummer, som aldrig kan sende beskeder til rigtige kunder), returnerer `400`. Tilføjelse af et nummer, der allerede findes på kontoen - selv hvis det er stavet lidt anderledes, som Mexicos `+52` vs `+521`-former - returnerer `409` i stedet for at oprette en dublet-række.

### Indstil et nummer som primært

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

Skifter ét nummer til `is_active: true` og alle andre numre på kontoen til `is_active: false`, atomart - kontoen ender aldrig med to aktive numre, eller ingen, midt i en anmodning. `is_active` kan ikke indstilles via det generelle opdaterings-endpoint med vilje; dette dedikerede kald er den eneste måde at ændre, hvilket nummer der er primært.

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

**Svar**

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

`phone_number` her er det fulde nummerobjekt (samme form som `GET /phone-numbers` returnerer), ikke bare strengen. Et `phoneNumber`, der ikke er på kontoen, returnerer `404`.

### Fjern et nummers registrering (uden at frigive det)

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

En simpel sletning af nummerets registrering på denne konto - ingen frigivelse eller afregistrering hos udbyderen, og ingen 7-dages nedkølingsperiode som ved frigivelsestrinnet ovenfor. Brug dette til at rydde BYO-, WhatsApp Web-, Telegram- eller LINE-registreringer eller en forældet post uden at gennemgå det administrerede frigivelsesflow. I modsætning til en frigivelse er sletning af et nummer, der ikke er på kontoen, en `404`, ikke en lydløs succes.

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

**Svar**

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

---

## Ruter en kanal til en kampagne

Forbindelse af en kanal får beskeder **ind i** kontoen. Det afgør ikke, **hvilken AI-agent der besvarer dem**.

Routing håndteres af **indgangspunkter** (Entry Points) på en AI-agent, ikke af kampagner. Hver kanal har ét kanal-standardindgangspunkt, der navngiver den agent, som besvarer nye, ukendte kontakter på den kanal:

| Hvad du vil gøre | Kald |
|---|---|
| Peg en kanal mod den agent, der skal besvare den | `PUT /entry-points/channel-defaults` med body `{ "channel": "instagram", "agent_id": "AGENT_ID" }` |
| Tjek om indgangspunkternes hierarki er aktivt for kontoen | `GET /entry-points/routing-status`, som returnerer `{ "success": true, "cutover_enabled": true }`, når indgangspunkter bestemmer kontoens routing |
| Efterlad en kanal uden en agent til at besvare den | `DELETE /entry-points/channel-defaults?channel=instagram` |

Indtil en kanal har et indgangspunkt (Entry Point), gemmes en første besked fra en person, du aldrig har talt med, stadig, men intet henter den, og ingen assistent svarer. Dette er det trin, de fleste integrationer overser: Det er ikke nok i sig selv at forbinde Instagram og oprette en agent — du skal også pege kanalen mod agenten. Det fulde sæt af kald — inklusive én agent pr. WhatsApp-nummer, søgeord og kommentarregler — findes i [Entry Points API](entry-points.md).

`POST /channels/campaign` skriver stadig det ældre routing-kort for kampagner pr. kanal, dokumenteret nedenfor, men det kort konsulteres ikke længere til indgående routing på nogen konto; det bevares kun til rollback. Byg ikke løsninger baseret på det.

### Route en eller flere kanaler (ældre routing-kort for kampagner)

`POST /channels/campaign`

**Anmodningsfelter**

| Felt | Påkrævet | Beskrivelse |
|---|---|---|
| `campaign_id` | Ja | Den kampagne, der skal besvare nye kontakter på disse kanaler. Skal tilhøre kontoen. |
| `channels` | Ja | Et ikke-tomt array af kanaler, der skal rutes. Tilladt: `whatsapp`, `whatsapp_web`, `telegram`, `instagram`, `messenger`, `chat_widget`, `custom_channel`, `sms`, `email`. |

Ruteringspladsen og kampagnens `enabled_channels`-liste opdateres sammen i én atomar handling, så de aldrig kan komme ud af synkronisering. En kanal, der allerede er rutet til en anden kampagne, bliver blot omdirigeret til denne.

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

**Svar**

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

### Hvad skal være opfyldt, for at rutering rent faktisk aktiveres

På en konto, der stadig læser det ældre routing-kort for kampagner, lykkes routing som et API-kald, men tre ting på kampagnen afgør, om en reel indgående besked bliver besvaret. Tjek alle tre, når en routet kanal forbliver tavs.

| Krav | Hvad der ellers sker |
|---|---|
| `type` er `Incoming from Unknown Contacts` eller `Combined` | Anmodningen afvises med `400`. Udgående kampagner og søgeord-kampagner kan ikke have en routing-plads. |
| `status` er `Live` | Routingen gemmes, men opsamler aldrig noget. En `Draft`-kampagne er den mest almindelige årsag til "Jeg routede den, og der sker intet". |
| `ai_mode` er `true` | Kontakten oprettes, og beskeden gemmes, men assistenten svarer aldrig. |

Matchning af søgeord ligger nu på indgangspunkter — opret et indgangspunkt af typen `keyword` på den AI-agent, der skal svare.

### Én kampagne pr. kanal

Hver kanal har præcis én ældre routing-plads. Routing af en anden kampagne til den samme kanal ændrer lydløst pladsen og returnerer `200` — der er ingen konfliktfejl. Den forrige kampagne fortsætter med at håndtere de kontakter, den allerede har; den stopper bare med at modtage nye.

### Ryd en kanals routing

`DELETE /channels/campaign/{channel}`

Fjerner routingen for en enkelt kanal, uanset hvilken kampagne den i øjeblikket peger på, og fjerner kanalen fra den pågældende kampagnes `enabled_channels`. Nye ukendte kontakter på kanalen bliver ikke længere opfanget af nogen kampagne. Kontakter, der allerede er i kampagnen, fortsætter som før.

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

**Svar**

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

Den er idempotent: rydning af en kanal, der aldrig var routet, returnerer også `200` med `cleared: false` og `campaign_id: null`. Dette slutpunkt kræver funktionen **indgående kampagner** i planen; uden den får du en `403`.


---

## Brug din egen Meta-app (Instagram + Messenger)

Som standard kører Instagram + Messenger-forbindelsen gennem platformens Meta-app, så det er navnet på den app, som kontohaveren ser på Facebooks samtykkeskærm. Hvis du ønsker, at samtykkeskærmen skal vise **dit** brand i stedet, kan du registrere din egen Meta-app og dirigere hele flowet gennem den. Når den er konfigureret, gælder den for din konto – intet ændres i forbindelsesopkaldene ovenfor udover brandingen.

> **Dette dækker kun Instagram + Messenger.** WhatsApp, WhatsApp Web, Telegram og LINE-forbindelser påvirkes ikke af en brugerdefineret Meta-app.

### Hvad din app har brug for først

Dette er den del, der tager tid, og den foregår udelukkende på Metas side:

1. **En app** af typen Business, med Messenger- og Instagram-produkterne tilføjet.
2. **Avanceret adgang** (via Meta App Review) til: `pages_show_list`, `pages_messaging`, `pages_manage_metadata`, `pages_read_engagement`, `instagram_basic`, `instagram_manage_messages`. Uden avanceret adgang kan kun personer, der har en rolle i din app, fuldføre forbindelsen — dine klienters forbindelser vil fejle. App-gennemgang tager typisk et par uger og kræver virksomhedsverificering.
3. **En Facebook Login for Business-konfiguration** oprettet i din app, som giver de samme tilladelser. Dens numeriske konfigurations-ID er pr. app, så du skal oprette dit eget.

Hvis din app mangler nogen af de påkrævede tilladelser, fejler forbindelsen på forbindelsestidspunktet med en klar fejlmeddelelse, der angiver, hvad der mangler (synlig i `/status`-polling som `byo_app_missing_permissions`) — i stedet for at se ud til at virke og fejle ved den første besked.

### Trin 1 - Gem din app

`PUT /account-config/meta-app`

| Felt | Påkrævet | Beskrivelse |
|---|---|---|
| `app_id` | Ja | Dit Meta App ID (Indstillinger → Grundlæggende). |
| `app_secret` | Ja | Din Meta App Secret. Verificeres mod Meta, før den gemmes, og derefter krypteres. Returneres aldrig af noget slutpunkt. |
| `config_id` | Ja | Det numeriske ID for Facebook Login for Business-konfigurationen i din app. |

Alle tre er påkrævet til Facebook Login-flowet. Hvis du kun kører Instagram Login token-push-stien, der er beskrevet længere nede, kan du udelade dem helt.

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

**Svar**

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

### Trin 2 - Konfigurer din app til at kommunikere med os

I din Meta-apps dashboard:

1. **Webhooks** - for både Instagram- og Messenger-produkterne skal du indstille Callback URL til den matchende `webhook_urls`-værdi fra svaret og Verify token til `verify_token`. Abonner på felterne `messages`, `messaging_postbacks` og `comments`.
2. **Gyldige OAuth Redirect URI'er** - tilføj `https://api.youraiconnector.com/v1/auth-meta-callback-handler`, så samtykkeflowet kan vende tilbage.

`GET /account-config/meta-app` returnerer det samme opsætningsmateriale hver gang; `DELETE /account-config/meta-app` fjerner appen (fremtidige forbindelser vender tilbage til platformens app — husk også at fjerne webhook-abonnementet i din app).

### Trin 3 - Opret forbindelse som sædvanlig

Intet andet ændres. `POST /channels/meta/connect` (og den hostede `connect_url`-side) bruger automatisk din app til din konto; svarets `uses_byo_meta_app: true` bekræfter, hvilken app samtykkeskærmen vil vise. Beskedafsendelse, valg af side og afbrydelse af forbindelsen fungerer identisk.

## Brug din egen Instagram Login-app (token-push)

Afsnittet ovenfor dækker Facebook Login-flowet, hvor kontoen forbindes via en Facebook-side. Meta tilbyder også **Instagram API med Instagram Login** (Business Login til Instagram): kontohaveren godkender sig direkte på Instagram, uden at en Facebook-konto eller -side er involveret.

Hvis din platform allerede kører sin egen Meta-app med det produkt, behøver du slet ikke noget OAuth-flow fra vores side. Dine klienter godkender **din** app, og du sender os den færdige legitimation pr. konto:

1. Du gemmer din Instagram-apps legitimationsoplysninger én gang (så vi kan verificere dine webhooks).
2. Pr. konto sender du Instagram-virksomhedskontoens ID + det langlivede Instagram-brugertoken, som din app har indhentet.
3. Du peger din apps Instagram-besked-webhook mod os. Begivenheder for konti, du aldrig har sendt, bliver anerkendt og ignoreret.
4. Du ejer tokenets livscyklus: opdater tokens i dit eget system og send hvert opdateret token med det samme kald. Vi opdaterer aldrig et sendt token.

### Hvad din app har brug for først

- **Instagram**-produktet ("API setup with Instagram login") tilføjet til din Meta-app. Det produkt har sit **eget App ID og App Secret-par**, adskilt fra Facebook App ID/Secret — find dem i produktets opsætningspanel.
- **Advanced Access** (via Meta App Review) til `instagram_business_basic` og `instagram_business_manage_messages` (tilføj `instagram_business_manage_comments`, hvis du bruger kommentarautomatiseringer). Uden dette kan kun personer med en rolle i din app godkende den.

### Trin 1 - Gem dine Instagram-app-legitimationsoplysninger

Samme endpoint som ovenfor — send Instagram-parret til `PUT /account-config/meta-app`. Facebook-felterne er ikke nødvendige for denne sti: Send parret alene, hvis Instagram Login er alt, hvad du kører, eller sammen med Facebook-felterne, hvis du kører begge dele. En lagring beskriver altid hele indstillingen, så det sæt, du udelader, bliver fjernet.

| Felt | Påkrævet | Beskrivelse |
|---|---|---|
| `instagram_app_id` | Sammen | Instagram-produktets eget numeriske App ID (ikke Facebook App ID). |
| `instagram_app_secret` | Sammen | Instagram-produktets egen App Secret. Krypteret ved lagring, returneres aldrig. |

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

**Svar** — indeholder webhook-URL'en til Instagram-Login (URL'erne `instagram` og `messenger` vises kun, når Facebook-felterne også er gemt):

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

I din apps **Webhooks**-panel for Instagram-produktet skal du indstille Callback URL til `webhook_urls.instagram_login`, Verify token til `verify_token` og abonnere på felterne `messages` og `comments`.

### Trin 2 - Send et token pr. konto

`PUT /channels/instagram-login/token`

Fungerer med `sub_account_id` ligesom alle andre ruter, så en bureau-nøgle kan klargøre hele sin flåde.

| Felt | Påkrævet | Beskrivelse |
|---|---|---|
| `ig_user_id` | Ja | **Instagram-virksomhedskontoens ID** — feltet `user_id` fra `GET https://graph.instagram.com/v21.0/me?fields=user_id,username`. Dette er det samme ID, som Instagram-webhooks bærer som `entry.id`. ⚠️ Det er **ikke** feltet `id` fra `/me` — det er app-scopet og varierer pr. Meta-app. Hvis du sender det app-scopede ID, returneres en `400`, der navngiver fejlen. |
| `access_token` | Ja | Det langlivede Instagram-brugertoken, som din app har indhentet for den konto. Valideres live mod Instagram, før det gemmes: tokenet skal fungere og skal tilhøre `ig_user_id`. |
| `expires_at` | Nej | ISO-8601 udløbsdato for tokenet. Alternativt kan du sende `expires_in` (sekunder). Standard er 60 dage. |
| `username` | Nej | Kontoens @handle; vi læser det alligevel fra 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"
  }'
```

**Svar**

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

Som en del af push-handlingen abonnerer vi din app på den kontos webhooks (`subscribed_apps` med det sendte token), så beskeder begynder at flyde uden yderligere kald fra din side.

**Opdatering** - send det opdaterede token til det samme slutpunkt med det samme `ig_user_id`; det opdaterer det gemte token og udløbsdatoen på stedet.

**Konflikter** - én Instagram-konto kan aldrig være aktiv på to forbindelser. Hvis kontoen allerede er forbundet et andet sted, eller på denne specifikke konto via Facebook-side-flowet, returnerer push-handlingen en `409`, der fortæller dig, hvilken forbindelse du skal afbryde først. En forbindelse via Facebook-flowet bliver aldrig erstattet automatisk, da den muligvis også betjener Messenger.

### Trin 3 - Afbryd forbindelsen, når en klient forlader

`DELETE /channels/instagram-login/token` (samme godkendelse og `sub_account_id`) afmelder webhooks efter bedste evne og fjerner den gemte legitimation. Det lykkes altid, selv når tokenet allerede er udløbet — og når legitimationen er væk, ignoreres den kontos webhook-begivenheder.

---

## Tips til at bygge en pålidelig wrapper

- **Pol forsigtigt.** Hvert par sekunder er rigeligt. Stop, når du når en terminal tilstand (`connected` / `ONLINE` eller en fejlstatus), og sæt en fornuftig samlet timeout på loopet (browser/QR-trin udløber, se hver `expires_at`).
- **URL-kod telefonnumre i stien.** Det indledende `+` skal sendes som `%2B`. Endepunkterne gendanner også rå cifre, men kodning er den sikre standard.
- **Forvent aldrig at få hemmeligheder retur.** Adgangstokens, kanalhemmeligheder og sidetokens accepteres eller gemmes, men returneres aldrig i noget svar.
- **Håndter adgangsporten.** En `403` betyder, at API-adgang ikke er inkluderet i planen, eller at den kanal, du forbinder, ikke er inkluderet i kontoens plan. Se [API-adgang](../integrations/api-access.md).
- **Vær opmærksom på hastighedsbegrænsningen.** Autentificerede anmodninger er begrænset til 300 pr. minut; en `429` betyder, at du skal vente og prøve igen. Se [Autentificering](authentication.md).

## Næste skridt

- [Godkendelse](authentication.md) - de fire accepterede godkendelsesformer og fejlformat.
- [API-adgang](../integrations/api-access.md) - generering og administration af din API-nøgle.
