Webhook Entegrasyonu
Bu rehber, Sosyal Köprü webhook sistemini projenize entegre etmenizi adım adım anlatır.
Webhook Endpoint’i Hazırlayın
Sosyal Köprü’nün POST isteklerini alacak bir HTTPS URL’i hazırlayın.
Webhook URL’i HTTPS olmalı ve yerel IP adreslerine yönlendirme yapmamalıdır. Geliştirme ortamında ngrok veya localtunnel kullanabilirsiniz.
Temel endpoint kodu:
Node.js (Express)
import express from 'express'
import crypto from 'crypto'
const app = express()
const SECRET = process.env.SOSYALKOPRU_WEBHOOK_SECRET
// ⚠️ Ham body için express.raw kullanın (json() değil)
app.use('/webhooks/sosyalkopru', express.raw({ type: 'application/json' }))
app.post('/webhooks/sosyalkopru', (req, res) => {
// İmzayı doğrula
const gelen = req.headers['x-sosyalkopru-signature'] ?? ''
const beklenen = 'sha256=' + crypto
.createHmac('sha256', SECRET)
.update(req.body)
.digest('hex')
if (!crypto.timingSafeEqual(Buffer.from(gelen), Buffer.from(beklenen))) {
return res.status(401).json({ error: 'İmza geçersiz' })
}
// Olayı işle
const olay = JSON.parse(req.body.toString())
console.log(`[WEBHOOK] ${olay.event}:`, olay.data?.postId)
// Hemen 200 dön, işlemi arka planda yap
res.status(200).json({ received: true })
// Arka plan işlemi
setImmediate(() => olayIisle(olay))
})
async function olayIisle(olay) {
switch (olay.event) {
case 'post.publishing':
console.log('Yayınlanıyor:', olay.data.postId)
break
case 'post.published':
console.log('Gönderi yayınlandı:', olay.data.postId)
// Veritabanını güncelle, bildirim gönder vb.
break
case 'post.failed':
console.error('Gönderi başarısız:', olay.data.postId)
// Hata raporla, yeniden dene vb.
break
case 'post.scheduled':
console.log('Gönderi planlandı:', olay.data.postId)
break
case 'post.updated':
console.log('Gönderi güncellendi:', olay.data.postId)
break
}
}
app.listen(3000, () => console.log('Webhook sunucusu çalışıyor: :3000'))Webhook Kaydedin
Hazırladığınız URL’i API üzerinden kaydedin:
const response = await fetch('https://api.sosyalkopru.com/v1/webhooks', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.SOSYALKOPRU_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
url: 'https://sizin-alan-adiniz.com/webhooks/sosyalkopru',
events: ['post.publishing', 'post.published', 'post.failed', 'post.scheduled'],
description: 'Üretim Webhook',
}),
})
const { data } = await response.json()
console.log('Webhook ID:', data.id)
// ⚠️ Bu değeri güvenli saklayın — bir daha gösterilmez!
process.env.SOSYALKOPRU_WEBHOOK_SECRET = data.secret
console.log('Secret kaydedildi')Test Ping Gönderin
Webhook’unuzun düzgün çalıştığını test edin:
const webhookId = 'wh_...' // kayıt adımından
const response = await fetch(
`https://api.sosyalkopru.com/v1/webhooks/${webhookId}/test`,
{
method: 'POST',
headers: { 'Authorization': `Bearer ${process.env.SOSYALKOPRU_API_KEY}` },
}
)
const { data } = await response.json()
console.log('Test sonucu:', data.success ? '✓ Başarılı' : '✗ Başarısız')
console.log('HTTP kodu:', data.statusCode)Sunucu loglarınızda [WEBHOOK] webhook.test: mesajını görmelisiniz.
Üretim Gönderisi Yapın
Gerçek bir gönderi oluşturun ve webhook’unuzun post.published veya post.failed olayını aldığını doğrulayın:
const post = await fetch('https://api.sosyalkopru.com/v1/posts', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.SOSYALKOPRU_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
platforms: ['instagram'],
content: { text: 'Webhook testi! #sosyalkopru' },
accountIds: ['acc_...'],
// Anlık yayın için scheduling vermeyin
}),
}).then(r => r.json())
console.log('Gönderi ID:', post.data.id, '— webhook bekleyiniz...')Önerilen Pratikler
15 Saniye Kuralı
Webhook endpoint’iniz 15 saniye içinde 2xx yanıt dönmelidir. Uzun süren işlemleri arka plana alın (queue, işçi süreci).
İdempotensi
Ağ sorunları nedeniyle aynı webhook birden fazla kez teslim edilebilir. X-SosyalKopru-Delivery başlığını kullanarak tekrarları tespit edin:
const deliveryId = req.headers['x-sosyalkopru-delivery']
const zatenIslendi = await redis.setnx(`webhook:${deliveryId}`, '1', 'EX', 86400)
if (!zatenIslendi) {
return res.status(200).json({ received: true, duplicate: true })
}Olay Türlerini Filtreleyin
const DESTEKLENEN_OLAYLAR = new Set(['post.published', 'post.failed'])
if (!DESTEKLENEN_OLAYLAR.has(olay.event)) {
console.log('Bilinmeyen olay:', olay.event)
return // Sessizce yok say
}Webhook Payload Yapısı
{
"event": "post.published",
"timestamp": "2025-06-10T12:00:00.000Z",
"data": {
"postId": "post_01HZGK9P3QABC",
"status": "PUBLISHED",
"platforms": [
{
"platform": "instagram",
"status": "PUBLISHED",
"platformPostUrl": "https://instagram.com/p/ABC123"
}
]
}
}