Kanallar: Web & Mobil.

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.

Kanal Türleri ve Oluşturma

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ürNe içinNasıl bağlanır
WhatsAppMeta onaylı işletme numaranızBaşvuruyu ekibimiz yapar; onaylanan numara Kanallar listesinde görünür.
WebWeb sitenizdeki sohbet balonuPanelin verdiği kurulum kodunu sitenize yapıştırırsınız. Kod yazmak gerekmez.
Mobil (custom kanal)Mobil uygulamanız ya da kendi istemcinizREST + WebSocket ile; uygulama doğrudan ya da kendi sunucunuz üzerinden bağlanır.

Yeni bir kanal oluşturmak için:

  1. Kanallar sayfasını açın

    Sol menüden Kanallar'a girin ve sağ üstteki Ekle düğmesine basın.

  2. Türü seçin

    Web sitenizdeki sohbet için Web, mobil uygulama ya da kendi istemciniz için Mobil kartını seçin.

  3. Ad ve bot adresi verin

    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.

  4. Bağlantı bilgilerini alı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ÖrnekNerede kullanılır
Kanal anahtarı (channelKey)ch_c727ccd3ef5112a1Adreslerde ve kurulum kodunda hangi kanal olduğunuzu söyler. Gizli değildir.
Secret64 karakterlik hexWeb 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 adresihttps://bot.ornek.com/api/cxperiumBu kanaldan gelen her mesajın iletildiği chatbot uç noktası. Kanalı düzenleyerek değiştirebilirsiniz.
Secret sızdıysa: Kanallar listesinde kanalı düzenleyip Secret'ı Yenile deyin, ardından sitenizdeki kurulum kodunu ya da uygulamanızdaki değeri güncelleyin. Eski secret o andan itibaren geçersizdir.

Web Kanalı: Widget Kurulumu

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.

site-kurulum-kodu.html
<!-- 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>
  1. Kodu kopyalayın

    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.

  2. Siteye yapıştırın

    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.

  3. Sayfayı yenileyin

    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.

Güvenlik: Kurulum kodu kanal anahtarınızı ve secret'ınızı içerir. Sayfadaki secret yalnızca yeni bir sohbet kaydı açabilir; mevcut sohbetleri okuyamaz. Yine de sızdığını düşünürseniz secret'ı yenileyin.

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.

Widget Görünümü (Widget Tasarımcısı)

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.

Tasarım sunucuda saklanmaz. Yaptığınız görünüm, sitenize yapıştırdığınız kurulum kodunun içinde yaşar. Tasarımcı yalnızca bu tarayıcıda bir taslak tutar; başka bir bilgisayardan açtığınızda varsayılanlar görünür. Her değişiklikten sonra kodu yeniden kopyalayıp sitenizdeki kodla değiştirin.

Marka

AyarKod anahtarıNe yapar
Marka adıbrandPencere başlığında ve bot balonlarının üstünde görünen ad.
Avatar görseliavatarUrlBaşlıktaki yuvarlak logo. Boşsa markanın baş harfi gösterilir. Kare, en az 96×96 px, tam adres (https://…).
Balon ikonuiconUrlKöşedeki açma balonunun ikonu. Boşsa standart sohbet ikonu.
Balon yazısılauncherTextBalonun yanında kısa çağrı metni (en fazla 24 karakter). Boşsa yalnızca ikon görünür.
Alt yazıfooterTextPencerenin en altındaki küçük yazı. Boş bırakılırsa satır gizlenir.

Renkler ve yazı tipi

AyarKod anahtarıNe yapar
Ana renkcolorBaşlık, ziyaretçi balonları, düğmeler ve açma balonu.
DegradecolorDarkBaşlığın koyu ucu. Boşsa ana renkten otomatik türetilir.
ZeminbackgroundSohbet alanının arka planı.
Metin / SoluktextColor, mutedColorBot balonlarındaki yazı rengi ve saat gibi ikincil yazılar.
Yazı tipifontCSS font adı (örn. Inter, sans-serif). Boşsa ziyaretçinin sistem yazı tipi. Font sitenizde yüklü olmalıdır.

Yerleşim ve boyut

AyarKod anahtarıNe yapar
Konumpositionright (sağ alt) ya da left (sol alt).
Kenar / alt boşluksideOffset, bottomOffsetBalonun 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ğiwidth, heightAçılan pencerenin ölçüleri (280–600 / 400–900 px). Telefonlarda pencere ekranı kaplar.
Köşe yuvarlaklığıradius0 keskin köşe, 40 çok yuvarlak.

Metinler ve davranış

AyarKod anahtarıNe yapar
Ziyaretçiye ad sorulsunaskNameAçıkken karşılama formunda ad istenir ve zorunludur. Kapalıysa ziyaretçi "Ziyaretçi" olarak başlar.
Kullanıcı adı sorulsunaskUsernameAynı 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.greetingMessageSohbet başladığında bot balonu olarak çıkan ilk mesaj. Boşsa gösterilmez.
Karşılama başlığı / metnitexts.welcomeTitle, texts.welcomeMessageKarşılama formunun üstündeki başlık ve açıklama.
Ad alanı etiketi / örneğitexts.nameLabel, texts.namePlaceholderAd kutusunun etiketi ve içindeki gri örnek yazı.
Başla butonutexts.startButtonFormu gönderen düğmenin yazısı.
Dosya / görsel gönderimiallowMediaMesaj kutusuna ataç düğmesi ekler. En fazla 2 MB; görsel ve PDF.
Mesaj kutusu yer tutucusutexts.inputPlaceholderMesaj 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 Uygulama (Custom Kanal)

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çinAdres
Kayıt, geçmiş, teslim onayı (REST)https://provider.cxperium.com
Canlı mesajlaşma (WebSocket, socket.io)https://ws.cxperium.com — ad alanı /custom

İki kurulum yolu

Karar tek soruya bağlı: uygulamanız ile Cxperium arasına kendi sunucunuz girecek mi?

A) Sadece mobil uygulamaB) Kendi sunucunuz var
Secret nerede dururUygulamaya gömülü; yalnızca kayıt anında kullanılırSunucunuzda ortam değişkeni olarak
Kullanıcı kimliğini kim üretirCxperium; kayıt cevabında dönerSiz belirlersiniz (u_42 gibi)
İstekleri ne doğrularKayı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 yeterliEvet; 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").

Adım 1: Kayıt ol (ilk açılışta bir kez)

register.js
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.

Adım 2: Bağlan ve geçmişi çek (her açılışta)

connect.js
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.

Adım 3: Mesaj gönder, cevap al, teslim onayla

chat.js
// 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.

  • contactId ve token'ı kalıcı saklayın — uygulama kapanınca kaybolmasın.
  • Önce WebSocket, sonra geçmiş — ters sıra aradaki saniyelerde gelen mesajı kaçırır.
  • Mesajları id ile tekilleştirin — sistem "en az bir kez teslim" garantisi verir, "tam bir kez" değil.
  • Sayfalarken after'ı cevaptaki cursor'dan ilerletin — kendi tuttuğunuz sayaçtan değil.
  • Kopunca panik yok — yeniden bağlanınca geçmişi çekin; mesaj kaybolmaz.

Sunucunuz varsa: imza (B yolu)

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.

sign.js
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}`) }),
});
POST gövdesini yeniden stringify etmeyin; anahtar sırası değişirse imza tutmaz. Gönderdiğiniz metnin aynısını imzalayın.

Mesaj Tipleri ve Formlar

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.

Kullanıcıdan bota gönderebilecekleriniz

TipGövdeNot
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.

Bottan kullanıcıya gelebilecekler

TipAlanlarNasıl çizilir
texttextDüz balon.
choicestext, choices[] (id, title)Metin altına butonlar; tıklanınca choice tipinde cevap gönderin.
mediamedia.kind, url, mime, caption, filenameGörsel, video ya da dosya kartı.
linktext, link.url, link.labelBağ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.
formtext, form.screens, form.token, form.screen, form.dataAşağıya bakın.

Formlar (Flow)

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.

  • Cevap: Son ekranın Footer aksiyonu complete ise doldurulan alanları form tipinde normal mesaj olarak gönderin; token zorunludur.
  • Sunucudan ekran isteme: Footer aksiyonu 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.
  • Hazır uygulama: Web widget'ı bu bölümün tamamını uygular; WebView entegrasyonunda ek iş gerekmez.

Sorun Giderme

En sık karşılaşılan durumlar ve çözümleri.

Web widget'ı

DurumAçı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üyorYeni kodu yapıştırıp eskisini kaldırdığınızdan emin olun; sayfayı önbelleksiz yenileyin (Ctrl + F5).
Widget varsayılan mavi görünüyorKod 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 yokDüğme yalnızca Web türündeki kanallarda gösterilir. Mobil kanallarda WebView Özelleştirici kullanılır.
Avatar / ikon görünmüyorAdres 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.

Custom kanal (mobil)

HataSebepÇözüm
401 Invalid channel secretKayıtta apiKey başlığı yok ya da yanlışPaneldeki secret ile karşılaştırın.
401 Invalid token / WS INVALID_TOKENToken başka bir kimlikle kullanılıyorHer kullanıcı kendi token'ını kullanmalı; gerekirse yeniden kayıt olun.
401 Invalid signature / WS INVALID_SIGNATUREGövde yeniden stringify edilmiş ya da imza 300 sn'den eskiHam metni imzalayın; her istekte yeniden üretin.
WS UNAUTHORIZEDKanal yok, pasif ya da silinmişKanal anahtarını ve kanalın durumunu panelden kontrol edin.
WS INVALID_AUTHNe token ne imza verilmişBağlantı auth alanını düzeltin.
WS AUTH_UNAVAILABLEGeçici sunucu sorunuBekleyip aynı şekilde yeniden deneyin.
WS ilk bağlanıyor, sonra hep reddediyorB yolunda auth statik obje verilmişauth fonksiyon olmalı; imza her bağlanmada tazelenir.
Mesajlar arada kayboluyorGeçmiş çekme (gap-fill) yapılmıyorBağlanınca after=<son seq> ile toplayın.
Aynı mesaj iki kez görünüyorid ile tekilleştirme yokMesajları id ile tekilleştirin.
400 FLOW_KEY_MISSINGKanalda bot form anahtarı tanımlı değilKanallar → Düzenle ekranından form anahtarını girin.
502 BOT_UNREACHABLE / BOT_ERRORBot 10 sn içinde cevap vermedi ya da hata döndü"Tekrar dene" gösterin; bot adresini panelden kontrol edin.
Bot hiç cevap vermiyorKanal pasif ya da bot ayakta değilKanal adıyla destek ekibimize yazın.

Aradığınızı bulamadınız mı?

Teknik ekibimiz entegrasyonunuzda size eşlik etsin — sorunuzu iletin, aynı gün dönelim.

Türkçe teknik destek · Entegrasyon danışmanlığı ücretsiz