الانتقال إلى محتوى الصفحة
الوثائق
وثائق Make Agent Fast

Webhooks

سجّل نقطة نهاية عامة، وتحقق من الحمولات الخام الموقّعة، وأزل تكرار الأحداث، وتعامل مع إعادة المحاولات بأمان.

نظرة سريعة

سجّل نقطة نهاية عامة، وتحقق من الحمولات الخام الموقّعة، وأزل تكرار الأحداث، وتعامل مع إعادة المحاولات بأمان.

تسليم Webhookأحداث موقّعة تخرج من المنصة إلى نقطة النهاية لديك
حدث المنصةتوقيعHMACHTTPS POSTتطبيقك
HMAC-SHA256مرة واحدة على الأقل8 محاولات

ترسل Webhooks الخاصة بالمطورين أحداث الحساب إلى الخادم لديك، فلا تحتاج إلى الاستعلام الدوري. التسليم يتم مرة واحدة على الأقل: قد تتكرر الأحداث أو تتأخر أو تصل بترتيب مختلف.

تسجيل نقطة نهاية#

أنشئ مفتاحًا بالصلاحية webhooks:write، ثم سجّل مستقبِلًا عامًا عبر HTTPS مع أصغر مجموعة أحداث تحتاج إليها.

curl --fail-with-body https://makeagent.fast/api/v1/webhook-endpoints \
  -X POST \
  -H "Authorization: Bearer $MAF_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: webhook-production-v1" \
  -d '{
    "url": "https://api.example.com/webhooks/make-agent-fast",
    "events": ["lead.created", "conversation.started"]
  }'

يجب أن يستخدم عنوان URL بروتوكول HTTPS، ولا يجوز أن يحتوي على اسم مستخدم أو كلمة مرور أو جزء (fragment) أو منفذ مخصص، ويجب أن يُحلَّ إلى عناوين IP عامة فقط. لا تُتبع عمليات إعادة التوجيه أثناء التسليم.

تكشف الاستجابة 201 عن سر التوقيع whsec_... مرة واحدة فقط. خزّنه في مدير الأسرار الخاص بالمستقبِل قبل إغلاق الاستجابة. عند عرض نقاط النهاية لاحقًا ستحصل على عنوان URL والأحداث والحالة وآخر عملية تسليم وآخر خطأ، لكن دون السر.

أنواع الأحداث#

الحدثيُرسَل عندما
site.publishedيصبح الموقع منشورًا
site.unpublishedيعود الموقع إلى حالة المسودة
lead.createdيلتقط الـ agent عميلًا محتملًا (Lead) جديدًا
lead.qualifiedيؤهّل الـ agent عميلًا محتملًا، أو يُقبل العميل المحتمل في مسار المبيعات
booking.requestedيطلب زائر موعدًا أو يحجزه
handoff.requestedيحوّل الـ agent محادثة إلى شخص (Handoff)
opportunity.createdيتحول عميل محتمل إلى فرصة في مسار المبيعات
opportunity.updatedيتغير إسناد الفرصة أو قيمتها أو إجراؤها التالي أو حقول أخرى فيها
opportunity.stage_changedتنتقل الفرصة إلى مرحلة أخرى
opportunity.wonتُغلق الفرصة كصفقة رابحة
opportunity.lostتُغلق الفرصة كصفقة خاسرة
conversation.startedتبدأ سلسلة محادثة جديدة
conversation.message.createdتُضاف رسالة إلى محادثة
knowledge.readyيكتمل تجهيز مصدر معرفة (Source)
broadcast.sentتنتهي رسالة جماعية من سير عمل الإرسال
domain.activatedحدث متقاعد: النطاقات المخصصة غير متاحة، ولا يُرسَل هذا الحدث أبدًا

تنسيق الطلب#

يرسل Make Agent Fast طلب POST مع Content-Type: application/json وUser-Agent: MakeAgentFast-Webhooks/1.0 والترويسات التالية:

maf-event-id: evt_...
maf-event-type: lead.created
maf-signature: t=1784210566,v1=HEX_HMAC_SHA256

يتخذ نص JSON غلافًا ثابتًا. تعتمد الحقول داخل data على الحدث، ويمكن أن تُضاف إليها حقول جديدة.

{
  "id": "evt_2c34...",
  "type": "lead.created",
  "created_at": "2026-07-16T10:02:46.000Z",
  "data": {
    "site_id": "SITE_ID",
    "lead_id": "LEAD_ID"
  }
}

استخدم id من النص أو maf-event-id مفتاحًا لإزالة التكرار. لا تستخدم وقت التسليم ولا معرّف قاعدة بيانات مولَّدًا.

التحقق من التوقيع في Node.js#

اقرأ البايتات الخام كما وصلت قبل تحليل JSON. القيمة الموقّعة هي TIMESTAMP + "." + RAW_BODY.

import { createHmac, timingSafeEqual } from "node:crypto";

export function verifyWebhook(rawBody: Buffer, header: string, secret: string) {
  const values = Object.fromEntries(header.split(",").map((part) => part.split("=", 2)));
  const timestamp = values.t;
  const supplied = values.v1;
  if (!timestamp || !supplied || !/^[a-f0-9]{64}$/.test(supplied)) return false;

  const age = Math.abs(Date.now() / 1_000 - Number(timestamp));
  if (!Number.isFinite(age) || age > 300) return false;

  const expected = createHmac("sha256", secret)
    .update(`${timestamp}.`)
    .update(rawBody)
    .digest("hex");
  return timingSafeEqual(Buffer.from(expected, "hex"), Buffer.from(supplied, "hex"));
}

ارفض التوقيعات المشوّهة والطوابع الزمنية الأقدم من نافذة إعادة التشغيل (replay) المقبولة لديك؛ وخمس دقائق قيمة افتراضية معقولة. قارن البايتات ذات الطول الثابت بزمن ثابت.

التحقق من التوقيع في Python#

import hashlib
import hmac
import time

def verify_webhook(raw_body: bytes, header: str, secret: str) -> bool:
    values = dict(part.split("=", 1) for part in header.split(",") if "=" in part)
    timestamp = values.get("t", "")
    supplied = values.get("v1", "")
    try:
        if abs(time.time() - int(timestamp)) > 300:
            return False
    except ValueError:
        return False

    signed = timestamp.encode() + b"." + raw_body
    expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, supplied)

لا تحلّل JSON ولا تعالجه إلا بعد نجاح التحقق من التوقيع.

الإقرار والمعالجة#

  1. تحقق من التوقيع والطابع الزمني.
  2. أدرج معرّف الحدث في جدول بقيد تفرّد (unique constraint).
  3. إذا كان موجودًا مسبقًا، فأعد 204 دون تكرار الأثر الجانبي.
  4. ثبّت الحدث (commit) أو أضف مهمتك الداخلية إلى قائمة الانتظار.
  5. أعد استجابة 2xx بسرعة.

ينتهي مهلة المرسِل في Make Agent Fast بعد 10 ثوانٍ. ويعدّ استجابات 2xx فقط ناجحة، ولا يتبع عمليات إعادة التوجيه.

سلوك إعادة المحاولة#

توضع عمليات التسليم الفاشلة في قائمة انتظار بحد أقصى ثماني محاولات. يبدأ التأخير التراجعي (backoff) عند نحو ثانيتين، ويتضاعف مع تشويش عشوائي (jitter)، ويبلغ حده الأقصى ساعة واحدة؛ وقد يتأخر وقت التسليم الفعلي عندما تكون العمليات المنفِّذة مشغولة. ولأن إعادة المحاولات قد تتجاوز عمر الطلب الذي أطلقها وقد تصل بترتيب مختلف، فلا تعتمد أبدًا على وصول حدث ما مباشرة قبل حدث آخر.

أعد استجابة غير 2xx فقط عندما تريد أن يعيد Make Agent Fast المحاولة. وفي حالة إصدار حدث غير مدعوم نهائيًا أو وجهة محذوفة، اقبل الحدث وسجّله أو احذف نقطة النهاية، بدلًا من إنتاج إخفاقات مؤقتة لا تنتهي.

تدوير سر التوقيع#

لا يمكن كشف أسرار التوقيع ولا تعديلها. لتدويرها بأمان:

  1. أنشئ نقطة نهاية ثانية تشير إلى مسار مستقبِل مؤقت أو مُرقَّم بإصدار.
  2. خزّن السر الجديد الذي كُشف لك.
  3. اقبل الأحداث من نقطتي النهاية معًا مع إزالة التكرار.
  4. تأكد أن نقطة النهاية الجديدة تتلقى عمليات تسليم صالحة.
  5. احذف نقطة النهاية القديمة عبر DELETE /webhook-endpoints/{endpoint_id}.

إذا بقي عنوان URL الخاص بالمستقبِل كما هو، فاجعل التطبيق المستقبِل يقبل السرّين خلال فترة التداخل، واستخدم معرّفات الأحداث لمنع تكرار الآثار الجانبية.

استكشاف الأخطاء وإصلاحها#

العَرَضما يجب فحصه
لا توجد عمليات تسليمحالة نقطة النهاية، والأحداث المحددة، وDNS العام، وشهادة HTTPS، وهل وقع الحدث فعلًا
عدم تطابق التوقيعالوصول إلى النص الخام، والتسلسل الدقيق timestamp.body، وسر نقطة النهاية الصحيح، وأي تحويلات يجريها الوكيل (proxy) على النص
عمليات تسليم متكررةرمز الاستجابة، ومهلة 10 ثوانٍ، والاستثناءات الداخلية، وتفرّد معرّف الحدث
خطأ عنوان خاصيجب أن تُحلّ سجلات DNS إلى عناوين عامة فقط؛ يُرفض localhost والنطاقات الداخلية
فشل إعادة التوجيهسجّل عنوان HTTPS النهائي مباشرة؛ لا تُتبع عمليات إعادة التوجيه

لا تضمّن سر التوقيع أو مفتاح bearer أو الحمولة الكاملة للزائر في أي رسالة إلى الدعم. أرفق معرّف نقطة النهاية ومعرّف الحدث ووقت الفشل وسجلات المستقبِل بعد تنقيتها.