نظرة عامة
استقبل أحداث TicketWave كطلبات HTTP موقّعة في تطبيقك الخاص.
Webhooks
الـ webhook هو طلب HTTP يرسله TicketWave إليك. كلما حدث شيء في خادمك — فُتحت تذكرة، أو أُضيف عضو إلى القائمة السوداء — يرسل TicketWave جسم JSON عبر POST إلى عنوان URL تملكه أنت.
وهذا هو الفرق عن Log Channels: قنوات السجل تكتب embed داخل Discord ليقرأه البشر، بينما الـ webhooks تسلّم الحدث الخام إلى كودك.
الـ Webhooks ميزة مدفوعة. بدون الاشتراك المدفوع، لا يمكن إنشاء endpoints ولا يتم تسليم أي أحداث.
Create an Endpoint
Open the endpoints page
لوحة تحكم الخادم → Webhooks → Endpoints.
Add an endpoint
انقر Add Endpoint واملأ الحقلين التاليين:
| Field | Description |
|---|---|
| Endpoint URL | عنوان https:// الذي يستقبل الطلبات |
| Event Types | أنواع الأحداث التي يجب أن يستقبلها هذا endpoint |
لا يستقبل الـ endpoint إلا الأنواع التي تحددها. لا يُسمح بعدم اختيار أي نوع — اختر نوعًا واحدًا على الأقل.
Copy the signing secret
يُنشئ TicketWave سر التوقيع (whsec_…) في اللحظة التي يتم فيها إنشاء الـ endpoint. افتح قائمة الـ endpoints، وأظهره بأيقونة العين ثم انسخه إلى إعدادات تطبيقك.
تعامل مع السر كما تتعامل مع كلمة المرور. أي شخص يملكه يمكنه تزوير طلبات تجتاز فحص التوقيع. احتفظ به في متغير بيئة، وليس أبدًا في المستودع الخاص بك.
Send a test event
استخدم زر Send test event (الطائرة الورقية) في صف الـ endpoint. سيُرسل طلبًا حقيقيًا وموقّعًا بالكامل مع "test": true داخل الحمولة، حتى تتمكن من التأكد أن المستقبِل يعمل قبل أن تعتمد عليه تذكرة حقيقية.
ستظهر النتيجة في سجل Webhooks مثل أي عملية تسليم أخرى.
Endpoint Requirements
| Requirement | Detail |
|---|---|
| Scheme | https:// فقط — يتم رفض http:// |
| Host | يجب أن يكون قابلاً للحل علنًا. تُرفض العناوين الخاصة، وعناوين loopback، وlink-local، وCGNAT |
| Response | أي حالة 2xx تُعد نجاحًا |
| Timeout | لديك 10 ثوانٍ للرد |
| Redirects | لا يتم اتباعها. تُعد 3xx فشلًا |
| Limit | حتى 5 endpoints لكل خادم |
يتم فحص الـ host عند حفظ الـ endpoint وأيضًا قبل كل عملية تسليم، لذلك إذا بدأ نطاق ما لاحقًا في الحل إلى عنوان داخلي، سيتوقف التسليم إليه.
The Request
كل عملية تسليم هي POST مع جسم JSON.
Headers
| Header | Example | Meaning |
|---|---|---|
Content-Type | application/json | JSON دائمًا |
User-Agent | TicketWave-Webhooks/1.0.5 | إصدار البوت الذي أرسله |
X-TicketWave-Event | ticket.created | نوع الحدث |
X-TicketWave-Delivery | wh_3f2a… | معرّف فريد لهذه العملية |
X-TicketWave-Timestamp | 1786224191 | ثواني Unix، وهي جزء من التوقيع |
X-TicketWave-Signature | sha256=9f86d0… | HMAC الخاص بالطلب |
Body
تستخدم كل حمولة نفس الغلاف. يختلف فقط data بحسب نوع الحدث:
{
"event": "ticket.created",
"timestamp": "2026-08-26T08:23:11.000Z",
"guild_id": "123456789012345678",
"data": {
"ticket_id": "ticket-1042",
"ticket_num_id": 1042,
"channel_id": "998877665544332211",
"category": "🤖 Support",
"user": { "id": "987654321098765432", "username": "Luna" },
"created_at": "2026-08-26T08:23:11.000Z"
}
}راجع Event Reference لمعرفة كائن data لكل نوع.
Verifying the Signature
أي شخص يكتشف عنوان URL الخاص بـ endpoint يمكنه إرسال طلب POST إليه. التوقيع هو الطريقة التي تميّز بها عملية تسليم حقيقية من TicketWave عن عملية مزوّرة.
تحقق دائمًا. أي endpoint غير مُتحقق منه ينشئ أو يغلق أشياء في نظامك هو باب مفتوح.
How the signature is built
يجمع TicketWave بين الطابع الزمني وجسم الطلب الخام باستخدام نقطة، ثم يشغّل HMAC-SHA256 على الناتج باستخدام سر الـ endpoint الخاص بك:
signed_payload = X-TicketWave-Timestamp + "." + raw_request_body
signature = HMAC_SHA256(signed_payload, your_endpoint_secret)يحمل العنوان هذا الملخّص بصيغة hex مع بادئة: sha256=<digest>.
What your receiver must do
اقرأ الجسم الخام. تحقّق من البايتات نفسها التي استلمتها. إذا كان إطار العمل لديك يحلل JSON أولًا ثم تعيد تسلسله، فقد يتغير ترتيب المفاتيح أو التباعد ولن يطابق الملخّص.
أعد حساب HMAC على timestamp + "." + rawBody باستخدام سرك.
قارن بزمن ثابت (crypto.timingSafeEqual في Node). المقارنة البسيطة === تكشف معلومات زمنية.
تحقق من أن الطابع الزمني حديث — خمس دقائق من السماح قيمة افتراضية جيدة. الطابع الزمني موجود داخل الحمولة الموقّعة، لذلك لا يمكن للمهاجم إعادة إرسال طلب قديم بطابع زمني جديد.
توجد عملية تنفيذ كاملة في صفحة Example Server.
Retries
أي عملية تسليم تفشل تتم إعادة المحاولة لها تلقائيًا.
| Attempts | 3 (المحاولة الأولى + محاولتان إضافيتان) |
| Backoff | ثانية واحدة، ثم 5 ثوانٍ |
| Retried on | أخطاء الشبكة، وانتهاء المهلة، و408 و429 وأي 5xx |
| Not retried on | أي 4xx أخرى — وهذا يعني أن الـ endpoint رفض الطلب عمدًا |
بسبب إعادة المحاولة قد يستقبل الـ endpoint نفس الحدث مرتين. استخدم X-TicketWave-Delivery كمفتاح idempotency: تذكّر المعرفات التي عالجتها وتجاهل التكرارات.
عمليات التسليم ليست مرتبة. إذا تم إنشاء تذكرتين في اللحظة نفسها، فقد تصل الطلبات بأي ترتيب — استخدم الحقل timestamp في الجسم إذا كان الترتيب مهمًا بالنسبة لك.
Delivery History
تسرد صفحة Webhooks في لوحة التحكم كل عملية تسليم مع حالتها، ورمز الاستجابة، والمدة، وعدد المحاولات. افتح أي صف لرؤية حمولة الطلب الدقيقة التي أُرسلت والاستجابة التي أعادها خادمك.
يمكن إعادة إرسال عمليات التسليم الفاشلة من صفحة التفاصيل باستخدام Retry Webhook. سيُرسل الحمولة الأصلية مرة أخرى إلى نفس الـ endpoint ويسجل عملية تسليم جديدة.
يُحتفظ بالسجل لمدة 30 يومًا، ثم يُنظَّف تلقائيًا.
Troubleshooting
| Problem | Fix |
|---|---|
| لا يمكن حفظ الـ endpoint | يجب أن يكون عنوان URL من نوع https:// وأن يُحل إلى عنوان عام |
| يظهر كل شيء على أنه فشل بدون رمز استجابة | لم يصل الطلب إليك أبدًا — انتهاء مهلة، أو فشل DNS، أو رفض الاتصال |
| لا يطابق التوقيع أبدًا | أنت تُجري الهاش على الجسم المحلل بدلًا من البايتات الخام، أو نسيت البادئة timestamp + "." |
| تتوقف عمليات التسليم بعد فترة | تحقّق مما إذا كان خادمك بدأ يعيد 4xx — هذه لا تُعاد المحاولة لها |
| لا يصل حدث أبدًا | الـ endpoint غير مشترك في ذلك النوع، أو أن الخادم فقد الاشتراك المدفوع |
| أحداث مكررة | متوقع عند إعادة المحاولة — أزل التكرار اعتمادًا على X-TicketWave-Delivery |
Next Steps
- Event Reference (كل حدث وحمولته)
- Example Server (مستقبِل Express قابل للتشغيل)
- Log Channels (نفس الأحداث، لكن تُنشر داخل Discord)
How is this guide?
