منصّة واحدة بثلاث واجهات: خادم MCP للوصول لحسابك بالكامل عبر JSON-RPC، وOAuth 2.1 لربط عملاء خارجيين مثل Claude، وواجهة WhatsApp لإرسال رسائل القوالب من تطبيقك. كل رقم ومسار في هذه الصفحة مأخوذ من الكود المنشور ومُختبَر على الخوادم الفعلية.
الدومين الرسمي للمنصّة هو mad3oom.com. كل مسارات MCP وOAuth تُخدَم منه مباشرة بلا أي إعادة توجيه.
POSThttps://mad3oom.com/mcp
الدومين القديم mad3oom.online انتهى ولم يعد يُستخدم. لو عندك كود أو Connector قديم بيشاور عليه، بدّله بـ mad3oom.com فورًا. الطلبات القديمة كانت بتمرّ على إعادة توجيه 301 تحوّل الـPOST إلى GET (سلوك مواصفة Fetch)، فكان الخادم يرد 405 Only POST is supported على طلب أُرسل أصلًا كـPOST.
لوحة المطوّرين بتولّد نوعين من الاعتماد — الخادم بيقبل الاتنين على نفس الترويسة، ويفرّق بينهم بوجود نقطة . في القيمة.
النوع
شكل القيمة
الترويسة
API Key + Secret credential_type: api_key_secret
mad3oom_pk_<32 hex> mad3oom_sk_<40 حرف>
Bearer mad3oom_pk_….mad3oom_sk_…
Bearer Token credential_type: bearer
mad3oom_bt_<64 hex>
Bearer mad3oom_bt_…
السرّ (mad3oom_sk_…) والـ Bearer Token بيظهروا مرة واحدة فقط لحظة الإنشاء. المخزَّن في قاعدة البيانات بصمة SHA-256 لا القيمة نفسها — فلا الخادم ولا فريق الدعم يقدر يعرضهم لك تاني. لو ضاع منك، ولّد مفتاح جديد أو جدّد السرّ.
اكتب اسمًا واضحًا (حد أقصى 80 حرفًا)، واختر نوع الاعتماد والصلاحيات.
احفظ القيم فورًا
انسخ الـ Key والـ Secret قبل ما تقفل النافذة.
إصدار المفاتيح متاح لمدير الشركة ضمن اشتراك يمنح ميزة api_tokens — وللمنصّة نفسها. أي حساب تاني بيستقبل 403. وصلاحيات أي مفتاح لا تتعدّى سقف حساب صاحبه مهما طلبت، والسقف مفروض على الخادم لا على الواجهة. أقصى مدة صلاحية للمفتاح 730 يومًا.
كل شيء بيمرّ من POST /mcp بجسم JSON-RPC 2.0 واحد. الـmethod بتحدّد العملية.
Method
الوظيفة
HTTP عند النجاح
initialize
التفاوض على نسخة البروتوكول وبدء جلسة
200
notifications/initialized
إشعار من العميل بانتهاء التهيئة (بلا جسم رد)
202
tools/list
الأدوات المتاحة لمفتاحك
200
tools/call
تنفيذ أداة
200
طلبات الدفعات (Batch) غير مدعومة. كل طلب HTTP لازم يحمل كائن JSON-RPC واحد — مش مصفوفة. وأي method غير الأربعة فوق بترجع 404 مع -32601. وGET /mcp بيرجع 405.
initialize
اختياري للاستخدام المباشر، لكنه إلزامي لو بتبني عميل MCP كامل. بيرجّع نسخة البروتوكول المتفق عليها وترويسة Mcp-Session-Id.
النسخ المدعومة: 2025-06-18 (الافتراضية)، 2025-03-26، 2024-11-05، 2025-11-25. لو بعتّ نسخة غير معروفة، الخادم بيرجع للافتراضية بدل ما يرفض الطلب. الخادم يعلن قدرة tools فقط — لا resources ولا prompts.
tools/list
بيرجّع مصفوفة الأدوات بعد فلترتين: أدوات مفتاحك يملك صلاحيتها، وغير مُعطَّلة من إدارة المنصّة. كل عنصر فيه name وdescription وinputSchema (JSON Schema).
الكتالوج بيتقري من قاعدة البيانات مع كاش 30 ثانية — فأي تعديل من الإدارة بيبان خلال نصف دقيقة على الأكثر. اعتبر tools/list هو مصدر الحقيقة وقت التشغيل، وهذه الصفحة مرجعًا للشرح.
لو التذكرة خارج نطاق رؤيتك يرجع -32004 بحالة 403، ولو غير موجودة -32005 بحالة 404.
POST
create_ticket
tickets:write
إنشاء تذكرة دعم جديدة نيابةً عن صاحب مفتاح الـ API.
المعامل
النوع
مطلوب
الوصف
title
string
مطلوب
عنوان التذكرة. لا يقبل قيمة فارغة.
description
string
مطلوب
وصف المشكلة أو الطلب. لا يقبل قيمة فارغة.
priority
string
اختياري
low | medium | high. الافتراضي medium.
category
string
اختياري
تصنيف حر. الافتراضي null.
ticket_type
string
اختياري
problem | inquiry. الافتراضي problem.
contact_info
string
اختياري
بيانات تواصل إضافية. الافتراضي null.
كتالوج الأداة يعلن urgent ضمن قيم priority، لكن قاعدة البيانات تقبل low وmedium وhigh فقط (قيد tickets_priority_check). إرسال urgent يفشل بخطأ داخلي — لا تستخدمه.
Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "create_ticket",
"arguments": {
"title": "عندي مشكلة في الدخول",
"description": "الصفحة بترجعني لتسجيل الدخول كل مرة",
"priority": "medium"
}
}
}
curl -X POST https://mad3oom.com/mcp \
-H "Authorization: Bearer $MAD3OOM_TOKEN" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"create_ticket","arguments":{"title":"عندي مشكلة في الدخول","description":"الصفحة بترجعني لتسجيل الدخول كل مرة","priority":"medium"}}}'
Response (بعد الـ parsing)
200 OK
{
"id": "e5f6…",
"ticket_number": 129,
"user_id": "9c1e…",
"title": "عندي مشكلة في الدخول",
"description": "الصفحة بترجعني لتسجيل الدخول كل مرة",
"status": "open",
"priority": "medium",
"ticket_type": "problem",
"created_at": "2026-09-19T08:12:00+00:00"
}
الرد هو صف التذكرة المُنشأ كاملًا بعد الإدراج.
POST
update_ticket
tickets:write
تعديل تذكرة موجودة. الأدمن يعدّل أي حقل مسموح؛ العميل العادي يقدر يؤرشف تذكرته فقط.
المعامل
النوع
مطلوب
الوصف
ticket_id
string
مطلوب
معرّف التذكرة.
updates
object
مطلوب
كائن الحقول المطلوب تعديلها.
للعميل العادي، المفتاح الوحيد المقبول داخل updates هو archived_by_customer. أي مفتاح غير ذلك يرجع -32004 بحالة 403.
إرسال رسالة واتساب (نصية أو قالب) من رقم مربوط بحسابك.
المعامل
النوع
مطلوب
الوصف
to
string
مطلوب
رقم المستقبِل بالصيغة الدولية بلا «+»، مثل 201001234567.
message_type
string
مطلوب
text أو template.
text
string
حسب النوع
نص الرسالة — مطلوب عند message_type="text".
template
object
حسب النوع
{ name, language, components } — مطلوب عند message_type="template".
phone_number_id
string
انظر التنبيه
معرّف رقم الإرسال لدى ميتا.
كتالوج الأداة يعلن phone_number_id كحقل مطلوب، لكن الخادم يستنتجه تلقائيًا لو حسابك مربوط برقم واحد فقط. لو مربوط بأكثر من رقم ولم ترسله، يفشل الطلب برسالة «عندك أكتر من رقم واتساب مرتبط بهذا الحساب — لازم تحديد phone_number_id صراحةً». الأأمَن: ابعته دائمًا.
عند الفشل يرجع { "ok": false, "status": …, "error": "…" } — ولاحظ إن ده يوصلك داخل result لا داخل error (الأداة نفّذت، والمزوّد هو اللي رفض). الحالة 402 معناها رصيد محفظة واتساب غير كافٍ.
POST
send_whatsapp · template
whatsapp:send
نفس الأداة بنوع template — لإرسال قالب معتمد من ميتا.
حد /mcp بيتحسب من عدّاد طلبات آخر 60 ثانية لنفس المفتاح. التجاوز يرجع 429 مع -32001.
الترقيم (Pagination)
كل الأدوات اللي بترجع قوائم بتاخد limit وoffset. الافتراضي limit=20 وoffset=0، والحد الأقصى limit=100 — أي رقم أكبر بيتقصّ بصمت لـ 100، فلا تفترض إنك هتستقبل 500 صف.
إعادة المحاولة والتكرار
مفيش Idempotency Key على واجهة MCP. لو عملت retry على create_ticket أو send_whatsapp بعد انقطاع، ممكن العملية تتكرّر فعليًا. لو الـ retry مهم لك: تحقّق من عندك قبل الإرسال، أو استخدم Integration API لرسائل واتساب — فيها منع تكرار مدمج.
أعد المحاولة على 429 و5xx فقط، بتراجع أُسّي (2s، 4s، 8s، 16s) وبحد أقصى 5 محاولات. أخطاء 4xx الأخرى تحتاج إصلاح الطلب نفسه — إعادة المحاولة لن تغيّر النتيجة.
أول POST /mcp بلا توكن بيرجع 401 مع ترويسة WWW-Authenticate: Bearer resource_metadata="…" تدلّك على نقطة الاكتشاف. من هنا يبدأ أي عميل MCP قياسي تلقائيًا.
تسجيل العميل — POST /oauth/register
ابعت client_name وredirect_uris (لازم HTTPS) → بيرجع 201 مع client_id.
موافقة المستخدم — GET /oauth/authorize
PKCE إجباري بـcode_challenge_method=S256. المستخدم بيوافق من صفحة الموافقة، وبيرجع code على الـ redirect URI.
تبادل الكود — POST /oauth/token
بيرجع access_token صالح 3600 ثانية وrefresh_token صالح 30 يومًا. التوكن بيتسجّل في نفس جدول api_tokens، فبيشتغل على /mcp زي أي مفتاح.
التجديد
grant_type=refresh_token. الـ refresh token يُدوَّر بالكامل عند كل استخدام — القديم يُلغى فورًا، فاحفظ الجديد دائمًا.
حط العنوان وبس — العميل يكتشف الـ OAuth تلقائيًا من الـ 401 ويفتح صفحة الموافقة
Claude، والعملاء اللي بيربطوا مستخدمين حقيقيين
من لوحة المطوّرين → تبويب MCP → الخادم هتلاقي عنوان الربط جاهز للنسخ، وزر «اختبار الاتصال»، وقائمة الأدوات المتاحة لحسابك لحظيًا.
ملاحظات لبناة العملاء
النقل: Streamable HTTP — طلب POST واحد لكل رسالة. لا SSE ولا WebSocket.
الخادم بيرجع Mcp-Session-Id على initialize، لكنه عديم الحالة: مش شرط ترجّعه في الطلبات التالية.
القدرات المُعلَنة: tools فقط. مفيش resources ولا prompts ولا sampling.
ترويسات CORS مفتوحة (*) وبتقبل mcp-session-id وmcp-protocol-version.
notifications/initialized بيرجع 202 بلا جسم — لا تحاول تعمل .json() عليه.
مدعوم كعميل MCP
في الاتجاه المعاكس، لوحة الإدارة في مدعوم تقدر تتصل بخوادم MCP خارجية (Supabase، GitHub…) نيابةً عن الأدمن. دي ميزة داخلية للوحة — مش جزء من الواجهة اللي بتستهلكها كمطوّر خارجي، وتُدار من تبويب MCP → العميل.
الجزء الثاني
واجهة WhatsApp
واجهة REST مستقلة لإرسال رسائل قوالب واتساب من تطبيقك — بمصادقة خاصة بها، ومنع تكرار مدمج، وصندوق رملي كامل.
تطبيقك الخارجي يعرف ثلاثة أشياء فقط: اسم القالب المنطقي، رقم المستقبِل، المتغيّرات. كل ما عداه — التوكنات، رقم الإرسال، اسم القالب لدى ميتا، الرصيد — مسؤولية مدعوم.
مسار الرسالة
تطبيقك → Integration API → حلّ القالب → طبقة الرسائل → WhatsApp Cloud API
قبل أي إرسال، لازم يكون فيه رقم واتساب مربوط بحساب مدعوم. الربط بيتم من لوحة واتساب بتدفّق Meta Embedded Signup — مش عبر الـ API العام.
تسجيل الدخول بميتا (Embedded Signup)
من لوحة واتساب بتفتح نافذة ميتا بصلاحيتَي whatsapp_business_management وwhatsapp_business_messaging. ميتا بترجّع code ومعاه sessionInfo فيه waba_id وphone_number_id.
تبادل الكود — POST /functions/v1/exchange-token
اللوحة بتبعت الكود للدالة، وهي بتبادله مع ميتا وبتخزّن توكن الوصول مشفّرًا في صف التكامل. الدالة بتتطلب جلسة Supabase (Authorization بجلسة المستخدم) — بلا ترويسة بترجع 401 بالشكل {"code":"UNAUTHORIZED_NO_AUTH_HEADER"}.
تسجيل الرقم — POST /functions/v1/register-whatsapp
جسم الطلب { "phoneNumberId": "…" } بجلسة المستخدم. الدالة بتقرأ حالة الرقم من Graph v25.0، وبتسجّله بـ PIN مولّد تلقائيًا لو محتاج تسجيل، وبتشترك في webhooks الـ WABA.
التحقق من الاشتراك في الـ Webhooks
الدالة بتقرأ الحقول المشتركة فعليًا وبترجّعها، وبتنبّه على أي حقل ناقص من المطلوبة: messages، smb_message_echoes، smb_app_state_sync.
دوال exchange-token وregister-whatsapp وwhatsapp-phone-status كلها بمصادقة جلسة مستخدم وتُستدعى من اللوحة، لا من تطبيقك الخارجي. مذكورة هنا لتفهم التدفّق كاملًا — لكن تكاملك يبدأ من مفتاح mad3_….
لو الرقم مش مربوط بالتكامل، كل محاولة إرسال بترجع CHANNEL_NOT_CONNECTED بحالة 409.
القالب time_getting حالته active ومربوط بقالب معتمد لدى ميتا، ومتغيّراته المطلوبة: tenant_name وcollection_phone. تحقّق دائمًا بنداء هذا المسار قبل الإرسال — لا تثبّت القائمة في كودك.
حالات القالب
الحالة
في live
في sandbox
active
يعمل
يعمل
draft
TEMPLATE_NOT_ACTIVE
يعمل
inactive
مرفوض
مرفوض
لا يظهر في الرد أي اسم قالب لدى المزوّد ولا معرّف رقم — العقد فقط.
8–200 حرفًا من A-Z a-z 0-9 . _ : -. راجع منع التكرار.
metadata
object
اختياري
حتى 20 مفتاحًا، قيم بسيطة ≤ 200 حرف. للتتبّع فقط، وخارج حساب تطابق التكرار.
قائمة الحقول مغلقة. أي حقل آخر — phone_number_id، provider، access_token، اسم القالب لدى المزوّد — يُرفض الطلب بسببه بـINVALID_REQUEST. المتصل لا يختار المزوّد ولا الرقم ولا قالب ميتا.
idempotency_keyإلزامي. اجعله معبّرًا عن الحدث نفسه لا عن لحظة الإرسال.
اختيار المفتاح
rent_due_property_827_tenant_55_2026-09-01 ✅ نفس الحدث ⇒ نفس المفتاح
send_1724180000123 ❌ يتغيّر كل محاولة — بلا فائدة
الحالة
HTTP
الاستجابة
أول طلب
202
يُرسَل فعليًا
تكرار بنفس الحمولة بعد النجاح
200
نفس message_id مع idempotent_replay: true — بلا إرسال ثانٍ
تكرار أثناء التنفيذ
409
REQUEST_IN_PROGRESS (قابل لإعادة المحاولة)
نفس المفتاح بحمولة مختلفة
409
IDEMPOTENCY_KEY_CONFLICT
إعادة محاولة بعد فشل مؤقت
—
يُعاد التنفيذ بنفس المفتاح
إعادة محاولة بعد فشل دائم
—
يُعاد نفس الخطأ بلا إرسال
الحماية مفروضة في قاعدة البيانات (قيد فريد على client_id + idempotency_key) لا في كود التطبيق — فطلبان متزامنان تمامًا لا يمكن أن يُرسلا رسالتين. وmetadata خارج حساب التطابق: تغييرها وحدها لا يكسر إعادة المحاولة.
سياسة إعادة المحاولة
أعد المحاولة فقط عند retryable: true — وهي 429، 5xx، 402، وREQUEST_IN_PROGRESS.
استخدم نفسidempotency_key — هذا بالضبط ما يمنع الازدواج.
مفتاح mad3_test_… بيشغّل المسار كاملًا — مصادقة، حدّ معدل، تحقّق من القالب والمتغيّرات والرقم، منع تكرار، استجابة — بلا نداء واتساب، بلا رسالة حقيقية، بلا خصم رصيد.
environment: "test" وsandbox: true في الرد.
message_id بيبدأ بـmsg_test_.
القوالب في حالة draft بتشتغل في الصندوق الرملي فقط — فتقدر تبني على عقد قالب قبل اعتماده في واتساب.
الانتقال للإنتاج بتبديل المفتاح فقط — لا تغيير في الكود ولا في المسار.
التكلفة والرصيد
الإعداد
القيمة الحالية
المعنى
template_charge_egp
0.282
تكلفة رسالة القالب بالجنيه
text_charge_egp
0
تكلفة الرسالة النصية عبر أداة MCP
wallet_charge_enabled
true
الخصم من المحفظة مفعّل
wallet_enforce_send
false
نقص الرصيد يُسجَّل تحذيرًا ولا يمنع الإرسال حاليًا — قياس أولًا
default_rate_limit_per_minute
60
حد الطلبات لكل تكامل
default_rate_limit_burst
20
الدفعة المسموحة
القيم دي إعدادات منصّة قابلة للتغيير من الإدارة — لا تثبّتها في كودك. تعامل مع INSUFFICIENT_BALANCE كخطأ محتمل دائمًا حتى لو الفرض مُعطَّل اليوم.
ميتا بتنادي المسار بـGET ومعاه ثلاثة باراميترات. لو hub.mode=subscribe وhub.verify_token طابق التوكن المضبوط، بيرجع hub.challenge نصًّا خامًا بحالة 200. غير كده 403Forbidden.
Verification request
GET /functions/v1/whatsapp-webhook
?hub.mode=subscribe
&hub.verify_token=<WEBHOOK_VERIFY_TOKEN>
&hub.challenge=1158201444
200 OK
1158201444
٢. استقبال الأحداث — POST
الحمولة بشكل Meta Cloud API القياسي. الخادم بيمرّ على كلentry وكل changes داخلها — لا يكتفي بالأول — وبيعالج كل value بمعزل عن الباقي، فخطأ في واحدة لا يُسقط البقية.
الـPOST بيرجع 200 OKدائمًا — حتى لو فشلت معالجة حدث داخلي. ده مقصود: ميتا بتوقف التسليم لو استقبلت أخطاء متكررة، فالأخطاء بتتسجّل في اللوج بدل ما تكسر التسليم.
٣. الحقول المطلوب الاشتراك فيها
عند ربط الرقم بيتم الاشتراك على مستوى الـ WABA، وبيتقرا الاشتراك الفعلي للتأكد. الحقول المطلوبة:
الحقل
الغرض
messages
الرسائل الواردة وحالات التسليم
smb_message_echoes
صدى الرسائل المُرسَلة من تطبيق واتساب نفسه (وضع التعايش)
smb_app_state_sync
مزامنة حالة تطبيق واتساب (وضع التعايش)
نقص أي حقل من دول بيظهر كتحذير وقت الربط بدل ما يتحوّل لمشكلة «الرسائل مش بتوصل» بعد أيام.
الدوال دي جزء من منظومة واتساب لكنها ليست واجهة عامة للمطوّرين. موثّقة هنا عشان تعرف الحدود بالضبط.
POST /functions/v1/send-whatsapp
نسخة REST من أداة send_whatsapp، بنفس مصادقة مفاتيح API وبنفس صلاحية whatsapp:send.
الحقل
مطلوب
ملاحظة
to
مطلوب
ناقصه ⇒ 400 «الحقل to مطلوب»
message_type
مطلوب
text أو template — غير ذلك 400
text
مع text
مطلوب عند message_type=text
template.name
مع template
مطلوب عند message_type=template
phone_number_id
اختياري
يُستنتَج لو الحساب مربوط برقم واحد
الردود المتحقَّق منها: بلا ترويسة ⇒ 401{"error":"Missing Authorization header"}، وGET ⇒ 405{"error":"Only POST is supported"}. عند النجاح بيرجع نفس كائن { ok, status, data }، وعند فشل المزوّد بيرجع حالة المزوّد نفسها أو 502.
POST /functions/v1/whatsapp-graph-request
وسيط محروس لعمليات Graph من اللوحة — بمصادقة جلسة مستخدم، مش بمفتاح API. جسم الطلب { "operation": "…", "payload": { … } }، أو multipart/form-data لرفع الوسائط.
العمليات المسموحة حصرًا (أي غيرها ⇒ 400unsupported_operation):