كيفية استخدام الويب هوكس؟
الويب هوكس هي استدعاءات HTTP يتم إعدادها لكل حساب. يتم تشغيلها عند حدوث إجراءات مثل إنشاء رسالة في Voxys Connect. يمكن
إنشاء عدة ويب هوكس لحساب واحد.
كيفية إضافة ويب هوك؟
الخطوة 1. انتقل إلى الإعدادات → التكاملات → الويب هوكس. انقر على زر "تكوين".
الخطوة 2. انقر على زر "إضافة ويب هوك جديد". ستفتح نافذة منبثقة. هنا، أدخل عنوان URL الذي يجب إرسال طلب POST إليه. بعد
ذلك، عليك تحديد الأحداث التي تريد الاشتراك فيها. سيسمح لك هذا الخيار بالاستماع فقط إلى الأحداث ذات الصلة في Voxys
Connect.
سيرسل Voxys Connect طلب POST مع الحمولة التالية إلى عناوين URL المكونة لمختلف التحديثات في حسابك.
نموذج لحمولة webhook
{
"event": "message_created", // اسم الحدث
"id": "1", // معرف الرسالة
"content": "Hi", // محتوى الرسالة
"created_at": "2020-03-03 13:05:57 UTC", // الوقت الذي تم فيه إرسال الرسالة
"message_type": "incoming", // سيكون هذا من النوع incoming أو outgoing أو template. يرسل المستخدم من الأداة الرسائل الواردة، ويرسل الوكيل الرسائل الصادرة إلى المستخدم.
"content_type": "enum", // هذا هو enum، ويمكن أن يكون input_select أو cards أو form أو text. سيكون message_type هو template إذا كان content_type أحد هذه الخيارات. القيمة الافتراضية هي text
"content_attributes": {} // سيكون هذا كائنًا، ويتم تعريف القيم المختلفة أدناه
"source_id": "", // سيكون هذا المعرف الخارجي إذا كان صندوق الوارد عبارة عن تكامل مع Twitter أو Facebook.
"sender": { // سيوفر هذا تفاصيل الوكيل الذي أرسل هذه الرسالة
"id": "1",
"name": "Agent",
"email": "[email protected]"
},
"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",
}
}
أحداث webhook المدعومة في Voxys Connect
ينشر Voxys Connect أحداثًا متنوعة إلى نقاط نهاية webhook المكونة. إذا كنت ترغب في تكوين webhook، فراجع الدليل هنا.
لكل حدث بنية حمولة خاصة به بناءً على نوع النموذج الذي يعمل عليه. يصف القسم التالي الكائنات الرئيسية التي نستخدمها في
Voxys Connect وسماتها.
الكائنات
قد تتضمن حمولة الحدث أيًا من الكائنات التالية. وفيما يلي قائمة بأنواع الكائنات المختلفة التي يدعمها Voxys Connect.
الحساب
{
"id": "عدد صحيح",
"name": "سلسلة"
}
صندوق الوارد
{
"id": "عدد صحيح",
"name": "سلسلة"
}
جهة الاتصال
{
"id": "integer",
"name": "string",
"avatar": "string",
"type": "contact",
"account": {
// <...كائن الحساب>
}
}
المستخدم
{
"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": "سلسلة"،
"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": ["مصفوفة من كائنات الرسائل"],
"meta": {
"sender": {
// كائن جهة الاتصال
},
"assignee": {
// كائن المستخدم
}
},
"status": "سلسلة"،
"unread_count": "عدد صحيح"،
"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"
// كائن المستخدم أو جهة الاتصال
},
"account": {
// كائن الحساب
},
"conversation": {
// كائن المحادثة
},
"inbox": {
// كائن صندوق الوارد
}
}
نموذج لحمولة webhook
{
"event": "event_name"
// السمات المتعلقة بالحدث
}
أحداث Webhook
يدعم Voxys Connect أحداث Webhook التالية. يمكنك الاشتراك فيها أثناء تكوين Webhook في لوحة التحكم أو باستخدام واجهة برمجة
التطبيقات (API).
conversation_created
سيتم تشغيل هذا الحدث عند إنشاء محادثة جديدة في الحساب. حمولة الحدث هي كما يلي.
{
"event": "conversation_created"
// <...سمات المحادثة>
}
conversation_updated
سيتم تشغيل هذا الحدث عند حدوث تغيير في أي من سمات المحادثة.
{
"event": "conversation_updated",
"changed_attributes": [
{
"<attribute_name>": {
"current_value": "",
"previous_value": ""
}
}
]
// <...سمات المحادثة>
}
conversation_status_changed
سيتم تشغيل هذا الحدث عند تغيير حالة المحادثة.
ملاحظة: إذا كنت تستخدم واجهات برمجة تطبيقات (API) لروبوتات الوكلاء بدلاً من webhooks، فإن هذا الحدث غير مدعوم حتى الآن.
{
"event": "conversation_status_changed"
// <...سمات المحادثة>
}
message_created
سيتم تشغيل هذا الحدث عند إنشاء رسالة في محادثة. فيما يلي الحمولة الخاصة بالحدث.
{
"event": "message_created"
// <...سمات الرسالة>
}
message_updated
سيتم تشغيل هذا الحدث عند تحديث رسالة في محادثة. فيما يلي الحمولة الخاصة بالحدث.
{
"event": "message_updated"
// <...سمات الرسالة>
}
webwidget_triggered
سيتم تشغيل هذا الحدث عندما يفتح المستخدم النهائي أداة الدردشة المباشرة.
{
"event": "webwidget_triggered",
"id": "",
"contact": {
// <...كائن جهة الاتصال>
},
"inbox": {
// <...كائن صندوق الوارد>
},
"account": {
// <...كائن الحساب>
},
"current_conversation": {
// <...كائن المحادثة>
},
"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
}
يقوم Voxys Connect بتوقيع كل طلب webhook صادر حتى يتمكن الخادم الخاص بك من التحقق من أن الحمولة قد تم إرسالها بواسطة
Voxys Connect ولم يتم العبث بها. يتم عرض السر لك بمجرد إنشاء webhook، ويمكنك مشاهدته مرة أخرى في نموذج تعديل webhook.
يرسل كل طلب webhook الرؤوس التالية، والتي يمكن استخدامها لحساب توقيع HMAC للحمولة
- X-Chatwoot-Signature: توقيع HMAC-SHA256 مسبوق بـ sha256=
- X-Chatwoot-Timestamp: طابع زمني Unix (بالثواني) عند توقيع الطلب
- X-Chatwoot-Delivery: معرف تسليم فريد لحدث webhook (عند توفره)
يتم حساب التوقيع على النحو التالي:
sha256=HMAC-SHA256(webhook_secret, "{timestamp}.{raw_body}")
حيث:
- webhook_secret هو السر المرتبط بـ webhook
- 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. اختياريًا، ارفض الطلبات التي يكون الطابع الزمني فيها قديمًا جدًا لمنع هجمات إعادة التشغيل
أمثلة
Ruby
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
Python
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 وإعادة تسلسله إلى تغيير ترتيب المفاتيح أو المسافات البيضاء
أو هروب أحرف Unicode، مما ينتج عنه توقيع مختلف.
- استخدم دائمًا المقارنة ذات الوقت الثابت (على سبيل المثال، hmac.compare_digest، crypto.timingSafeEqual،
ActiveSupport::SecurityUtils.secure_compare) لمنع هجمات التوقيت.
- ضع في اعتبارك رفض الطلبات التي تحتوي على طوابع زمنية أقدم من 5 دقائق للتخفيف من هجمات إعادة التشغيل.