/v1/account/webhook-endpoints

account/webhook-endpoints

Webhooks: إلى أين يرسل Monitoring الـ Signals الجديدة وكيف تتحقق منها.

التكاليف والحدود

التكاليف والحدود
ماذا الأرصدة
إدارة نقاط نهاية webhook وعمليات التسليم مجانًا

الحد: 30 طلب في الدقيقة. الإنشاء والتعديل والحذف: 10 في الدقيقة. الفحص والاختبار وسرّ جديد: 6 في الدقيقة.

رمز المسؤول أو مفتاح API

نقاط النهاية

الطريقة
الطريقة المسار الغرض الوصول
GET /v1/account/webhook-endpoints جميع نقاط نهاية webhook، دون المؤرشفة. مفتاح API أو رمز المسؤول
POST /v1/account/webhook-endpoints إنشاء نقطة نهاية webhook. رمز المسؤول
POST /v1/account/webhook-endpoints/{id}/verify التحقق. مفتاح API أو رمز المسؤول
POST /v1/account/webhook-endpoints/{id}/test إرسال رسالة اختبار. مفتاح API أو رمز المسؤول
POST /v1/account/webhook-endpoints/{id}/rotate-secret سرّ توقيع جديد. رمز المسؤول
POST /v1/account/webhook-endpoints/{id}/enable تفعيل. رمز المسؤول
POST /v1/account/webhook-endpoints/{id}/disable تعطيل. رمز المسؤول
DELETE /v1/account/webhook-endpoints/{id} أرشفة. رمز المسؤول
GET /v1/account/webhook-deliveries آخر 50 عملية تسليم. مفتاح API أو رمز المسؤول
POST /v1/account/webhook-deliveries/{id}/retry إعادة إرسال عملية تسليم فاشلة. مفتاح API أو رمز المسؤول
GET /v1/account/webhook-events آخر 50 حدث. مفتاح API أو رمز المسؤول

إنشاء نقطة نهاية webhook

curl -X POST "https://handelsregister.ai/api/v1/account/webhook-endpoints" \
  -H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "CRM-Sync",
    "url": "https://hooks.example.com/handelsregister",
    "headers": {
        "X-Receiver-Token": "YOUR_RECEIVER_TOKEN"
    }
}'
المعاملات
الاسم النوع الوصف مثال
Idempotency-KeyHeader نص (string)إلزامي قيمة فريدة لكل عملية، ويُفضَّل UUID. انظر Idempotency-Key.الحدود: من 1 إلى 128 حرفًا req-20260802-01
nameBody نص (string)إلزامي اسم لمرجعك الخاص.الحدود: من 1 إلى 120 حرفًا CRM-Sync
urlBody نص (string) (uri)إلزامي عنوان خادمك: يمكن الوصول إليه علنًا، https على المنفذ 443، باسم مضيف بدلًا من عنوان IP.الحدود: من 1 إلى 2,048 حرفًا https://hooks.example.com/handelsregister
headersBody كائن (object)اختياري Headers مخصصة تُرسل مع كل رسالة، مثل رمز لخادمك.الحدود: 10 عنصرًا على الأكثر {"X-Receiver-Token":"YOUR_RECEIVER_TOKEN"}
1{2  "endpoint": {3    "id": "wep_01m6b3j1g0cdz98hw8zdefbf52",4    "name": "CRM-Sync",5    "url": "hooks.example.com/…",6    "status": "pending_verification",7    "verified_at": null,8    "header_names": [9      "X-Receiver-Token"10    ],11    "consecutive_failures": 0,12    "created_at": "2026-11-01T08:28:01+00:00"13  },14  "signing_secret": "whsec_…",15  "meta": {16    "message": "Endpoint created. Store the signing secret now — it is shown only once.",17    "request_credit_cost": 0,18    "credits_remaining": 14519  }20}
201 · مثال على استجابة: نقطة نهاية webhook جديدة، والسرّ مختصر هنا

التحقق

1{2  "id": "msg_01m6b3jsqq7ntwzkdj099ayraz",3  "type": "endpoint.verification",4  "timestamp": "2026-11-01T08:28:26.743Z",5  "schema_version": 1,6  "data": {7    "challenge": "189fb34b2af819bb13cb47d9806dbf30"8  }9}
الرسالة التي يتلقاها خادمك أثناء التحقق
curl -X POST "https://handelsregister.ai/api/v1/account/webhook-endpoints/wep_01m6b3j1g0cdz98hw8zdefbf52/verify" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
1{2  "verified": true,3  "endpoint": {4    "id": "wep_01m6b3j1g0cdz98hw8zdefbf52",5    "name": "CRM-Sync",6    "url": "hooks.example.com/…",7    "status": "active",8    "verified_at": "2026-11-01T08:28:26+00:00",9    "header_names": [10      "X-Receiver-Token"11    ],12    "consecutive_failures": 0,13    "created_at": "2026-11-01T08:28:01+00:00"14  },15  "meta": {16    "request_credit_cost": 0,17    "credits_remaining": 14518  }19}
200 · مثال على استجابة لتحقق ناجح
1{2  "delivery": {3    "id": "del_01m6b3jsyrnc3sz1mt31dq6107",4    "message_id": "msg_01m6b3jsynxzhvagm7n2nq7mpv",5    "event_id": "evt_01m6b3jsynxzhvagm7n2nq7mpt",6    "event_type": "endpoint.test",7    "endpoint_id": "wep_01m6b3j1g0cdz98hw8zdefbf52",8    "status": "succeeded",9    "attempts": 1,10    "last_status_code": 200,11    "last_error_category": null,12    "next_attempt_at": "2026-11-01T08:28:26+00:00",13    "succeeded_at": "2026-11-01T08:28:26+00:00",14    "created_at": "2026-11-01T08:28:26+00:00"15  },16  "meta": {17    "request_credit_cost": 0,18    "credits_remaining": 14519  }20}
200 · مثال على استجابة لرسالة اختبار

التحقق من التوقيع

الـ Header
الـ Header المعنى
webhook-id معرّف الرسالة (msg_…). ويبقى كما هو عند إعادة المحاولة. استخدمه لاكتشاف التكرارات.
webhook-timestamp وقت محاولة التسليم هذه بثواني Unix.
webhook-signature توقيع واحد أو أكثر بالصيغة v1,<Base64>، مفصولة بمسافات.
import base64, hashlib, hmac, time

def verify_webhook(secret: str, headers: dict, body: bytes) -> bool:
    msg_id = headers["webhook-id"]
    timestamp = headers["webhook-timestamp"]
    # ارفض الرسائل الأقدم من خمس دقائق
    if abs(time.time() - int(timestamp)) > 300:
        return False
    key = base64.b64decode(secret.removeprefix("whsec_"))
    signed = f"{msg_id}.{timestamp}.".encode() + body
    expected = base64.b64encode(hmac.new(key, signed, hashlib.sha256).digest()).decode()
    # أثناء تدوير السرّ يحمل الـ Header توقيعين
    for part in headers["webhook-signature"].split(" "):
        version, _, signature = part.partition(",")
        if version == "v1" and hmac.compare_digest(signature, expected):
            return True
    return False

الحمولة

الحقل
الحقل المعنى
id معرّف الرسالة، مساوٍ للـ Header ‏webhook-id.
event_id معرّف الحدث (evt_…).
type نوع الحدث، انظر أدناه.
timestamp متى اكتشفنا الحدث، بتوقيت UTC.
schema_version إصدار البنية، حاليًا 1.
data بيانات الحدث.
أنواع الأحداث
نوع الحدث المعنى
organization.signal.detected وجد مراقب إشارة جديدة. لـ data.signal البنية نفسها التي للإشارة في signals، إضافةً إلى data.monitor، وتحت data.links.signal الرابط إلى الإشارة في الـ API.
organization.signal.sample مثال من التاريخ الحقيقي للشركة، يُرسل تحت الحساب › المراقبة. بالبنية نفسها كما في الأعلى، إضافةً إلى data.sample: true.
endpoint.test رسالة اختبار عبر /test.
endpoint.verification التحدي أثناء التحقق.
1{2  "id": "msg_01m65pqg9x0176cteqvtxw68sa",3  "event_id": "evt_01m65pqg9sx7mwmw0edc1mfbbe",4  "type": "organization.signal.sample",5  "timestamp": "2026-10-30T06:07:37.000Z",6  "schema_version": 1,7  "data": {8    "monitor": {9      "id": "mon_01m65pn3vm11sjjp1j076cbvec",10      "type": "organization.signals"11    },12    "sample": true,13    "signal": {14      "event": {15        "id": "36c7c8fddf99bb0299d6815bcaa01013",16        "topic": "TRANSFORMATIONS",17        "topic_name": {18          "de": "Umwandlungen & M&A",19          "en": "Transformations & M&A"20        },21        "occurred_on": "2022-12-22",22        "announced_on": "2023-08-10",23        "date_basis": "SOURCE_EVENT"24      },25      "organization": {26        "type": "ORGANIZATION",27        "entity_id": "94eb910fef13f94585c48c263fa446d4",28        "current_profile": {29          "name": "Hetzner Online GmbH",30          "registration": {31            "register_type": "HRB",32            "register_number": "6089",33            "court": "Ansbach",34            "register_locality": "Ansbach",35            "registration_authority_id": "D3201",36            "register_entity_name": "Ansbach HRB 6089"37          },38          "legal_form": {39            "name": {40              "de": "Gesellschaft mit beschränkter Haftung"41            },42            "short": {43              "de": "GmbH"44            }45          },46          "seat": {47            "city": "Gunzenhausen"48          },49          "status": {50            "code": "ACTIVE"51          }52        }53      },54      "parties": {55        "counterparty": {56          "entity": {57            "type": "ORGANIZATION",58            "entity_id": "dd4d2d6854b2dbd1ffce74e669f3852e",59            "current_profile": {60              "name": "Headtrip GmbH",61              "registration": {62                "register_type": "HRB",63                "register_number": "33432",64                "court": "Nürnberg",65                "register_locality": "Nuremberg",66                "registration_authority_id": "D3310",67                "register_entity_name": "Nürnberg HRB 33432"68              },69              "legal_form": {70                "name": {71                  "de": "Gesellschaft mit beschränkter Haftung"72                },73                "short": {74                  "de": "GmbH"75                }76              },77              "seat": {78                "city": "Nürnberg"79              },80              "status": {81                "code": "INACTIVE"82              }83            }84          },85          "relationship": "TRANSFERRING_COMPANY"86        }87      },88      "register_entry": {89        "entry_number": "3",90        "entry_date": "2023-08-10",91        "description_text": "Verschmelzung zur Aufnahme der Headtrip GmbH",92        "context": "PRIMARY",93        "flags": []94      },95      "source": {96        "kind": "COMMERCIAL_REGISTER"97      },98      "details": {99        "schema": "TRANSFORMATION",100        "kind": "MERGER",101        "specifics": {102          "merger_target": "ABSORPTION"103        },104        "direction": "INCOMING",105        "is_cross_border": false,106        "resolution_date": "2022-12-22",107        "agreement_date": "2022-12-22"108      }109    },110    "links": {111      "signal": "https://handelsregister.ai/api/v1/signals/36c7c8fddf99bb0299d6815bcaa01013"112    }113  }114}
رسالة نموذجية لـ Hetzner Online GmbH، Ansbach HRB 6089: اندماج Headtrip GmbH، Nürnberg HRB 33432، مرسلة كمثال من التاريخ

عمليات التسليم وإعادة المحاولة

نسلّم كل رسالة مرة واحدة على الأقل، لكن ليس بترتيب ثابت. اكتشف التكرارات حسب webhook-id. أجب بسرعة وعالج الرسالة بعد ذلك فقط.
حالة عملية التسليم
الحالة المعنى
withheld تنتظر حتى يُحتسب الفحص.
pending تنتظر الإرسال.
in_flight قيد الإرسال الآن.
retry_wait تنتظر المحاولة التالية.
succeeded سُلّمت.
exhausted فشلت جميع المحاولات.
blocked_endpoint لا تستطيع نقطة نهاية webhook استقبال أي شيء حاليًا.
cancelled أُلغيت، مثلًا لأن الرسالة انتهت صلاحيتها.

التفعيل والتعطيل والأرشفة

curl -X POST "https://handelsregister.ai/api/v1/account/webhook-endpoints/wep_01m6b3j1g0cdz98hw8zdefbf52/disable" \
  -H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)"

الأخطاء

الأخطاء
الحالة السبب ما يمكنك فعله
400 api_key موجود في الـ URL. أرسل المفتاح في الـ Header ‏x-api-key.
400 الـ URL غير مسموح كوجهة، أو Header غير مسموح، أو تم بلوغ الحد الأقصى للعدد، أو نقطة نهاية webhook غير نشطة. ويذكر meta.message السبب. صحّح القيمة أو تحقّق أولًا.
400 لـ Idempotency-Key صيغة غير صالحة. صحّح الصيغة، مثلًا استخدم UUID.
401 لا يوجد مفتاح API أو رمز، أو أحدهما غير صالح. أرسل المفتاح في الـ Header ‏x-api-key.
403 ينقص Bearer token الصلاحية account:read. استخدم مفتاح API أو رمزًا بـ account:read.
403 لم يُؤكَّد عنوان البريد الإلكتروني لحسابك بعد، أو الحساب مقفل. افتح الرابط من بريد التأكيد. وإذا كان الحساب مقفلًا، يمكن للدعم المساعدة.
403 يحتاج هذا الاستدعاء إلى رمز المسؤول. لا يكفي مفتاح API، ولا أي رمز آخر. أرسله مع Authorization: Bearer ورمز المسؤول.
403 ينقص Bearer token الصلاحية monitoring:manage. استخدم مفتاح API أو رمز المسؤول.
404 لا توجد نقطة نهاية webhook أو عملية تسليم بهذا المعرّف. تحقّق من المعرّف.
409 استُخدم Idempotency-Key بالفعل مع بيانات مختلفة، أو هو أقدم من 24 ساعة، أو لا يزال قيد المعالجة. استخدم مفتاحًا جديدًا أو انتظر قليلًا.
422 قيمة مفقودة أو غير صالحة، مثل name أو url. ويذكر errors الحقل. صحّح القيمة وأعد المحاولة بمفتاح جديد.
422 فشل التحقق. تحقّق من Header التحدي ومن حالة 2xx، ثم أعد المحاولة بمفتاح جديد.
428 الـ Header ‏Idempotency-Key مفقود. أرسل الـ Header.
429 طلبات كثيرة جدًا. أعد المحاولة بعد Retry-After.
503 التحقق والاختبار وإعادة الإرسال غير متاحة مؤقتًا. أعد المحاولة بعد قليل.
1{2  "error": "invalid_request",3  "meta": {4    "message": "The endpoint is not active.",5    "request_credit_cost": 0,6    "credits_remaining": 1457  }8}
400 · لا تستطيع نقطة نهاية webhook غير موثّقة بعد استقبال رسالة اختبار