WhatsApp'ın yanında web sitenize sohbet balonu ekleyin ya da mobil uygulamanızı doğrudan Cxperium'a bağlayın — aynı bot, aynı gelen kutusu.
Bir Cxperium hesabı birden fazla kanala sahip olabilir. Kanalların tümü aynı bota, aynı kişi listesine ve aynı gelen kutusuna bağlanır; temsilciler hangi kanaldan gelirse gelsin sohbeti tek ekranda görür.
| Tür | Ne için | Nasıl bağlanır |
|---|---|---|
| Meta onaylı işletme numaranız | Başvuruyu ekibimiz yapar; onaylanan numara Kanallar listesinde görünür. | |
| Web | Web sitenizdeki sohbet balonu | Panelin verdiği kurulum kodunu sitenize yapıştırırsınız. Kod yazmak gerekmez. |
| Mobil (custom kanal) | Mobil uygulamanız ya da kendi istemciniz | REST + WebSocket ile; uygulama doğrudan ya da kendi sunucunuz üzerinden bağlanır. |
Yeni bir kanal oluşturmak için:
Sol menüden Kanallar'a girin ve sağ üstteki Ekle düğmesine basın.
Web sitenizdeki sohbet için Web, mobil uygulama ya da kendi istemciniz için Mobil kartını seçin.
Kanala bir ad yazın ve bu kanala gelen mesajların iletileceği bot adresini girin. Varsayılan dil isteğe bağlıdır. Kanal Ekle'ye basın.
Son adımda kanal anahtarı, secret ve (Web türünde) hazır kurulum kodu gösterilir. Bu bilgilere daha sonra Kanallar listesindeki Detay penceresinden de ulaşırsınız.
| Değer | Örnek | Nerede kullanılır |
|---|---|---|
Kanal anahtarı (channelKey) | ch_c727ccd3ef5112a1 | Adreslerde ve kurulum kodunda hangi kanal olduğunuzu söyler. Gizli değildir. |
| Secret | 64 karakterlik hex | Web kanalında kurulum kodunun içinde yer alır. Mobil (custom) kanalda yalnızca kayıt anında (uygulama) ya da istek imzalamak için (sunucu) kullanılır. |
| Bot adresi | https://bot.ornek.com/api/cxperium | Bu kanaldan gelen her mesajın iletildiği chatbot uç noktası. Kanalı düzenleyerek değiştirebilirsiniz. |
Web kanalı, sitenizin köşesine bir sohbet balonu ekler. Ziyaretçi balona tıklar, isterseniz adını yazar ve botla ya da temsilcinizle konuşmaya başlar. Kurulum tek bir kod parçasından ibarettir.
<!-- Cxperium chat -->
<script>
window.cxperiumSettings = {
channelKey: "ch_c727ccd3ef5112a1",
secret: "f57b4e…",
brand: "Acme Destek",
color: "#7c3aed",
launcherText: "Bize yazın",
texts: { greetingMessage: "Merhaba! Size nasıl yardımcı olabiliriz?" }
};
// İsteğe bağlı: sitenizde oturum açmış kullanıcıyı tanıtın —
// karşılama formu sorulmaz, sohbet doğrudan başlar:
// window.cxperiumSettings.user = { name: "Ahmet Yılmaz", username: "ahmet.y" };
(function (d) {
var s = d.createElement("script");
s.src = "https://cdn.cxperium.com/widget/v1/cxperium-widget.js";
s.async = true;
d.head.appendChild(s);
})(document);
</script>
Kanal oluşturmanın son adımında ya da Kanallar → Detay penceresinde Kopyala'ya basın. Görünümü özelleştirdiyseniz kodu Widget Tasarımcısı'ndan kopyalayın; oradaki kod seçtiğiniz tasarımı içerir.
Sohbetin görünmesini istediğiniz her sayfada </body> etiketinden hemen önce yapıştırın. Sayfada yalnızca bir Cxperium kodu olmalı; eskisi varsa silin.
Balon seçtiğiniz köşede görünmelidir. Görünmüyorsa sayfayı önbelleksiz yenileyin (Ctrl + F5).
Widget, ziyaretçinin kimliğini ve token'ını tarayıcıda saklar; ziyaretçi siteye geri döndüğünde önceki konuşmasına devam edebilir ya da yeni bir konuşma açabilir. Sitenizde oturum açmış kullanıcıyı user ayarıyla tanıtırsanız karşılama formu hiç sorulmaz.
Mobil uygulamada aynı widget: Custom kanalı bir WebView içinde de kullanabilirsiniz. Kanallar listesinde mobil kanalın WebView Özelleştirici ekranı, uygulamanıza gömeceğiniz sayfanın görünümünü ayarlar; böylece aşağıdaki SDK entegrasyonunu yazmadan sohbeti uygulamaya ekleyebilirsiniz.
Balonun rengini, konumunu, metinlerini ve markasını panelden değiştirirsiniz. Tasarımcı yalnızca Web türündeki kanallarda açılır.
Tasarımcıya iki yerden ulaşırsınız: kanalı oluşturduğunuz anda son adımdaki Görünümü özelleştir düğmesinden ya da daha sonra Kanallar listesinde kanalın Detay penceresinden. Ekran üç parçadır: solda ayarlar, sağda canlı önizleme (Sohbet / Karşılama formu görünümleri), önizlemenin altında kurulum kodu. Kaydet düğmesi yoktur; her değişiklik yaklaşık yarım saniye içinde hem önizlemeye hem koda yansır.
| Ayar | Kod anahtarı | Ne yapar |
|---|---|---|
| Marka adı | brand | Pencere başlığında ve bot balonlarının üstünde görünen ad. |
| Avatar görseli | avatarUrl | Başlıktaki yuvarlak logo. Boşsa markanın baş harfi gösterilir. Kare, en az 96×96 px, tam adres (https://…). |
| Balon ikonu | iconUrl | Köşedeki açma balonunun ikonu. Boşsa standart sohbet ikonu. |
| Balon yazısı | launcherText | Balonun yanında kısa çağrı metni (en fazla 24 karakter). Boşsa yalnızca ikon görünür. |
| Alt yazı | footerText | Pencerenin en altındaki küçük yazı. Boş bırakılırsa satır gizlenir. |
| Ayar | Kod anahtarı | Ne yapar |
|---|---|---|
| Ana renk | color | Başlık, ziyaretçi balonları, düğmeler ve açma balonu. |
| Degrade | colorDark | Başlığın koyu ucu. Boşsa ana renkten otomatik türetilir. |
| Zemin | background | Sohbet alanının arka planı. |
| Metin / Soluk | textColor, mutedColor | Bot balonlarındaki yazı rengi ve saat gibi ikincil yazılar. |
| Yazı tipi | font | CSS font adı (örn. Inter, sans-serif). Boşsa ziyaretçinin sistem yazı tipi. Font sitenizde yüklü olmalıdır. |
| Ayar | Kod anahtarı | Ne yapar |
|---|---|---|
| Konum | position | right (sağ alt) ya da left (sol alt). |
| Kenar / alt boşluk | sideOffset, bottomOffset | Balonun sayfanın yan kenarına ve altına uzaklığı (0–200 px). Sabit alt çubuğunuz varsa alt boşluğu artırın. |
| Panel genişliği / yüksekliği | width, height | Açılan pencerenin ölçüleri (280–600 / 400–900 px). Telefonlarda pencere ekranı kaplar. |
| Köşe yuvarlaklığı | radius | 0 keskin köşe, 40 çok yuvarlak. |
| Ayar | Kod anahtarı | Ne yapar |
|---|---|---|
| Ziyaretçiye ad sorulsun | askName | Açıkken karşılama formunda ad istenir ve zorunludur. Kapalıysa ziyaretçi "Ziyaretçi" olarak başlar. |
| Kullanıcı adı sorulsun | askUsername | Aynı kural, kullanıcı adı için. Varsayılan kapalı; çoğu site bunu user ayarıyla kendi oturumundan gönderir. |
| Sohbet karşılama mesajı | texts.greetingMessage | Sohbet başladığında bot balonu olarak çıkan ilk mesaj. Boşsa gösterilmez. |
| Karşılama başlığı / metni | texts.welcomeTitle, texts.welcomeMessage | Karşılama formunun üstündeki başlık ve açıklama. |
| Ad alanı etiketi / örneği | texts.nameLabel, texts.namePlaceholder | Ad kutusunun etiketi ve içindeki gri örnek yazı. |
| Başla butonu | texts.startButton | Formu gönderen düğmenin yazısı. |
| Dosya / görsel gönderimi | allowMedia | Mesaj kutusuna ataç düğmesi ekler. En fazla 2 MB; görsel ve PDF. |
| Mesaj kutusu yer tutucusu | texts.inputPlaceholder | Mesaj yazma kutusundaki gri yazı. |
Kurulum kodunda yalnızca varsayılandan farklı ayarlar yer alır; bu yüzden kod kısa kalır. Üst çubuktaki Varsayılanlara dön tüm ayarları ve taslağı temizler.
Mobil kanal (custom kanal), iOS, Android, React Native ya da Flutter uygulamanızı doğrudan Cxperium'a bağlar. Kullanıcı uygulamada mesaj yazar, bot ya da temsilci cevaplar, cevap anında uygulamaya düşer. Backend gerekmez.
| Ne için | Adres |
|---|---|
| Kayıt, geçmiş, teslim onayı (REST) | https://provider.cxperium.com |
| Canlı mesajlaşma (WebSocket, socket.io) | https://ws.cxperium.com — ad alanı /custom |
Karar tek soruya bağlı: uygulamanız ile Cxperium arasına kendi sunucunuz girecek mi?
| A) Sadece mobil uygulama | B) Kendi sunucunuz var | |
|---|---|---|
| Secret nerede durur | Uygulamaya gömülü; yalnızca kayıt anında kullanılır | Sunucunuzda ortam değişkeni olarak |
| Kullanıcı kimliğini kim üretir | Cxperium; kayıt cevabında döner | Siz belirlersiniz (u_42 gibi) |
| İstekleri ne doğrular | Kayıtta alınan kullanıcı token'ı (Authorization: Bearer) | Secret ile hesaplanan HMAC imzası (X-Cxperium-Signature) |
| Kullanıcının o kişi olduğu doğrulanır mı | Hayır; anonim destek için yeterli | Evet; kullanıcıyı sizin sunucunuz doğrular |
Backend'iniz yoksa A yolunu izleyin. Aşağıdaki adımlar A yolunu anlatır; B yolu için yalnızca kimlik başlığı değişir (bkz. "Sunucunuz varsa: imza").
const res = await fetch("https://provider.cxperium.com/custom/ch_xxxxxxxx/register", {
method: "POST",
headers: { "apiKey": SECRET, "Content-Type": "application/json" },
body: JSON.stringify({ user: { name: "Ahmet" } }),
}).then((r) => r.json());
// res = { status: 200, channelKey: "ch_xxxxxxxx",
// contact: { id: "c_5d5cdeb1-…" }, token: "8abfc196…" }
sakla("contactId", res.contact.id); // Keychain / EncryptedSharedPreferences
sakla("token", res.token); // süresi dolmaz, bir kez alınır
Uygulama silinip yeniden kurulduysa ve saklı contactId elinizdeyse kayıt gövdesine user.id olarak ekleyin; aynı token döner ve sohbet kaldığı yerden devam eder. Kullanıcı kimliğinde & karakteri bulunamaz.
import { io } from "socket.io-client";
const socket = io("https://ws.cxperium.com/custom", {
transports: ["websocket"],
auth: { channelKey: "ch_xxxxxxxx", user: contactId, token },
});
socket.on("connect", async () => {
// SIRA ÖNEMLİ: önce bağlan, SONRA geçmişi çek — tersi mesaj kaçırır.
// Mesajları yerelde saklıyorsanız after = son görülen seq; saklamıyorsanız 0.
let after = sakli("sonSeq") || 0;
for (;;) {
const h = await fetch(
`https://provider.cxperium.com/custom/ch_xxxxxxxx/messages?user=${contactId}&after=${after}&limit=50`,
{ headers: { Authorization: `Bearer ${token}` } },
).then((r) => r.json());
for (const m of h.messages) ekranaCiz(m);
if (!h.hasMore) break;
after = h.cursor; // sayfanın cursor'ından ilerleyin, kendi sayacınızdan değil
}
});
Geçmiş iki yönü birden döner: direction: "in" kullanıcının kendi mesajı (ekranda sağa), "out" bot ya da temsilci cevabı (sola). seq kullanıcı başına artan sıra numarasıdır.
// Gönder — id tekrar korumasıdır: ağ hatasında aynı id ile yeniden yollayın
socket.emit("message.send",
{ user: { name: "Ahmet" }, message: { id: benzersizId(), type: "text", text: "merhaba" } },
(ack) => { /* ack = { status: 202, messageId: "…" } */ });
// Al — m = { id, seq, ts, type, text, choices, media, link, form }
socket.on("message.created", (m) => {
if (gorulenler.has(m.id)) return; // aynı mesaj iki kez gelebilir
gorulenler.add(m.id);
ekranaCiz(m);
sakla("sonSeq", m.seq);
socket.emit("message.ack", { seq: m.seq }, () => {}); // seq'e kadar her şey teslim sayılır
});
WebSocket kopuksa aynı gövde REST'e de atılabilir: POST /custom/<KEY>/messages ve POST /custom/<KEY>/ack, Authorization: Bearer <token> başlığıyla. socket.io kopan bağlantıyı kendisi yeniler; connect geldiğinde Adım 2'deki geçmiş çekmeyi tekrar çalıştırın, arada kaçan mesajlar gelir.
Uygulama sizin sunucunuza, sunucunuz Cxperium'a gider. Secret uygulamaya inmez. Her isteğe X-Cxperium-Signature: t=<unix saniye>,v1=<hex> başlığı eklenir; v1 = HMAC-SHA256(secret, "<t>.<içerik>"). İçerik POST isteklerinde gövdenin ham JSON metni, WebSocket bağlantısında ve geçmiş sorgusunda "<channelKey>:<userId>" dizesidir. İmza 300 saniye geçerlidir; her istekte yeniden üretin.
const crypto = require("crypto");
function imzala(icerik) {
const t = Math.floor(Date.now() / 1000);
const v1 = crypto.createHmac("sha256", CHANNEL_SECRET).update(`${t}.${icerik}`).digest("hex");
return `t=${t},v1=${v1}`;
}
// WebSocket'te auth STATİK OBJE DEĞİL, FONKSİYON olmalı — yeniden bağlanmada imza tazelenir
const socket = io("https://ws.cxperium.com/custom", {
transports: ["websocket"],
auth: (cb) => cb({ channelKey: CHANNEL_KEY, user: userId, signature: imzala(`${CHANNEL_KEY}:${userId}`) }),
});
stringify etmeyin; anahtar sırası değişirse imza tutmaz. Gönderdiğiniz metnin aynısını imzalayın.
Aynı mesaj gövdesi WebSocket message.created olayında, geçmiş sorgusunda ve teslim webhook'unda birebir aynıdır. Tanımadığınız bir type gelirse text alanını gösterin; yeni tipler zamanla eklenir ve text her zaman doludur.
| Tip | Gövde | Not |
|---|---|---|
text | { "type": "text", "text": "merhaba" } | Düz metin. |
choice | { "type": "choice", "choice": { "id": "opt_evet", "title": "Evet" } } | Botun sunduğu butona tıklama. |
media | { "type": "media", "media": { "kind": "image", "url": "https://…", "mime": "image/jpeg", "caption": "…" } } | Görsel ya da dosya; adres herkese açık olmalı. |
form | { "type": "form", "form": { "token": "…", "name": "kayit_formu", "version": 3, "response": { … } } } | Botun gönderdiği formun cevabı; token gelen formdan aynen döner. |
Konum (location) tipi henüz desteklenmez; gönderirseniz 202 alırsınız ama işlenmez.
| Tip | Alanlar | Nasıl çizilir |
|---|---|---|
text | text | Düz balon. |
choices | text, choices[] (id, title) | Metin altına butonlar; tıklanınca choice tipinde cevap gönderin. |
media | media.kind, url, mime, caption, filename | Görsel, video ya da dosya kartı. |
link | text, link.url, link.label | Bağlantı butonu; tıklanınca sohbete bir şey gönderilmez, adres açılır. Adres text'in son satırında da bulunur; butonu çiziyorsanız o satırı gösteremeyin. |
form | text, form.screens, form.token, form.screen, form.data | Aşağıya bakın. |
Bot, WhatsApp'taki Flow ile aynı kodla custom kanala da form gönderebilir. Form tanımı mesajın içinde form.screens olarak gelir; ekranlar Meta Flow JSON biçimindedir (TextInput, Dropdown, RadioButtonsGroup, CheckboxGroup, DatePicker, Footer). form.screen ile başlayın; form.data ilk ekranın verisidir. Form çizemiyorsanız en azından text alanını gösterin.
complete ise doldurulan alanları form tipinde normal mesaj olarak gönderin; token zorunludur.data_exchange ise POST /custom/<KEY>/flows/exchange çağırın; yanıt { "version": "3.0", "screen": "…", "data": { … } } döner. screen değeri SUCCESS ise formu kapatıp data.extension_message_response.params nesnesini cevap olarak gönderin.En sık karşılaşılan durumlar ve çözümleri.
| Durum | Açıklama / çözüm |
|---|---|
| Tasarımcıyı tekrar açtım, ayarlarım gitmiş | Taslak yalnızca aynı tarayıcıda tutulur. Sitenizdeki kod değişmez; asıl kayıt odur. Koddaki değerleri tasarımcıya yeniden girin. |
| Değişiklik sitede görünmüyor | Yeni kodu yapıştırıp eskisini kaldırdığınızdan emin olun; sayfayı önbelleksiz yenileyin (Ctrl + F5). |
| Widget varsayılan mavi görünüyor | Kod kanal detayından kopyalanmış olabilir; oradaki kod her zaman varsayılan görünümü verir. Özelleştirilmiş kod tasarımcıdan kopyalanır. |
| "Görünümü özelleştir" düğmesi yok | Düğme yalnızca Web türündeki kanallarda gösterilir. Mobil kanallarda WebView Özelleştirici kullanılır. |
| Avatar / ikon görünmüyor | Adres tam (https://…) ve herkese açık olmalı. |
| Konsolda "channelKey ve secret zorunlu" | Kurulum kodundaki channelKey ya da secret boş. Kanal detayından kodu yeniden kopyalayın. |
| Hata | Sebep | Çözüm |
|---|---|---|
401 Invalid channel secret | Kayıtta apiKey başlığı yok ya da yanlış | Paneldeki secret ile karşılaştırın. |
401 Invalid token / WS INVALID_TOKEN | Token başka bir kimlikle kullanılıyor | Her kullanıcı kendi token'ını kullanmalı; gerekirse yeniden kayıt olun. |
401 Invalid signature / WS INVALID_SIGNATURE | Gövde yeniden stringify edilmiş ya da imza 300 sn'den eski | Ham metni imzalayın; her istekte yeniden üretin. |
WS UNAUTHORIZED | Kanal yok, pasif ya da silinmiş | Kanal anahtarını ve kanalın durumunu panelden kontrol edin. |
WS INVALID_AUTH | Ne token ne imza verilmiş | Bağlantı auth alanını düzeltin. |
WS AUTH_UNAVAILABLE | Geçici sunucu sorunu | Bekleyip aynı şekilde yeniden deneyin. |
| WS ilk bağlanıyor, sonra hep reddediyor | B yolunda auth statik obje verilmiş | auth fonksiyon olmalı; imza her bağlanmada tazelenir. |
| Mesajlar arada kayboluyor | Geçmiş çekme (gap-fill) yapılmıyor | Bağlanınca after=<son seq> ile toplayın. |
| Aynı mesaj iki kez görünüyor | id ile tekilleştirme yok | Mesajları id ile tekilleştirin. |
400 FLOW_KEY_MISSING | Kanalda bot form anahtarı tanımlı değil | Kanallar → Düzenle ekranından form anahtarını girin. |
502 BOT_UNREACHABLE / BOT_ERROR | Bot 10 sn içinde cevap vermedi ya da hata döndü | "Tekrar dene" gösterin; bot adresini panelden kontrol edin. |
| Bot hiç cevap vermiyor | Kanal pasif ya da bot ayakta değil | Kanal adıyla destek ekibimize yazın. |
Teknik ekibimiz entegrasyonunuzda size eşlik etsin — sorunuzu iletin, aynı gün dönelim.
Türkçe teknik destek · Entegrasyon danışmanlığı ücretsiz