Webhook هو طلب POST يرسله GREM إلى عنوانك عندما يحدث شيء: تنتهي مهمة، أو يتغير عقار أو عميل محتمل. إدارة الاشتراكات تتطلب النطاق webhooks وهي مجانية. تُدار Webhooks الوكالة بمفتاح الوكالة كلها؛ ومفتاح الوكيل يتلقى 403.
الاشتراك
curl -X POST https://developers.grem.capital/api/v1/webhooks \
-H "Authorization: Bearer gsk_live_xxx" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/grem-hook","events":["content.completed","content.failed","lead.created"]}'
{ "id": "...", "url": "https://example.com/grem-hook", "events": [...], "status": "active",
"failureCount": 0, "lastDeliveryAt": null, "secret": "whsec_..." }
url: عنوان عامhttps://على المنفذ الافتراضي (443)، دونuser:passwordفيه. المنافذ الأخرى وبيانات الدخول في العنوان والعناوين الخاصة والمحلية والداخلية تُرفض (400). قاعدة المنفذ تُطبق عند تعيين العنوان: العناوين المحفوظة سابقا بمنفذ آخر تستمر في تلقي التسليمات.events: حدث واحد على الأقل من القائمة أدناه؛ الأسماء غير المعروفة تُهمل.secret: سر التوقيع. يُعاد مرة واحدة فقط، فاحفظه.- حتى 10 عناوين لكل حساب، ومنفصلةً حتى 10 عناوين لبيئة الاختبار أُنشئت بمفاتيح الاختبار؛ والعنوان الحادي عشر يُرفض بـ
422 business_rule. - العناوين المنشأة بمفتاح اختبار هي عناوين بيئة الاختبار: لا تتلقى إلا أحداث مهام بيئة الاختبار (بيئة الاختبار).
يمكن إدارة الاشتراكات من لوحة التحكم أيضا: API → Webhooks. ومن هناك يمكن تغيير سر التوقيع.
الإدارة
| الطلب | ماذا يفعل |
|---|---|
GET /webhooks | اشتراكاتك (دون الأسرار) |
PATCH /webhooks/{id} | تغيير url أو events أو status (active / disabled) |
DELETE /webhooks/{id} | حذف الاشتراك |
POST /webhooks/{id}/test | إرسال حدث تجريبي؛ الجسم {"eventType": "content.completed"} يحدد الشكل |
GET /webhooks/{id}/deliveries | آخر 50 عملية تسليم: الحالة، ورمز الرد، والزمن، وبداية الرد |
POST /webhooks/{id}/deliveries/{deliveryId}/resend | إعادة إرسال تسليم؛ deliveryId هو _id لسطر من السجل |
PATCH دون أي حدث صالح في events أو بقيمة status غير active / disabled يُرفض بـ 400. وDELETE لاشتراك غير معروف يعيد 404. في سجل التسليمات payload هو data الخاص بالحدث.
الأحداث
المهام المنتهية
| الحدث | متى |
|---|---|
valuation.completed، valuation.failed | تقرير التقييم الكامل |
review.completed، review.failed | مراجعة التقرير |
content.completed، content.partial، content.failed | حزمة المحتوى (partial: فشلت بعض الملفات) |
text.completed، text.failed | النصوص |
video.completed، video.failed | الفيديو |
avatar.completed، avatar.failed | فيديو الأفاتار |
photo.completed، photo.failed | تحسين الصور |
floorplan.completed، floorplan.failed | المخطط |
pdf.completed، pdf.failed | عرض PDF |
data: { "jobId", "status", "state" }. status هي الحالة الخام للأداة بأحرف كبيرة (مثلا COMPLETED)؛ اعتمد على state في التفرع. إذا لم تنته المهمة خلال 30 دقيقة يصل .failed مع "reason": "timeout". لا تُتابَع المهمة إلا إذا كان الاشتراك في حدثها موجودا عند إنشائها (المهام والنتائج).
العقارات
| الحدث | متى |
|---|---|
object.created | أنشأت عقارا |
object.updated | تغير عقار، بما في ذلك من قِبل مشرف |
object.published | أصبح العقار عاما |
object.deleted | حُذفت مسودة أو أُرشف عقار منشور |
data: { "objectId", "kind", "status", "occurredAt" }؛ في object.deleted بدلا من status يأتي mode (deleted أو archived). البيانات الكاملة: GET /objects/{kind}/{id}.
العملاء المحتملون
| الحدث | متى |
|---|---|
lead.created | عميل محتمل جديد لك |
lead.updated | تغيرت الحالة أو المسؤول |
data: { "leadId", "status", "type", "source", "objectId", "occurredAt" }. لا توجد بيانات شخصية للعميل في الحدث: اقرأ العميل المحتمل عبر GET /leads/{id}.
Swipe Match
| الحدث | متى |
|---|---|
match.lead.offered | عُرض عليك (أو على وكيل في وكالتك) عميل محتمل |
match.lead.offer_closed | أُغلق العرض دونك (انتهت المهلة) |
match.lead.matched | أُسند إليك العميل المحتمل |
match.lead.updated | انتقل العميل المحتمل إلى مرحلة جديدة |
match.lead.unassigned | سُحب منك العميل المحتمل |
data: { "leadId", "eventId", "eventCode", "occurredAt", "source", "stage", "active", "leadKind", "clientType", "country", "brokerId", "agencyId" }. اسم العميل وهاتفه وبريده لا ترد أبدا في الأحداث (Swipe Match).
صيغة التسليم
POST https://example.com/grem-hook
Content-Type: application/json
x-grem-event: content.completed
x-grem-signature: t=1759400000,v1=3b78a03b78058d229023db2a0b4ee072...
{ "id": "...", "type": "content.completed", "createdAt": "2026-10-02T10:00:00.000Z", "data": { ... } }
idثابت في كل إعادات التسليم الواحد: استخدمه كي لا تعالج الحدث مرتين.tوcreatedAtهما وقت المحاولة المعنية.- التسليم التجريبي (
POST /webhooks/{id}/test) معeventTypeمن القائمة يحملtest: trueفيdata؛ ودونه يكون نوع الحدثwebhook.test. وeventTypeغير الموجود في القائمة يعطي400. أماwebhook.testنفسه فمقبول.
التحقق من التوقيع
التوقيع هو HMAC-SHA256 للسلسلة "<t>.<raw body>" بسر الاشتراك، بصيغة ست عشرية في v1. تحقق قبل أي معالجة، وارفض قيم t القديمة (حماية من إعادة الإرسال).
احسب التوقيع على الجسم الخام كما وصل، قبل تحليل JSON. إعادة التسلسل تغير البايتات فلا يتطابق التوقيع.
const crypto = require('crypto');
function verifyGremSignature(secret, header, rawBody, toleranceSec = 300) {
const parts = Object.fromEntries(String(header || '').split(',').map((kv) => kv.split('=')));
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;
const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(parts.v1 || '');
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
app.post('/grem-hook', express.raw({ type: 'application/json' }), (req, res) => {
const raw = req.body.toString('utf8');
if (!verifyGremSignature(process.env.GREM_WEBHOOK_SECRET, req.get('x-grem-signature'), raw)) {
return res.status(400).send('invalid signature');
}
const event = JSON.parse(raw);
// event.id, event.type, event.data
res.sendStatus(200);
});
في SDK تقوم بذلك الدالة verifyWebhookSignature().
إعادة المحاولات والتعطيل
- ينجح التسليم إذا أجاب خادمك بـ
2xxخلال 10 ثوان. أجب بسرعة ونفّذ العمل الثقيل في الخلفية. - يُعاد التسليم الفاشل بعد 5 دقائق و30 دقيقة وساعتين و6 ساعات: حتى 5 محاولات إجمالا.
- بعد 5 عمليات تسليم فاشلة كليا على التوالي يُعطَّل الاشتراك (
status: disabled). أعد تفعيله عبرPATCH /webhooks/{id}مع{"status":"active"}أو من لوحة التحكم. - سجل التسليم (
GET /webhooks/{id}/deliveries) يعرض رمز رد خادمك وبداية جسم الرد: منه تعرف سبب فشل التسليم.
مقالات ذات صلة
- المهام والنتائج: حالات المهام.
- Swipe Match: رموز أحداث عملاء الوحدة.