İnsan devri ve ekip yanıtları
Asistan sohbeti ekibinize devrettiğinde ne olur, ekibin yanıtları ziyaretçiye nasıl ulaşır.
API'den açılan her sohbet, ekibinizin Sonecentral'daki Mesajlar ekranında API kaynağıyla görünür. Ziyaretçinin adı orada API ziyaretçisi olarak geçer, çünkü kimliği bilinmez. Ekip sohbeti okuyabilir, devralabilir ve ziyaretçiye oradan yazabilir.
Devir nasıl olur
Asistan WhatsApp'ta nasıl davranıyorsa burada da öyle davranır: ziyaretçi bir insanla görüşmek isterse, asistan bir soruyu yanıtlayamazsa ya da işletmenin kuralları gerektirirse sohbeti ekibe devreder ve ziyaretçiye bunu söyler.
Ekibinizden biri Mesajlar ekranından sohbete yazdığında ya da bir ürün, hizmet veya belge paylaştığında da sohbet ekibe geçer. Asistan o andan sonra bu sohbette yanıt vermez; ekip sohbeti asistana geri verene kadar ekipte kalır.
Turun sonucu status alanında gelir:
status | Ne oldu | Ne yapmalı |
|---|---|---|
answered | Asistan yanıt verdi. | Bir şey gerekmez. |
handoff | Sohbet bu turda ekibe geçti; ziyaretçiye bir mesaj, genellikle devir mesajı yazıldı. | Mesajı gösterin, ekip yanıtlarını okumaya başlayın. |
human | Sohbet ekipte; asistan yanıt vermedi, mesaj ekibe ulaştı. | Ekip yanıtlarını okumaya başlayın ya da sürdürün. |
silent | Yanıt gerekmedi. | Bir şey gerekmez. |
status her biçimde gelir:
- Chat Completions: akışsız yanıtta
choices[0].message.sone.status, akışta son parçanın üst düzeyindekisone.status. - Responses: yanıtın üst düzeyindeki
sone.status. - Vercel AI SDK:
finishparçasınınmessageMetadata.statusalanı.
Sohbet ekipteyken ziyaretçi yazmaya devam edebilir; mesajları her zamanki uç noktalarla gönderin. Her biri human durumuyla döner ve ekibe ulaşır.
Sohbet ekipteyken ona yalnız sohbetin kimliğiyle ulaşılır, bu yüzden her istekte kimliği gönderin. Kimliği göndermeyen, yalnız role ve content saklayan ya da yalnız useChat'in id değerine dayanan bir istemcinin sonraki mesajı, geçmişi ne taşırsa taşısın ayrı bir sohbet açar ve o sohbette asistan yanıt verir: Sohbet sürekliliği. Sohbet asistana döndükten sonra da kimliği göndermeye devam edin: kimlik olmadan sohbet yalnız son yanıtı asistan kendisi yazdıysa, geçmişiniz o yanıtı kelimesi kelimesine taşıyorsa ve sohbetin ilk mesajından başlıyorsa sürer; hazır bir cümle, karşılama mesajı ya da ekibinizin bir mesajı buna yetmez. Ekibin yanıtlarını okumak için de kimliğe ihtiyacınız var. Her mesaja bir Idempotency-Key de ekleyin: ekip yazdıktan sonra adı olmayan bir mesajın yeniden denemesi ikinci kez kaydedilebilir.
Ekibin yanıtlarını okumak
Ekibin yazdıkları akışa gelmez, çünkü ne zaman yazacakları belli değildir. Onları sohbetin mesajlarından okursunuz:
GET https://pb.sonecentral.com/api/v1/conversations/{id}/messages?after={son_mesaj_kimliği}curl "https://pb.sonecentral.com/api/v1/conversations/conv_x8k2m9p4q7w1r3t/messages?after=msg_p4q7w1x8k2m9a5z" \
-H "Authorization: Bearer $SONE_API_KEY"{
"object": "list",
"data": [
{
"id": "msg_v2k8r4t1m9q6w3e",
"role": "user",
"type": "text",
"text": "Perşembe 15.00 olur mu?",
"created_at": 1760867520
},
{
"id": "msg_s7t4f2k9w1q3n8d",
"role": "staff",
"type": "text",
"text": "Merhaba, ben Elif. Perşembe 15.00 için sizi not aldım, onaylayınca buradan yazacağım.",
"created_at": 1760867538
}
],
"has_more": false,
"mode": "team",
"first_id": "msg_v2k8r4t1m9q6w3e",
"last_id": "msg_s7t4f2k9w1q3n8d"
}Alan
Tür
| Alan | Anlamı |
|---|---|
data | Mesajlar, eskiden yeniye. SoneMessage biçimindedir; ekip de ürün, hizmet, belge ve düğme gönderebilir. |
has_more | true ise sayfaya sığmayan mesajlar var. last_id ile hemen yeniden isteyin. |
mode | "team": sohbet ekipte. "assistant": asistan yanıt veriyor. |
first_id, last_id | Sayfadaki ilk ve son mesajın kimliği. data boşsa bu alanlar gelmez. |
- Liste sohbetin bütün satırlarını taşır: ziyaretçinin kendi mesajları
role: "user", asistanınkilerrole: "assistant", ekibinizinkilerrole: "staff"ile gelir. Ziyaretçinin mesajlarını zaten gösterdiğiniz için çizmeyin. - Bir sonraki istekte
afterolarak yanıttakilast_id'yi gönderin. Böylece ziyaretçinin satırları da imleci ilerletir ve aynı mesajı iki kez okumazsınız. afterbu sohbete ait bir mesajın kimliği değilse istek400 invalid_cursoralır. İmleci bırakıp sohbeti baştan okuyun.- Sohbet bu çalışma alanında bir API sohbeti değilse ya da anahtarınızın çağıramadığı bir asistanın sohbetiyse
404 conversation_not_founddöner. Aynı çalışma alanının, aynı asistanı çağırabilen her anahtarı bu sohbeti okuyabilir. - Her okuma anahtarın sınırlarına sayılır. Tarayıcı anahtarında okumaların kendi saatlik sınırı vardır; mesaj göndermek için ayrılan sınırdan düşmez.
Ekibin paylaştıkları
Ekibiniz Mesajlar ekranından yalnız yazmaz. WhatsApp'ta olduğu gibi envanterden bir ürünü, bir hizmeti ya da Bilgi Bankası'ndan bir belgeyi de sohbete paylaşabilir. Paylaşım size asistanın paylaşımlarıyla aynı yapıda gelir, yalnız role değeri "staff" olur:
| Paylaşılan | type | Nerede |
|---|---|---|
| Ürün ya da hizmet | catalog | Kayıt catalog.items içindedir. kind ürün için inventory, hizmet için offering olur. Ekibin her paylaşımı tek kayıt taşır. |
| Belge | file | file.url belgenin imzalı indirme bağlantısıdır. |
{
"id": "msg_k8r3t6w1q9m2x5c",
"role": "staff",
"type": "catalog",
"text": "Saç kesimi\nYıkama ve fön dahil.\n750₺\n45 dakika\nhttps://www.ornek.com/hizmet/sac-kesimi",
"created_at": 1760867590,
"catalog": {
"format": "card",
"items": [
{
"id": "o5n2k8w4q1t7m3x",
"kind": "offering",
"title": "Saç kesimi",
"description": "Yıkama ve fön dahil.",
"price": "750₺",
"detail": "45 dakika",
"url": "https://www.ornek.com/hizmet/sac-kesimi",
"button_title": "Hizmeti incele"
}
]
}
}- Paylaşım, ekibin yazdığı bir mesaj gibi sohbeti ekibe geçirir ve akışa gelmez; onu bu mesaj listesinden okursunuz. Asistanın yanıt verdiği bir sohbete paylaşım yapıldıysa ziyaretçinin sonraki mesajı
humandurumuyla döner; son turda aldığınız son mesajdan sonrasını okuduğunuzda paylaşım da gelir. - Ekip, ziyaretçinin bir mesajını bir paylaşımla yanıtladıysa ve siz o mesajı aynı
Idempotency-Keyile yeniden gönderirseniz, paylaşım o turun mesajları arasında da gelir. - Her paylaşımın
textalanı doludur. Kart ya da dosya çizmeyen bir istemci yalnız onu gösterebilir; çok uzun bir kaydıntext'i kısalır, kaydın tamamıcatalog.items'tadır. - Kartları çizmek ve belgeyi indirmek asistanın paylaşımlarıyla aynıdır: Zengin mesajlar.
Sohbetin durumu
Yalnız sohbetin kimde olduğunu öğrenmek için mesajları okumanız gerekmez:
GET https://pb.sonecentral.com/api/v1/conversations/{id}{
"id": "conv_x8k2m9p4q7w1r3t",
"object": "conversation",
"created_at": 1760866000,
"model": "k3m9x2p7q1w8e4r",
"mode": "team"
}model sohbetin bağlı olduğu asistanın kimliğidir. mode "assistant" ise asistan yanıt veriyor, "team" ise sohbet ekipte.
Sayfa yeniden açıldığında ekip yanıtlarını okumaya devam edip etmeyeceğinize buna bakarak karar verebilirsiniz.
Ne sıklıkla sormalı
Pencere açıkken ve sohbet ekipteyken beş saniyede bir sormak yeterli. Sekme arka plandayken ya da pencere kapalıyken sormayın; ziyaretçi geri döndüğünde bir kez sorup eksikleri tamamlayın.
Tarayıcı anahtarında okumaların kendi sınırı vardır: anahtar başına saatte 20.000. Beş saniyede bir soran her ziyaretçi saatte 720 okuma yapar; bu, bir anahtarla aynı anda yaklaşık 27 ziyaretçiye yeter. Sitenizde aynı anda daha çok ziyaretçi ekip yanıtı bekleyebiliyorsa aralığı uzatın:
- Devirden ya da ekibin son mesajından sonraki ilk iki dakika beş saniyede bir, sonra 30 ile 60 saniyede bir sorun.
- Yarım saat yeni mesaj gelmezse ziyaretçi yazana ya da pencereyi yeniden açana kadar sormayı bırakın.
429gelirseRetry-Afterkadar bekleyip öyle sorun.
Ayrıntılar: Limitler.
// İmleçten sonraki ekip ve asistan mesajlarını, sayfa sayfa sonuna kadar okur.
async function readTeamReplies(conversationId, cursor) {
const messages = [];
let mode = 'team';
for (;;) {
const url = new URL(`https://pb.sonecentral.com/api/v1/conversations/${encodeURIComponent(conversationId)}/messages`);
if (cursor) url.searchParams.set('after', cursor);
const response = await fetch(url, { headers: { Authorization: `Bearer ${KEY}` } });
if (!response.ok) break;
const page = await response.json();
messages.push(...page.data.filter((message) => message.role !== 'user'));
cursor = page.last_id ?? cursor;
mode = page.mode;
if (!page.has_more) break;
}
return { messages, cursor, mode }; // mode 'assistant' ise sormayı bırakın
}İlk imleç, son turda aldığınız son mesajın kimliğidir. Sonraki her okumada dönen cursor'ı saklayıp onu gönderin.
Tam bir örnek: Site içine sohbet penceresi.
Asistan yanıt vermediğinde
Açık bir sohbette ai_turn_ceiling, assistant_quota_exhausted, plan_required ya da assistant_paused gelirse ziyaretçinin mesajı kaydedilir ve ekibe ulaşır ama asistan yanıt vermez. Sohbet bu sırada ekibe geçmez, mode "assistant" kalır. Ekipten biri yazdığında ya da bir kayıt paylaştığında sohbet ekibe geçer ve yanıt mesaj listesinde görünür.
Bu yüzden bu hatalardan sonra, mode "assistant" olsa da mesajları okumayı sürdürün. Ekipten bir yanıt geldiğinde ya da ziyaretçinin sonraki mesajı yanıtlandığında bırakın.
Aynı hatalar yeni bir sohbetin ilk mesajında gelirse hiçbir şey kaydedilmez ve sohbet açılmaz. Ziyaretçiye biraz sonra yeniden denemesini söyleyin.
Sohbet asistana geri döner
Ekibiniz işi bitince sohbeti Mesajlar ekranından asistana geri verebilir. O andan sonra mesaj listesindeki mode "assistant" olur; ekip yanıtlarını okumayı bırakın. Ziyaretçinin sonraki mesajı yine asistan tarafından yanıtlanır ve status answered olur.
Site içine sohbet penceresi
Sitenizin köşesinde açılan, asistanınızla konuşan bir sohbet penceresi. Kopyalayıp yapıştırabileceğiniz düz HTML ve JavaScript ile React ve Next.js sürümü.
Siparişler, randevular ve gizlilik
API ziyaretçisi neyi yapabilir, neyi göremez. Sipariş ve randevu talepleri ekibin onayını bekler; kişisel kayıtlar API ziyaretçisine hiç açılmaz.