Webhooks والتحقق من التوقيع
استقبل الأحداث من Campify في نظامك، وتحقق من أنها منا ومن أنها حديثة.
- contact.created — أُنشئت جهة اتصال
- consent.changed — تغيّرت موافقة
- campaign.published — اعتُمدت حملة
- campaign.started — بدأت حملة
- journey.enrolled — دخل عميل مساراً
- message.sent — أُرسلت رسالة
- conversion.recorded — سُجّل تحويل
- sales_task.created — أُنشئت مهمة مبيعات
- journey.webhook_triggered — عقدة Webhook في مسار
يحمل كل طلب الترويسات x-campify-event وx-campify-delivery وx-campify-signature. التوقيع بالصيغة t=<ثوانٍ>,v1=<HMAC-SHA256> على النص `${t}.${body}` بالسر الذي ظهر عند إنشاء الاشتراك. ارفض أي طلب بتوقيع غير صحيح أو أقدم من خمس دقائق.
import { createHmac, timingSafeEqual } from 'node:crypto';
// rawBody: the request body exactly as received, before JSON.parse.
export function verifyCampifySignature(secret, rawBody, header, toleranceSeconds = 300) {
const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
const t = Number.parseInt(parts.t ?? '', 10);
if (!Number.isInteger(t) || !parts.v1) return false;
if (Math.abs(Math.floor(Date.now() / 1000) - t) > toleranceSeconds) return false;
const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest();
const got = Buffer.from(parts.v1, 'hex');
return got.length === expected.length && timingSafeEqual(got, expected);
}أعد الرد بأي رمز 2xx خلال عشر ثوانٍ. أي رد آخر يُعاد إرساله لاحقاً، ويمكنك إعادة إرسال أي تسليم يدوياً من صفحة الاشتراك ورؤية الرد.