İçeriğe geç
ZZenWapp Docs

Webhook ve entegrasyon

Webhook rehberi

Webhook, gelen mesajları ve teslimat durumlarını anlık olarak sizin sisteminize iletir. Sürekli sorgulama yapmak yerine bunu kullanın.

1. Webhook tanımlayın

Uç noktanızı kaydedin. Production ortamında URL HTTPS olmak zorundadır.

curl -X POST "https://api.zenwapp.com/api/v1/whatsapp/external/webhooks" \
  -H "Authorization: Bearer $ZENWAPP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://sizin-sunucunuz.com/zenwapp/webhook",
    "events": ["message.received", "message.status"],
    "timeout_seconds": 30
  }'

2. Olay tipleri

OlayNe zaman tetiklenir
message.receivedHesaba yeni bir mesaj geldiğinde.
message.sentGiden mesaj kanala iletildiğinde.
message.statusTeslimat durumu değiştiğinde (iletildi, okundu).
connection.connectedKanal bağlantısı kurulduğunda.
connection.disconnectedKanal bağlantısı koptuğunda.

Teslimat sırasında durum olayları message.delivered ve message.read alt tipleriyle de görünebilir. Bilinmeyen bir olay tipi geldiğinde hata vermeyin — sessizce yok sayın; ileride yeni tipler eklenebilir.

3. İstek başlıkları

ZenWapp her çağrıda şu başlıkları gönderir:

Başlıkİçerik
X-Zenwapp-SignatureGövdenin HMAC-SHA256 imzası (hex).
X-Zenwapp-TimestampUnix zaman damgası (saniye).
X-Zenwapp-EventOlay tipi.
X-Zenwapp-Event-IdBenzersiz olay kimliği (tekrar tespiti için).
X-Zenwapp-Account-IdOlayın ait olduğu kanal hesabı.
User-AgentZenwapp-Webhook/1.0

4. İmzayı doğrulayın

İmza, ham istek gövdesi üzerinden hesaplanır. Gövdeyi JSON'a çevirdikten sonra yeniden serileştirirseniz imza tutmaz — framework'ünüzde ham gövdeyi saklayın.

const crypto = require('crypto')
const express = require('express')

const app = express()

// Ham gövdeyi sakla — imza bunun üzerinden hesaplanıyor.
app.use('/zenwapp/webhook', express.raw({ type: 'application/json' }))

function verify(rawBody, signature, secret) {
  const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex')
  const received = Buffer.from(signature || '', 'utf8')
  const computed = Buffer.from(expected, 'utf8')
  // Uzunluk farklıysa timingSafeEqual istisna atar; önce kontrol et.
  if (received.length !== computed.length) return false
  return crypto.timingSafeEqual(received, computed)
}

app.post('/zenwapp/webhook', (req, res) => {
  const signature = req.get('X-Zenwapp-Signature')
  const timestamp = Number(req.get('X-Zenwapp-Timestamp'))

  if (!verify(req.body, signature, process.env.ZENWAPP_WEBHOOK_SECRET)) {
    return res.status(401).send('invalid signature')
  }

  // Replay koruması: 5 dakikadan eski olayları reddet.
  if (!Number.isFinite(timestamp) || Math.abs(Date.now() / 1000 - timestamp) > 300) {
    return res.status(401).send('stale timestamp')
  }

  const event = JSON.parse(req.body.toString('utf8'))

  // Önce 200 dön, ağır işi kuyruğa al.
  res.sendStatus(200)
  enqueue(event)
})

İmza doğrulaması isteğe bağlı değildir

Doğrulama yapmayan bir uç nokta, sizin adınıza sahte mesaj olayları enjekte edilmesine açıktır. Secret'ı POST /webhooks/rotate-secret ile alın ve secret yöneticinizde saklayın.

5. Örnek gövdeler

{
  "event": "message.received",
  "account_id": "b3d1e009-...",
  "chat": {
    "id": "[email protected]",
    "name": "Ahmet Yılmaz",
    "phone": "905551234567",
    "type": "individual"
  },
  "message": {
    "id": "3EB0A1B2C3",
    "from": "[email protected]",
    "to": "[email protected]",
    "body": "Merhaba, fiyat listesi alabilir miyim?",
    "type": "chat",
    "raw_type": "conversation",
    "timestamp": 1785400000,
    "from_me": false,
    "has_media": false,
    "media": null
  }
}

6. Test edin

Canlı trafiği beklemeden kurulumunuzu sınayın — bu uç kayıtlı URL'inize örnek bir olay gönderir:

curl -X POST "https://api.zenwapp.com/api/v1/whatsapp/external/webhooks/test" \
  -H "Authorization: Bearer $ZENWAPP_API_KEY"

Uç nokta tasarım kuralları

  • Hızlı yanıt verin. Önce 200 dönün, işi kuyruğa alın. Yanıt süresi timeout_seconds değerini aşarsa teslimat başarısız sayılır.
  • Tekrarlı teslimata hazır olun. Aynı olay yeniden gönderilebilir; X-Zenwapp-Event-Id değerini saklayıp mükerrer işlemeyi engelleyin.
  • Sıra garantisi varsaymayın. Olaylar sırasız gelebilir; karar verirken timestamp alanına bakın.
  • Bilinmeyen alanları yok sayın. Gövdeye zamanla yeni alanlar eklenir; katı şema doğrulaması entegrasyonunuzu kırar.
  • Hata durumunda 5xx dönün. Böylece teslimat başarısız kabul edilir; 200 dönerseniz olay kaybolur.