Entegrasyon
Özel kanal — kendi yazılımını bağla
Sitendeki formları, lead araçlarını ya da kendi uygulamandaki sohbeti CRM'e API ile bağla — kanal anahtarı, gönderim, mesaj ve webhook.
Özel kanal, kendi yazılımını CRM'in gelen kutusuna bağlamanın yoludur. Hazır bir entegrasyonu olmayan her şey buradan girer: kendi sitenin teklif formu, bir lead toplama aracı, mobil uygulamanın içindeki sohbet, bir kiosk.
İki türü var; kanalı açarken birini seçersin:
| Tür | Ne için | Gelen uç | Yanıt |
|---|---|---|---|
| Formlar ve talepler | Site formları, lead araçları, "sizi arayalım" kutuları | …/submissions | Müşteriye e-postayla |
| İki yönlü sohbet | Kendi uygulamanın içindeki mesajlaşma | …/messages | Senin webhook adresine |
Kanalı aç
CRM → Ayarlar → Çalışma alanı → Kanallar → Özel kanal → Bağlantı kur
Türü ve kanalın adını seçersin (sohbette bir de webhook adresi). Karşılığında:
- Kanal anahtarı (
bck_önekli) — gelen uçları bununla çağırırsın. - Gelen uç adresi — çalışma alanının CRM adresinde.
- Sohbet türünde ayrıca imza sırrı (
bcs_önekli) — webhook isteklerini doğrularsın.
Anahtar ve sır bir kez gösterilir; bizde yalnız özetleri durur. Kaybedersen kanalın detayından Yeni kanal anahtarı üretirsin — eskisi o an çalışmaz olur.
Kanal anahtarı için çekirdek panelden ayrıca API anahtarı almana gerek yoktur. Anahtar yalnız kendi kanalının uçlarına girer: kişi listesini okuyamaz, başka konuşmalara dokunamaz. Bunun yerine conversations.write kapsamlı bir API anahtarı da kullanabilirsin (bkz. Kimlik doğrulama).
[!İPUCU] Anahtarı sunucunda tut, sitenin tarayıcıda çalışan JavaScript'ine gömme. Formu kendi sunucuna gönder, oradan bize ilet. Anahtar sızarsa en kötü ihtimalle o kanala sahte gönderim düşer; panelden yenileyip kapatırsın.
Form gönderimi
curl -X POST 'https://<çalışma-alanın>.crm.blesyum.app/api/crm/public/v1/channels/custom/<kanal>/submissions' \
-H 'Authorization: Bearer bck_…' \
-H 'Content-Type: application/json' \
-d '{
"id": "lead-1001",
"form": "Teklif formu",
"contact": { "name": "Deniz Kaya", "email": "deniz@ornek.com", "phone": "0532 111 22 33" },
"fields": [
{ "label": "Bütçe", "value": "10.000 TL" },
{ "label": "Modüller", "value": ["CRM", "ERP"] }
],
"message": "Pazartesi arayın.",
"page_url": "https://ornek.com/teklif",
"utm": { "utm_source": "google" },
"deal": {}
}'Adresi panelden kopyala: kanal ekranı tam adresi verir (kendi alan adını bağladıysan onu taşır).
| Alan | Zorunlu | Ne olur |
|---|---|---|
id | hayır | Senin kayıt kimliğin (en çok 190 karakter). Aynı kimlikle tekrar gönderirsen yeni talep açılmaz — ağ hatasında güvenle yeniden dene. |
form | hayır | Talebin konusu (Teklif formu — Deniz Kaya). Boşsa kanalın adı. |
contact.name · email · phone | hayır | Kişi e-postayla, e-posta yoksa telefonla bulunur ya da açılır. İkisi de yoksa talep yine açılır, kişi açılmaz. |
fields[] | message yoksa evet | label + value (metin, sayı, true/false ya da liste). Talebin gövdesine Etiket: değer satırları olarak yazılır; boş değerler atlanır. En çok 50 alan. |
message | fields yoksa evet | Serbest metin — alanlardan sonra kendi paragrafında. |
page_url | hayır | Formun gönderildiği sayfa — talebin künyesinde görünür. |
utm | hayır | Kampanya kaynağı (utm_source → source olarak saklanır). En çok 10 anahtar. |
deal | hayır | Varsa satış hattının ilk sütununda fırsat açılır. {"title": "…"} ile başlık verebilirsin; boşsa talebin konusu. |
Gövdedeki alanların adı bir sözleşmedir: tanınmayan bir alan ("email" kökte, contact altında değil) sessizce yok sayılmaz, 400 alır.
Yanıt
Yeni talep 201, aynı id ile tekrar 200 döner:
{
"conversation_id": "0193c4e2-…",
"duplicate": false,
"deal_id": null,
"deal_note": "pipeline_not_set_up"
}| Alan | Anlamı |
|---|---|
duplicate | true ise bu id daha önce işlendi; aynı talep döner. |
deal_id | Açılan (ya da daha önce açılmış) fırsat. |
deal_note | Fırsat açılamadıysa sebebi. pipeline_not_set_up: çalışma alanında satış hattı yok — CRM → Fırsatlar → Önerilen hattı kur. Hat kurulduktan sonra aynı idyi tekrar göndermek fırsatı açar, ikinci talep açmaz. |
Talep gelen kutusuna Web formu kanalıyla düşer; temsilcinin yanıtı müşteriye e-postayla gider. Kanal ilk gönderim gelince panelde "Bağlı" görünür.
Sohbet mesajı (iki yönlü)
curl -X POST 'https://<çalışma-alanın>.crm.blesyum.app/api/crm/public/v1/channels/custom/<kanal>/messages' \
-H 'Authorization: Bearer bck_…' \
-H 'Content-Type: application/json' \
-d '{
"contact": { "external_id": "user-42", "name": "Deniz Kaya", "email": "deniz@ornek.com" },
"message": { "id": "msg-1", "body": "Merhaba, siparişim nerede?" },
"attachments": [{ "url": "https://cdn.ornek.com/fatura.pdf", "name": "fatura.pdf" }]
}'contact.external_idsenin sistemindeki kişi kimliğidir; aynı kişi hep aynı konuşmaya düşer (kapalıysa yeniden açılır).message.idmükerrer korumasıdır: aynı kimlik ikinci kez yazılmaz.- Ek adresleri herkese açık olmalı (iç ağ adresleri reddedilir); dosyayı biz indirip saklarız (en çok 25 MB, 10 ek).
Yanıt 201:
{ "conversation_id": "0193c4e2-…", "message_id": "0193c4e3-…", "new_conversation": true, "duplicate": false }Yanıtlar senin webhook'una
Temsilci (ya da AI) yanıt verince adresine imzalı bir POST gelir:
POST /senin-ucun HTTP/1.1
Content-Type: application/json
X-Blesyum-Event: message.created
X-Blesyum-Signature: t=1790000000,v1=5f3a9c…{
"event": "message.created",
"channel_id": "cc_…",
"conversation_id": "0193c4e2-…",
"contact": { "external_id": "user-42" },
"message": {
"id": "0193c4e4-…",
"author": { "type": "agent", "name": "Temsilci Can" },
"text": "Kargoda, yarın elinizde.",
"html": "<p>Kargoda, <b>yarın</b> elinizde.</p>",
"attachments": []
},
"sent_at": "2026-10-03T12:00:00Z"
}2xx dönmezsen gönderim temsilciye "iletilemedi" olarak görünür. Yanıt gövdende {"id": "…"} döndürürsen o kimliği saklarız.
Kapanış, yeniden açılış ve AI'dan insana devir de aynı adrese olay olarak gelir: conversation.closed · conversation.reopened · conversation.handed_off. Bunlar kuyruktan teslim edilir ve tutmazsa üstel beklemeyle birkaç saat boyunca yeniden denenir.
İmzayı doğrula
v1, imza sırrıyla "<t>.<ham gövde>" metninin HMAC-SHA256'sıdır (hex). t beş dakikadan eskiyse reddet — tekrar oynatılan istek budur.
import { createHmac, timingSafeEqual } from "node:crypto";
export function imzaGecerli(hamGovde: string, baslik: string, sir: string): boolean {
const parca = Object.fromEntries(baslik.split(",").map(p => p.trim().split("=")));
const t = Number(parca.t);
if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false;
const beklenen = createHmac("sha256", sir).update(`${t}.${hamGovde}`).digest("hex");
const a = Buffer.from(beklenen);
const b = Buffer.from(String(parca.v1 ?? ""));
return a.length === b.length && timingSafeEqual(a, b);
}Müşterinin arayüzünden iki eylem
| Uç | Ne yapar |
|---|---|
POST …/custom/<kanal>/conversations/<konuşma>/escalate | "Bir insanla görüşmek istiyorum" — AI'dan ekibe devreder. Zaten insandaysa {"transferred": false, "reason": "already_human"}. |
POST …/custom/<kanal>/conversations/<konuşma>/csat | {"rating": 4, "remark": "…"} — memnuniyet puanı. CSAT kapalıysa ya da zaten puanlandıysa 409. |
Hatalar
Gövde her zaman aynı biçimdedir:
{ "type": "error.list", "errors": [{ "code": "parameter_invalid", "message": "Send at least one field or a message." }] }| Durum | Ne zaman |
|---|---|
400 parameter_invalid | Gövde okunamadı, tanınmayan alan, boş gönderim, geçersiz e-posta, tavanı aşan değer (sessizce kırpılmaz). |
401 unauthorized | Anahtar yok, yanlış ya da yenilenmiş. |
403 forbidden | Başka bir kanalın anahtarı; kanal anahtarıyla kanal dışı bir uç; kapsamı eksik API anahtarı; çalışma alanının CRM aboneliği kapalı. |
404 not_found | Kanal yok ya da kaldırılmış. |
409 conflict | Kanal duraklatılmış; form kanalına /messages ya da sohbet kanalına /submissions. |
429 rate_limit_exceeded | Kanal başına dakikada 300 istek aşıldı — X-RateLimit-Reset saniye sonra yeniden dene. |