> ## Documentation Index
> Fetch the complete documentation index at: https://docs.flextell.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Web sitesi widget'ı

> Widget'ı sitenize gömmeyi, ziyaretçi oturumu ve mesaj API'sini ve presence kanalını anlatır.

Web sitesi widget'ı, sitenizde canlı sohbet balonu gösterir. Ziyaretçinin ilk mesajı klinikte **Sohbetler** bölümüne düşer ve AI asistan ziyaretçiye yanıt verebilir. Bu sayfa, widget'ı sitenize gömmek isteyen entegratörler ve widget'ın herkese açık uç noktalarını doğrudan kullanmak isteyenler içindir.

Widget'ın panelden kurulumu için [Web sitesi widget'ı](/panel/baglantilar/web-sitesi-widgeti) sayfasına bakın. Kanal kaynağının genel yapısı için [Kanallar](/api/kaynaklar/kanallar) sayfasına bakın.

<Info>
  Widget uç noktaları `/api/v1` altında değildir ve OAuth `access_token` istemez. Kimlik bilgisi, yoldaki `embed_token` ile ziyaretçi oturumunun `session_token` değeridir. Yanıtlar standart API zarfında dönmez; hata biçimi için sayfanın sonundaki Güvenlik ve sınırlar bölümüne bakın.
</Info>

## Gömme kodu

Her web sitesi kanalının bir `embed_token` değeri vardır. Kanal oluşturulduğunda otomatik üretilir. Gömme kodu bu değeri taşıyan tek satırlık bir script etiketidir.

```html theme={null}
<script async src="https://app.flextell.ai/widget/<embed_token>/embed.js"></script>
```

<Steps>
  <Step title="Kanalı oluşturun">
    Panelde **Bağlantılar → Entegrasyonlar → Website → Kanallar** yolundan **Kanal Ekle**'ye tıklayın. **Website alan adı** alanına sitenizin alan adını protokol ve `www` olmadan girin (örneğin `example.com`). Yerel geliştirme için port ekleyebilirsiniz (`localhost:5500`). Kanalı API ile de açabilirsiniz; bkz. [Kanallar](/api/kaynaklar/kanallar).
  </Step>

  <Step title="Gömme kodunu alın">
    Kanal satırının menüsünden **Embed Script**'i seçin ve **Kodu Kopyala**'ya tıklayın. API ile almak için aşağıdaki uç noktayı kullanın.
  </Step>

  <Step title="Kodu sayfaya ekleyin">
    Kodu HTML sayfanızdaki kapanış `</body>` etiketinden hemen önce yapıştırın. Etiket yöneticisi kullanıyorsanız oradan da ekleyebilirsiniz.
  </Step>
</Steps>

| Metot | Endpoint | Açıklama | Scope | İzin |
| - | - | - | - | - |
| GET | `/api/v1/channels/{id}/widget/embed-snippet` | Gömme kodunu döndürür | `channels:read` | `CopyLink:Channel` (panelde **Gömme Kodunu Kopyala**) |
| POST | `/api/v1/channels/{id}/widget/rotate-token` | `embed_token` değerini yeniler | `channels:write` | `GenerateLink:Channel` (panelde **Bağlantı Oluştur**) |

`embed-snippet` yanıtı üç alan içerir: `embed_token`, `embed_url` ve `snippet`. Kanalda token yoksa `CHANNEL_EMBED_TOKEN_MISSING` (422) döner. Kanal web sitesi kanalı değilse widget uç noktaları `CHANNEL_NOT_WEBSITE` (422) döner.

<Warning>
  `rotate-token` eski gömme kodunu hemen çalışmaz hâle getirir ve tüm ziyaretçi oturumlarını geçersiz kılar. Token'ı yeniledikten sonra yeni kodu sitenize eklemeniz gerekir. Panelde bu işlemin adı **Token Yenile**'dir.
</Warning>

## Yapılandırma

Widget'ın görünümü ve davranışı kanalın widget yapılandırmasında tutulur. `PUT` isteği kısmi birleştirme yapar: yalnız gönderdiğiniz alanlar değişir.

| Metot | Endpoint | Açıklama | Scope | İzin |
| - | - | - | - | - |
| GET | `/api/v1/channels/{id}/widget` | Varsayılanlar uygulanmış yapılandırmayı döndürür | `channels:read` | `View:Channel` |
| PUT | `/api/v1/channels/{id}/widget` | Yapılandırmayı günceller | `channels:write` | `Update:Channel` |

Başlıca alanlar:

| Alan | Kural | Varsayılan |
| - | - | - |
| `title` | En çok 100 karakter | Kanal adı |
| `welcome_message` | En çok 500 karakter | `Merhaba! Size nasıl yardımcı olabilirim?` |
| `input_placeholder` | En çok 100 karakter | `Mesajınızı yazın...` |
| `primary_color` | Onaltılık renk (`#RGB` veya `#RRGGBB`) | `#4F46E5` |
| `secondary_color`, `background_color` | Onaltılık renk | `#4338CA`, `#FFFFFF` |
| `border_radius` | 0–50 | 16 |
| `position` | `bottom-right` veya `bottom-left` | `bottom-right` |
| `widget_width` | 280–500 | 380 |
| `widget_height` | 400–800 | 600 |
| `bubble_icon` | `chat`, `headset`, `help`, `wave` | `chat` |
| `auto_open_delay` | `null` veya 1–60 saniye | `null` (otomatik açılmaz) |
| `allow_message_editing` | Personelin giden metin mesajlarını düzenlemesine izin verir | `false` |
| `allow_message_deletion` | Personelin giden mesajları ve ekleri silmesine izin verir | `false` |
| `custom_css` | En çok 10000 karakter | Boş |

Yazı tipi, başlık, mesaj balonu, giriş alanı ve açma düğmesi (FAB) için ek alanlar da vardır. Tam listeyi `GET` yanıtında görebilirsiniz. Başlık, kullanıcı mesajı, gönder düğmesi ve FAB arka plan renkleri boş bırakılırsa `primary_color` kullanılır. Renk alanları onaltılık biçimde değilse 422 döner.

<Note>
  Widget altında "Powered by Flextell" ibaresi her zaman görünür. `show_branding` yapılandırmadan kapatılamaz.
</Note>

Panelde aynı ayarlar **Widget Ayarları** sayfasındadır. Widget, sayfanızda `iframe` olmadan çalışır; sitenizin CSS'i ve `custom_css` aynı sayfayı etkiler.

## Ziyaretçi oturumu

Embed script yüklenince önce yapılandırmayı okur, sonra oturum açar. Kendi arayüzünüzü yazıyorsanız aynı sırayı izleyin. Örneklerde `Origin` başlığı zorunludur; tarayıcı bunu kendisi gönderir, `curl` ile siz ekleyin.

<Steps>
  <Step title="Yapılandırmayı okuyun">
    `GET /widget/{token}/config` tema alanlarını, uç nokta adreslerini ve gerçek zamanlı bağlantı ayarlarını döndürür. Yanıttaki başlıca alanlar: `channel_id`, `channel_name`, `api_base_url`, `session_endpoint`, `message_endpoint`, `broadcast_driver`, `broadcast_config`, `broadcast_auth_endpoint`, `ai_online`.
  </Step>

  <Step title="Oturum başlatın veya sürdürün">
    `POST /widget/{token}/session` isteğinde kayıtlı `session_token` değerini gönderin. İlk ziyarette alanı boş bırakın.
  </Step>

  <Step title="Token'ı saklayın">
    Yanıttaki `session_token` değerini saklayın ve sonraki isteklerde gönderin. Embed script bunu tarayıcıda `localStorage` içinde `flextell-widget:{embed_token}:session_token` anahtarıyla tutar.
  </Step>
</Steps>

```bash theme={null}
curl -X POST "https://app.flextell.ai/widget/<embed_token>/session" \
  -H "Origin: https://example.com" \
  -H "Content-Type: application/json" \
  -d '{"session_token": null}'
```

| Yanıt alanı | Açıklama |
| - | - |
| `conversation_id` | Sohbet kimliği. İlk mesaja kadar `null`. |
| `visitor_id` | Sunucunun ürettiği anonim ziyaretçi kimliği. |
| `session_token` | Sonraki isteklerde gönderilecek oturum anahtarı. |
| `broadcast_channel` | `conversation.{id}`; sohbet yoksa `null`. |
| `ai_online` | AI asistanın yanıt verip veremeyeceği. |
| `messages` | En çok 100 mesaj, eskiden yeniye. Sistem mesajları yoktur. |

Oturum açmak veri yazmaz. Sohbet, hasta kaydı ve (kliniğinizde aktif bir pipeline varsa) Lead ancak ziyaretçi ilk mesajı gönderdiğinde oluşur. Hasta kaydı ad ve telefon içermez. `session_token` 30 gün geçerlidir.

## Mesaj gönderme

Ziyaretçi mesajı `POST /widget/{token}/message` ile gider.

| Alan | Zorunlu | Kural |
| - | - | - |
| `session_token` | Evet | En çok 2048 karakter. Eksikse `Oturum anahtarı zorunludur.` |
| `message` | Evet | En çok 10000 karakter. Eksikse `Mesaj alanı zorunludur.`, uzunsa `Mesaj en fazla 10000 karakter olabilir.` |

```bash theme={null}
curl -X POST "https://app.flextell.ai/widget/<embed_token>/message" \
  -H "Origin: https://example.com" \
  -H "Content-Type: application/json" \
  -d '{"session_token": "<session_token>", "message": "Merhaba, randevu almak istiyorum."}'
```

Başarılı yanıt `{ "success": true, "chat_log_id": 123, "conversation_id": 456 }` biçimindedir. Geçersiz, süresi dolmuş veya yenilenmiş token'la gönderirseniz `403` ve `{"message": "Invalid session"}` alırsınız. Mesaj kaydedilemezse `409` ve `Could not create chat log` döner.

<Note>
  Ziyaretçi yalnızca metin mesajı gönderebilir. Ek ve konum yalnızca klinik personelinden ziyaretçiye gider. Personelin yazdığı biçimlendirilmiş (markdown) metin ziyaretçiye düz metin olarak iletilir.
</Note>

## Gerçek zamanlı kanal

Personelin ve AI asistanın yanıtları ziyaretçiye `presence-conversation.{conversationId}` kanalından gelir. Ziyaretçinin sohbeti yokken kanal da yoktur. İlk `message` yanıtında `conversation_id` gelir; kanala o andan sonra abone olun.

Bağlantı ayarlarını `config` yanıtındaki `broadcast_config` alanı verir (`key`, `cluster`, `wsHost`, `wsPort`, `wssPort`, `forceTLS`, `enabledTransports`). Kanal yetkilendirmesi için `broadcast_auth_endpoint` adresine `socket_id`, `channel_name` ve `session_token` gönderilir. Bu uç nokta yalnızca ziyaretçinin kendi sohbetinin kanalını yetkilendirir.

```javascript theme={null}
import Pusher from 'pusher-js'

const cfg = await fetch(`https://app.flextell.ai/widget/${EMBED_TOKEN}/config`).then(r => r.json())

const pusher = new Pusher(cfg.broadcast_config.key, {
  cluster: cfg.broadcast_config.cluster,
  channelAuthorization: {
    endpoint: cfg.broadcast_auth_endpoint,
    params: { session_token: sessionToken },
  },
})

const channel = pusher.subscribe(`presence-conversation.${conversationId}`)
channel.bind('MessageSent', ({ message }) => render(message))
channel.bind('PresenceUpdated', ({ is_typing }) => showTyping(is_typing))
```

| Olay | Payload | Ne zaman |
| - | - | - |
| `MessageSent` | `{ message }` | Sistem dışındaki her yeni mesajda. Mesaj, düzenleme zamanı veya silinme durumu değişince yeniden gönderilir. Personelin gönderdiği ek, dosya hazır olduktan sonra iletilir. |
| `PresenceUpdated` | `{ conversation_id, is_typing, expires_at }` | AI asistan yazmaya başlayınca ve bitirince. Yalnızca kanalın AI sohbet modu `Otomatik` ise gönderilir. |

`message` nesnesinin başlıca alanları: `id`, `message_id`, `body`, `role` (`customer` veya `agent`), `is_customer`, `is_deleted`, `edited_at`, `message_type`, `media_type`, `created_at`, `file_url`, `file_name`, `file_mime_type`, `file_size`, `file_download_url`. Silinen mesajda `body` boştur. `file_download_url` 1 saat geçerli, imzalı bir bağlantıdır.

<Tip>
  Kaçan olaylar tekrar gönderilmez. Bağlantı kurulunca (`pusher:subscription_succeeded`) `session` uç noktasını yeniden çağırıp son 100 mesajı okuyun ve ekrandakilerle birleştirin. Embed script de böyle çalışır.
</Tip>

Kliniğin personel tarafındaki kanalları için [Kanallar ve olaylar](/api/gercek-zamanli/kanallar-ve-olaylar) sayfasına bakın. Personel bu presence kanalına yalnızca `View:Conversation` iznine sahipse ve sohbeti görebiliyorsa abone olabilir.

## Güvenlik ve sınırlar

### Alan adı denetimi

Widget uç noktaları (`embed.js` hariç) isteğin `Origin` başlığını kanalın **Website alan adı** ile karşılaştırır.

* Alan adı büyük/küçük harfe ve baştaki `www.` önekine duyarsızdır.
* Alan adı portsuz kaydedildiyse her port kabul edilir. Portlu kaydedildiyse yalnız o port kabul edilir.
* Başka alt alan adları reddedilir. `example.com` kayıtlıyken `shop.example.com` çalışmaz.
* `Origin` başlığı olmayan istekler reddedilir.
* `embed.js` dosyası `Origin` göndermeyen `<script src>` etiketiyle yüklendiği için bu denetimden geçmeden sunulur.

### Hata yanıtları

Widget hataları standart API zarfında değildir. Durum kodu ve kısa bir `message` ya da `error` metni döner.

| HTTP | Metin | Ne zaman |
| - | - | - |
| 403 | `Invalid embed token` | Token bulunamadı, kanal pasif (**Aktif** kapalı) veya token yenilendi. |
| 403 | `Channel domain not configured` | Kanalda alan adı kayıtlı değil. |
| 403 | `Origin not allowed`, `Invalid origin` | `Origin` kayıtlı alan adıyla eşleşmiyor. |
| 403 | `Invalid session` | `message` isteğinde oturum anahtarı eksik, süresi dolmuş, başka kanala ait veya yenilenmiş. |
| 403 | `Missing parameters`, `Conversation not found`, `Channel mismatch` | Kanal yetkilendirmesinde eksik alan, henüz sohbet yok veya ziyaretçinin kendi sohbeti dışında bir kanal istendi. |
| 409 | `Could not create chat log` | Mesaj kaydedilemedi. |
| 422 | Alan mesajı | `message` veya `session_token` doğrulaması başarısız. |
| 429 | — | İstek sınırı aşıldı. |

### İstek sınırları

Sınırlar, embed token ve IP adresi çiftine göre dakikada uygulanır.

| Uç nokta | Sınır |
| - | - |
| `POST /widget/{token}/session` | 10 / dakika |
| `POST /widget/{token}/message` | 20 / dakika |
| `GET /widget/{token}/config`, `GET /widget/{token}/embed.js`, `POST /widget/{token}/broadcasting/auth` | 60 / dakika |

### Ziyaretçi kimliği ve gizlilik

* Ziyaretçiyi yalnızca şifreli `session_token` tanır. Ham ziyaretçi kimliği kabul edilmez.
* Token geçersizse yeni bir ziyaretçi kimliği verilir. Ziyaretçi, site verilerini temizlediğinde, 30 gün geçtiğinde veya `embed_token` yenilendiğinde sohbet geçmişini görmez.
* Pasif kanal yeni web sitesi mesajı kabul etmez.

<Warning>
  `embed_token` herkese açıktır; sayfa kaynağında görünür. Gizli tutulacak bir değer olarak saklamayın. Kötüye kullanım şüphesinde **Token Yenile** ile yeni token üretin.
</Warning>

### Sorun giderme

* Widget görünmüyor ve konsolda 403 var: alan adı yazımını, alt alan adını ve portu kontrol edin, kanalın **Aktif** olduğundan ve gömme kodunun güncel olduğundan emin olun.
* Gönder düğmesi pasif: oturum açılamamıştır. `session` çağrısının hatasına bakın.
* Yanıtlar canlı gelmiyor: `config` yanıtındaki `broadcast_config` boş olabilir. Bu durumda widget gerçek zamanlı bağlantı kurmaz; ayrıntı için [Destek](/api/destek) sayfasına bakın.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.