كيفية استخدام نقاط الويب (Webhooks)؟

Sojan

Sojan

آخر تحديث في Sep 8, 2026

الويبهوكس هي استدعاءات HTTP يتم إعدادها لكل حساب. يتم تفعيلها عند حدوث إجراءات مثل إنشاء رسالة في Chatwoot. يمكن إنشاء عدة ويبهوكس لحساب واحد.

كيف يمكن إضافة ويبهوك؟

الخطوة 1. انتقل إلى الإعدادات → التكاملات → الويبهوكس. اضغط على زر "تهيئة".

الخطوة 2. اضغط على زر "إضافة ويبهوك جديد". ستظهر نافذة منبثقة. هنا، أدخل عنوان URL الذي يجب إرسال طلب POST إليه. بعد ذلك، تحتاج إلى اختيار الأحداث التي ترغب في الاشتراك بها. هذا الخيار يسمح لك بالاستماع فقط للأحداث ذات الصلة في Chatwoot.

سيرسل Chatwoot طلب POST بالحمولة التالية إلى عناوين URL التي تم إعدادها لمختلف التحديثات في حسابك.

مثال على حمولة ويبهوك

{

  "event": "message_created", // اسم الحدث
  "id": "1", // معرف الرسالة
  "content": "Hi", // محتوى الرسالة
  "created_at": "2020-03-03 13:05:57 UTC", // وقت إرسال الرسالة
  "message_type": "incoming", // هذا سيكون نوع داخلي، خارجي أو قالب. المستخدم من الويدجت يرسل رسائل داخلية، والوكيل يرسل رسائل خارجية للمستخدم.
  "content_type": "enum", // هذا نوع تعداد، يمكن أن يكون input_select أو cards أو form أو نص. سيكون نوع الرسالة "template" إذا كان content_type هو أحد هذه القيم. القيمة الافتراضية هي نص
  "content_attributes": {} // سيكون كائنًا، القيم المختلفة معرفة أدناه
  "source_id": "", // سيكون المعرف الخارجي إذا كان البريد الوارد تكامل مع تويتر أو فيسبوك.
  "sender": { // تفاصيل الوكيل الذي أرسل الرسالة
    "id": "1",
    "name": "Agent",
    "email": "agent@example.com"
  },
  "contact": { // تفاصيل المستخدم الذي أرسل الرسالة
    "id": "1",
    "name": "contact-name"
  },
  "conversation": { // تفاصيل المحادثة
    "display_id": "1", // معرف المحادثة الذي يمكنك رؤيته في لوحة التحكم.
    "additional_attributes": {
      "browser": {
        "device_name": "Macbook",
        "browser_name": "Chrome",
        "platform_name": "Macintosh",
        "browser_version": "80.0.3987.122",
        "platform_version": "10.15.2"
      },
      "referer": "<http://www.chatwoot.com>",
      "initiated_at": "Tue Mar 03 2020 18:37:38 GMT-0700 (Mountain Standard Time)"
    }
  },
  "account": { // تفاصيل الحساب
    "id": "1",
    "name": "Chatwoot",
  }
}

الأحداث المدعومة في Chatwoot للويبهوك

ينشر Chatwoot أحداثًا مختلفة إلى نقاط نهاية الويبهوك المحددة. إذا كنت تريد إعداد ويبهوك، يمكنك الرجوع إلى الدليل هنا.

كل حدث له بنية حمولة خاصة به بناءً على نوع النموذج الذي يعمل عليه. يصف القسم التالي الكائنات الرئيسية التي نستخدمها في Chatwoot وخصائصها.

الكائنات

قد تتضمن حمولة الحدث أيًا من الكائنات التالية. أنواع الكائنات المختلفة التي يدعمها Chatwoot مبينة أدناه.

الحساب

{
  "id": "integer",
  "name": "string"
}

البريد الوارد

{
"id": "integer",
"name": "string"
}

جهة الاتصال

{
  "id": "integer",
  "name": "string",
  "avatar": "string",
  "type": "contact",
  "account": {
    // <...Account Object>
  }
}

المستخدم

{
  "id": "integer",
  "name": "string",
  "email": "string",
  "type": "user"
}

المحادثة

{
  "additional_attributes": {
    "browser": {
      "device_name": "string",
      "browser_name": "string",
      "platform_name": "string",
      "browser_version": "string",
      "platform_version": "string"
    },
    "referer": "string",
    "initiated_at": {
      "timestamp": "iso-datetime"
    }
  },
  "can_reply": "boolean",
  "channel": "string",
  "id": "integer",
  "inbox_id": "integer",
  "contact_inbox": {
    "id": "integer",
    "contact_id": "integer",
    "inbox_id": "integer",
    "source_id": "string",
    "created_at": "datetime",
    "updated_at": "datetime",
    "hmac_verified": "boolean"
  },
  "messages": ["Array of message objects"],
  "meta": {
    "sender": {
      // Contact Object
    },
    "assignee": {
      // User Object
    }
  },
  "status": "string",
  "unread_count": "integer",
  "agent_last_seen_at": "unix-timestamp",
  "contact_last_seen_at": "unix-timestamp",
  "timestamp": "unix-timestamp",
  "account_id": "integer"
}

الرسالة

{
  "id": "integer",
  "content": "string",
  "message_type": "integer",
  "created_at": "unix-timestamp",
  "private": "boolean",
  "source_id": "string / null",
  "content_type": "string",
  "content_attributes": "object",
  "sender": {
    "type": "string - contact/user"
    // User or Contact Object
  },
  "account": {
    // Account Object
  },
  "conversation": {
    // Conversation Object
  },
  "inbox": {
    // Inbox Object
  }
}

مثال على حمولة ويبهوك

{
  "event": "event_name"
  // خصائص تتعلق بالحدث
}

أحداث الويبهوك

يدعم Chatwoot أحداث الويبهوك التالية. يمكنك الاشتراك فيها أثناء إعداد الويبهوك في لوحة التحكم أو باستخدام واجهة البرمجة (API).

conversation_created

سيتم تفعيل هذا الحدث عند إنشاء محادثة جديدة في الحساب. حمولة الحدث كالتالي.

{
  "event": "conversation_created"
  // <...Conversation Attributes>
}

conversation_updated

سيتم تفعيل هذا الحدث عند حدوث تغيير في أي من خصائص المحادثة.

{
  "event": "conversation_updated",
  "changed_attributes": [
    {
      "<attribute_name>": {
        "current_value": "",
        "previous_value": ""
      }
    }
  ]
  // <...Conversation Attributes>
}

conversation_status_changed

سيتم تفعيل هذا الحدث عند تغيير حالة المحادثة.

ملاحظة: إذا كنت تستخدم واجهات البرمجة الخاصة بروبوت الوكلاء بدلاً من الويبهوكس، هذا الحدث غير مدعوم حالياً.

{
  "event": "conversation_status_changed"
  // <...Conversation Attributes>
}

message_created

سيتم تفعيل هذا الحدث عند إنشاء رسالة في محادثة. حمولة الحدث كالتالي.

{
  "event": "message_created"
  // <...Message Attributes>
}

message_updated

سيتم تفعيل هذا الحدث عند تحديث رسالة في محادثة. حمولة الحدث كالتالي.

{
  "event": "message_updated"
  // <...Message Attributes>
}

webwidget_triggered

سيتم تفعيل هذا الحدث عند فتح المستخدم النهائي لويدجت الدردشة المباشرة.

{
  "event": "webwidget_triggered",
  "id": "",
  "contact": {
    // <...Contact Object>
  },
  "inbox": {
    // <...Inbox Object>
  },
  "account": {
    // <...Account Object>
  },
  "current_conversation": {
    // <...Conversation Object>
  },
  "source_id": "string",
  "event_info": {
    "initiated_at": {
      "timestamp": "date-string"
    },
    "referer": "string",
    "widget_language": "string",
    "browser_language": "string",
    "browser": {
      "browser_name": "string",
      "browser_version": "string",
      "device_name": "string",
      "platform_name": "string",
      "platform_version": "string"
    }
  }
}

conversation_typing_on

يتم تفعيل هذا الحدث عندما يبدأ الوكيل بالكتابة في محادثة. يمكن أن تكون ملاحظة خاصة أو رسالة للعميل. يمكنك استخدام علم is_private للتمييز بينهما.

{
  "event": "conversation_typing_on",
  "conversation": { ...<Conversation Object> },
  "user": { ... <User / AgentBot / Captain Object> },
  "is_private": true
}

conversation_typing_off

يتم تفعيل هذا الحدث عندما يتوقف الوكيل عن الكتابة أو عند مغادرة نافذة المحادثة.

{
  "event": "conversation_typing_off",
  "conversation": { ...<Conversation Object> },
  "user": { ... <User / AgentBot / Captain Object> },
  "is_private": true
}

التحقق من الويبهوكس

يقوم Chatwoot بتوقيع كل طلب ويبهوك صادر حتى يتمكن الخادم لديك من التحقق من أن الحمولة تم إرسالها من قبل Chatwoot وأنها لم يتم العبث بها. يظهر السر لك عند إنشاء الويبهوك، ويمكنك مشاهدته مرة أخرى في نموذج تحرير الويبهوك.

يرسل كل طلب ويبهوك الرؤوس التالية، والتي يمكن استخدامها لحساب توقيع HMAC الخاص بالحمولة

  • X-Chatwoot-Signature: توقيع HMAC-SHA256 مسبوق بـ sha256=

  • X-Chatwoot-Timestamp: الطابع الزمني (ثواني) عند توقيع الطلب

  • X-Chatwoot-Delivery: معرف تسليم فريد لحدث الويبهوك (عند توفره)

يتم احتساب التوقيع كما يلي:

sha256=HMAC-SHA256(webhook_secret, "{timestamp}.{raw_body}")

حيث:

  • webhook_secret هو السر المرتبط بالويبهوك

  • timestamp هو قيمة رأس X-Chatwoot-Timestamp

  • raw_body هو نص الطلب JSON الخام (غير محلل/غير مُعاد تسلسله)

خطوات التحقق

  1. استخرج X-Chatwoot-Signature و X-Chatwoot-Timestamp من رؤوس الطلب

  2. اقرأ نص الطلب الخام كبايتات (لا تقم بتحليل وإعادة تسلسلها)

  3. احسب التوقيع المتوقع: sha256=HMAC-SHA256(secret, "{timestamp}.{raw_body}")

  4. قارن التوقيع المحسوب مع التوقيع المستلم باستخدام مقارنة وقت ثابت

  5. اختياريًا، ارفض الطلبات التي يكون طابعها الزمني قديمًا جدًا لمنع هجمات إعادة الطلب

أمثلة

روبي

def verify_signature(raw_body, timestamp, received_signature, secret)
  expected = "sha256=#{OpenSSL::HMAC.hexdigest('SHA256', secret, "#{timestamp}.#{raw_body}")}"
  ActiveSupport::SecurityUtils.secure_compare(expected, received_signature)
end

بايثون

import hmac
import hashlib

def verify_signature(raw_body: bytes, timestamp: str, received_signature: str, secret: str) -> bool:
    message = f"{timestamp}.".encode() + raw_body
    expected = "sha256=" + hmac.new(secret.encode(), message, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, received_signature)

Node.js


const crypto = require("crypto");

function verifySignature(rawBody, timestamp, receivedSignature, secret) {
  const message = `${timestamp}.${rawBody}`;
  const expected =
    "sha256=" + crypto.createHmac("sha256", secret).update(message).digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(receivedSignature)
  );
}

Go

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
)

func verifySignature(rawBody []byte, timestamp, receivedSignature, secret string) bool {
	mac := hmac.New(sha256.New, []byte(secret))
	mac.Write([]byte(fmt.Sprintf("%s.%s", timestamp, rawBody)))
	expected := "sha256=" + hex.EncodeToString(mac.Sum(nil))
	return hmac.Equal([]byte(expected), []byte(receivedSignature))
}

ملاحظات هامة

  • استخدم دائمًا نص الطلب الخام للتحقق. تحليل JSON وإعادة تسلسله قد يغير ترتيب المفاتيح أو الفراغات أو ترميز يونيكود، مما سيؤدي إلى توقيع مختلف.

  • استخدم دائمًا مقارنة وقت ثابت (مثل hmac.compare_digest، crypto.timingSafeEqual، ActiveSupport::SecurityUtils.secure_compare) لمنع هجمات التوقيت.

  • فكر في رفض الطلبات التي تحمل طوابع زمنية أقدم من 5 دقائق لتقليل مخاطر هجمات إعادة الإرسال.