İçeriğe geç

Webhook’lar

Zitena, talepler, çağrılar ve giden aramalar gibi olayları sizin adresinize imzalı POST istekleriyle bildirir. Uçlar Ayarlar → Webhook’lar sayfasında yönetilir (paket: Webhooklar; yazma yönetici ve üstü).

Webhook teslimatı1. Olay oluşur (ör. talep açıldı) → 2. Teslimat sırası (her uç için ayrı) → 3. İmzalı POST (X-Zitena-Signature) → 4. 2xx = teslim (değilse tekrar dener)Olay oluşurör. talep açıldıTeslimat sırasıher uç için ayrıİmzalı POSTX-Zitena-Signature2xx = teslimdeğilse tekrar dener
  1. Yeni uç: adres (yalnız https://; iç ağa ya da özel IP’ye çıkan adresler reddedilir), açıklama ve dinlenecek olaylar.
  2. Kaydedince gizli anahtar (whsec_…) bir kez gösterilir. Sunucunuzda saklayın; Gizliyi yenile ile değiştirebilirsiniz.
  3. Test gönder ile test olayını hemen gönderip sonucu görün.

Her uçta son teslimatın durumu ve son 24 saatteki başarısız teslimat sayısı görünür; Teslimatlar listesinde her teslimatın durumunu, deneme sayısını, yanıt kodunu ve gövdesini görebilir, başarısız bir teslimatı elle yeniden deneyebilirsiniz.

POST https://sizin-adresiniz.example.com/zitena
Content-Type: application/json
User-Agent: Zitena-Webhook/1
X-Zitena-Event: request.created
X-Zitena-Delivery: 0199a1b2-… (teslimat kimliği; tekrarlarda aynı)
X-Zitena-Signature: t=1790000000,v1=5f2c…
{"id": "0199a1b2-…", "event": "request.created", "created_at": "2026-09-24T10:15:00+00:00", "data": {…}}
OlayNe zamandata
request.createdGörüşmede talep açıldıTalep: id, number, call_id, kind, status, order_number, order_status, customer_name, email, phone, details, history, created_at, updated_at
request.status_changedTalebin durumu değiştiTalep + previous_status
talep.acildiGörüşmede talep açıldı (sade, iletişim bilgisi yok)id, talep_no, tur, durum, siparis_no, call_id, created_at
order.appliedTalep sitede otomatik uygulandı (adres, iptal)request_id, request_number, kind, order_number, action, site, call_id, applied_at
call.completedGörüşme bitti (tamamlandı, meşgul, cevapsız, başarısız…)id, agent_id, channel, status, outcome, phone, callee_name, is_test, summary, created_at, answered_at, ended_at, duration_s, requests
cagri.etiketlendiGörüşme etiketlendi ya da etiketi elle düzeltildiid, agent_id, channel, is_test, created_at, duration_s, summary, cozum, kaynak (otomatik/elle), konu_duzeltme, konular, tagged_at
arama.planlandiGiden arama isteği planlandıGiden arama isteği (aşağıda)
arama.reddedildiİstek ön kontrolde reddedildiGiden arama isteği (sebep)
arama.tamamlandiİstek bitti: tamamlandi, basarisiz ya da iptalGiden arama isteği
arama.sonucGörüşmenin sonuç kodu yazıldıGiden arama isteği (sonuc_kodu, sonuc)
kupon.olusturulduAsistan görüşmede kupon oluşturduid, kod, tip, deger, gecerlilik, arama_id, call_id, siparis_no, created_at (e-posta yok)
testKonsoldaki Test göndermessage, endpoint_id

Giden arama isteği gövdesi: id, amac, tur, iys_kontrolu, kaynak, durum, sebep, planlanan, deneme, siparis_no, sepet_id, musteri (ad, eposta maskeli, telefon_maskeli), tetikleyen (eposta maskeli), call_id, sonuc_kodu, sonuc, parent_id, created_at, updated_at.

{
"id": "0199a1b2-7c3d-7e41-9f00-2b1c3d4e5f60",
"event": "request.created",
"created_at": "2026-09-24T10:15:02+00:00",
"data": {
"id": "0199a1b2-6a10-7b22-8c33-1d2e3f405162",
"number": "TLP-000123",
"call_id": "0199a1b0-1111-7222-8333-944455566677",
"kind": "adres_degisikligi",
"status": "acik",
"order_number": "98765",
"order_status": "processing",
"customer_name": "Ayşe Yılmaz",
"email": "[email protected]",
"phone": "+90 532 *** ** 67",
"details": {"yeni_adres": "…"},
"history": [],
"created_at": "2026-09-24T10:15:01+00:00",
"updated_at": "2026-09-24T10:15:01+00:00"
}
}

X-Zitena-Signature başlığı t=<unix saniye>,v1=<imza> biçimindedir. İmza, HMAC-SHA256(gizli, "<t>.<ham gövde>") değerinin onaltılık (hex) halidir. Doğrularken:

  1. Başlığı , ile bölün; t ve bir ya da daha fazla v1 değerini alın (gizli yenilendiğinde birden fazla v1 olabilir; herhangi biri eşleşirse geçerlidir).
  2. t’nin şimdiden en çok 300 saniye uzak olduğunu kontrol edin (tekrar oynatma koruması).
  3. Ham gövdeyi (JSON’u ayrıştırıp yeniden yazmadan) kullanarak beklenen imzayı hesaplayın ve sabit zamanlı karşılaştırın.
import crypto from 'node:crypto';
import express from 'express';
const SECRET = process.env.RZ_WEBHOOK_SECRET; // whsec_xxx
const app = express();
function verify(header, rawBody) {
if (!header) return false;
let t = null; const sigs = [];
for (const part of header.split(',')) {
const [k, v] = part.trim().split('=', 2);
if (k === 't' && /^\d+$/.test(v)) t = Number(v);
else if (k === 'v1' && v) sigs.push(v);
}
if (t === null || !sigs.length || Math.abs(Date.now() / 1000 - t) > 300) return false;
const expected = crypto.createHmac('sha256', SECRET).update(`${t}.`).update(rawBody).digest('hex');
return sigs.some((s) => s.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(s), Buffer.from(expected)));
}
app.post('/zitena', express.raw({ type: 'application/json' }), (req, res) => {
if (!verify(req.get('X-Zitena-Signature'), req.body)) return res.sendStatus(401);
const evt = JSON.parse(req.body.toString('utf8'));
// Aynı teslimat birden fazla gelebilir: evt.id'yi (X-Zitena-Delivery) saklayıp tekrarı atlayın.
res.sendStatus(204); // hızlı yanıt verin, işi kuyruğa alın
});
  • 2xx yanıt teslim sayılır. Zaman aşımı 10 saniye; yönlendirme izlenmez (3xx başarısızdır).
  • Başarısız teslimat 1 dk, 5 dk, 30 dk, 2 sa ve 12 sa sonra yeniden denenir (toplam 6 deneme); sonra “başarısız” olur. Konsoldan elle yeniden deneyebilirsiniz.
  • 24 saatten eski bekleyen teslimatlar gönderilmez (süresi doldu): olay bildirimi zamanında değilse anlamsızdır ve kişisel veri taşır.
  • Adres her gönderimde yeniden çözülür; özel/yerel IP’ye çıkan adrese istek atılmaz ve bu kalıcı hata sayılır (tekrar denenmez).
  • En az bir kez teslim: aynı teslimat birden fazla gelebilir. X-Zitena-Delivery (gövdedeki id) değerini saklayıp tekrarları atlayın. Olayların sırası garanti değildir; updated_at gibi zaman alanlarını kullanın.
  • Loglarda ve teslimat hatasında gövde, gizli anahtar ya da yanıt içeriği tutulmaz.