Webhooks

Webhook Konektor mengirim event secara asynchronous ketika perubahan lead terjadi. Delivery menggunakan queue, sehingga integrasi Anda harus mengasumsikan model at-least-once delivery.

Header Webhook

Setiap request webhook menyertakan header:

  1. Content-Type: application/json
  2. X-Konektor-Signature: t=<unix_timestamp>,v1=<hex_hmac_sha256>
  3. X-Konektor-Event: <event_name>
  4. User-Agent: Konektor-Webhook/1.0

Event yang Dikirim

Event utama pada flow lead:

  1. lead.created
  2. lead.updated

Payload body berisi objek event langsung (bukan envelope tambahan).

Contoh lead.created

{
  "lead": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "uniqueCode": "API_1A2B3C4D",
    "externalRef": "crm-001",
    "firstName": "Budi",
    "email": "budi@example.com",
    "phone": "6281234567890",
    "status": "new",
    "priority": "medium",
    "city": null,
    "country": null
  },
  "source": "api"
}

Contoh lead.updated

{
  "lead": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "uniqueCode": "API_1A2B3C4D",
    "status": "qualified"
  },
  "leadId": "550e8400-e29b-41d4-a716-446655440000",
  "previousStatus": "new",
  "newStatus": "qualified",
  "changes": ["status"],
  "source": "api"
}

Verifikasi Signature (Timing-Safe)

Gunakan raw body request saat menghitung HMAC. Jangan pakai body yang sudah di-parse lalu di-stringify ulang.

import crypto from 'node:crypto'

function verifyKonektorSignature(rawBody, signatureHeader, secret) {
  const parts = signatureHeader.split(',')
  const timestamp = parts.find(p => p.startsWith('t='))?.slice(2)
  const signature = parts.find(p => p.startsWith('v1='))?.slice(3)

  if (!timestamp || !signature) return false

  const now = Math.floor(Date.now() / 1000)
  if (Math.abs(now - Number(timestamp)) > 300) return false

  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${timestamp}.${rawBody}`)
    .digest('hex')

  const providedBuf = Buffer.from(signature, 'hex')
  const expectedBuf = Buffer.from(expected, 'hex')

  if (providedBuf.length !== expectedBuf.length) return false
  return crypto.timingSafeEqual(providedBuf, expectedBuf)
}

Idempotensi

Webhook dikirim via queue dan bisa terkirim ulang saat retry. Endpoint Anda harus idempotent:

  1. Simpan event key internal (misalnya kombinasi leadId + updatedAt + event).
  2. Abaikan event duplikat yang sudah diproses.
  3. Selalu balas 2xx jika event valid sudah pernah diproses.

Timeout dan Respons

Konektor mengirim webhook dengan timeout request singkat (5s). Endpoint receiver sebaiknya:

  1. Validasi signature.
  2. Enqueue pekerjaan berat ke worker internal.
  3. Segera balas 200 OK.

Catatan Keamanan

  1. Simpan webhook secret di server-side secret manager.
  2. Rotasi secret secara berkala.
  3. Tolak request tanpa header signature valid.
  4. Terapkan allowlist IP jika infrastruktur Anda membutuhkannya.

Butuh Bantuan Lebih Lanjut?

Tim kami siap membantu Anda memaksimalkan tracking iklan dan atribusi bisnis.

Email Supportsupport@konektor.id
YouTubeYouTube

© 2026 Konektor. Seluruh hak cipta dilindungi.