تنطبق هذه القواعد على كل نقطة تحت /api/v1. ولا تصف صفحات الموارد إلا ما يختلف عنها.
الشكل
- المسارات بصيغة الجمع وبأحرف صغيرة مفصولة بشرطات (
/org-units،/job-descriptions)، والحقول بصيغة camelCase. - النص ثنائي اللغة بصيغة
{ "ar": …, "en": … }. العربية هي اللغة الأساسية: حيث يكون الاسم مطلوبًا، تكونarمطلوبة. - الأوقات بصيغة ISO 8601 بتوقيت UTC (
2026-10-24T09:46:14.331Z). - لكل كائن
idوexternalRefsوcreatedAtوupdatedAt(ولصفوف التدقيق وآثار الحذف حقول وقت خاصة بها). - تُرفض الحقول غير المعروفة في جسم الطلب (
422 validation_failed)، فلا يمر خطأ إملائي دون أن تلاحظه.
المعرّفات والمعرّفات الثابتة والمعرّفات الخارجية
| المفتاح | ما هو | استخدمه في |
|---|---|---|
id | معرّف جديرون (cuid). | استدعاء الواجهة البرمجية داخل بيئة واحدة. |
slug | مفتاح ثابت لا يتغير على صفوف الكتالوج: القطاعات والقطاعات الفرعية والعائلات الوظيفية والجدارات العامة. وصفوف مساحة العمل الخاصة قيمتها slug: null. | ربط صفوف الكتالوج بين بيئات جديرون. |
externalRefs | [{ system, externalId }]: معرّفاتك أنت، مربوطة بالسجل. | ربط سجلاتك أنت بسجلات جديرون، في كل بيئة. |
تختلف المعرّفات بين بيئات جديرون (الاختبار، والإنتاج، والنشر المخصص)، وتتغير عند إعادة تعبئة مساحة عمل تجريبية أو اختبارية. لذلك:
- لا تنسخ المعرّفات بين البيئات. وإن حفظتها فاحفظها لكل بيئة على حدة.
- اربط صفوف الكتالوج بـ
slug. - اربط صفوف مساحة العمل بـ
externalRefs: أنشئها أو عدّلها بنقاطPUT …/by-external/{system}/{externalId}، وابحث عنها بـ?externalSystem=&externalId=، وسمّها في أجسام الطلبات بصيغة{ "externalSystem": "…", "externalId": "…" }. انظر دليل المزامنة مع ERP.
system نص حر حتى 64 حرفًا (مثل oracle-hcm أو sap-sf)، وexternalId حتى 128 حرفًا.
الترقيم
كل قائمة مرقّمة بالمؤشر:
curl "https://jadiroon.com/api/v1/employees?limit=100" -H "Authorization: Bearer $JADIROON_KEY"
{ "data": [ … ], "nextCursor": "Y212bTdydTBxMDAwNmtuZGxlMGZ4NGl2dA" }
limitمن 1 إلى 100 (الافتراضي 50).- أعد
nextCursorفي المعاملcursorللصفحة التالية؛ وتعنيnextCursor: nullأنها الصفحة الأخيرة. - المؤشرات معتمة: لا تبنِها ولا تفك ترميزها. المؤشر المشوَّه يُرجع
422، لكن مؤشراً نصياً بسيطاً غير معروف قد يُرجع ببساطة صفحة لاحقة. - من دون
updatedSinceتأتي الصفوف بترتيبid، ومعه بترتيبupdatedAtثمid. - يحمل المؤشر موضعه في هذا الترتيب، فلا يُفسد تعديلُ صف أو حذفه أثناء التصفح المسارَ: لا يُتخطّى أي صف بعد المؤشر، ولا تفشل الصفحة التالية لأن آخر صف حُذف. ومع
updatedSinceينتقل الصف المعدَّل أثناء التصفح إلى النهاية فتقرؤه مرة أخرى، لذا أزل التكرار بحسبid. وتظل المؤشرات الصادرة قبل 2026-10-25 صالحة.
المزامنة التدريجية بـ updatedSince
تقبل كل قائمة updatedSince (ISO 8601). وتعيد الصفوف التي قيمة updatedAt فيها تساوي هذا الوقت أو بعده، بما فيها الصفوف المؤرشفة (مع archivedAt)، فتعرف بالأرشفة دون طلب منفصل.
حلقة مزامنة آمنة:
- سجّل الوقت الحالي
T. - اقرأ كل الصفحات مع
updatedSince= آخر علامة مائية لديك. - حدّث سجلاتك حسب
id(قد يظهر الصف نفسه مرتين إذا تغير أثناء التصفح). - اقرأ سجل المحذوفات مع
since= العلامة نفسها. - احفظ
Tناقص دقيقة واحدة علامةً مائية جديدة.
ما ينبغي معرفته:
- يتغير
updatedAtأيضًا عند تغيير السجل في التطبيق، وعندما يمسه تغيير مرتبط (مثل وظيفة تصبح بلا وحدة تنظيمية عند حذف وحدتها). - أول مزامنة بعد إطلاق الواجهة البرمجية: السجلات الموجودة قبل الإطلاق تحمل كلها
updatedAt= تاريخ الإطلاق، فتعيد أول مزامنة بـupdatedSinceكل شيء. ابدأ بقراءة كاملة. - سجل التدقيق يصفّي حسب
occurredAtبدلًا من ذلك، وصفوفه لا تتغير أبدًا. - تغييرات الكتالوج التي يجريها جديرون (القطاعات والقطاعات الفرعية والعائلات الوظيفية العامة) لا ترسل أحداث خطافات ويب. أعد قراءة
/sectorsو/sub-sectorsو/job-familiesدوريًا (مرة يوميًا تكفي). - إزالة قطاع فرعي أو عائلة وظيفية أو قطاع من الهيكل الوظيفي لمساحة عملك ترسل أحداث
<resource>.deleted، لكنها لا تترك أثر حذف (لم يُحذف شيء). قارن بقراءة كاملة للقائمة لاكتشافها دون خطافات الويب.
سجل المحذوفات
يمكن مزامنة الحذف النهائي دون خطافات الويب:
curl "https://jadiroon.com/api/v1/deleted?since=2026-10-24T00:00:00Z&resource=position" \
-H "Authorization: Bearer $JADIROON_KEY"
{
"data": [
{ "resource": "position", "id": "cmv…", "externalRefs": [{ "system": "oracle-hcm", "externalId": "POS-310" }], "deletedAt": "2026-10-24T10:02:11.000Z" }
],
"nextCursor": null
}
- كل حذف نهائي لسجل عام، في التطبيق أو عبر الواجهة البرمجية، يكتب أثر حذف يحمل
externalRefsكما كانت. وتُحفظ آثار الحذف 180 يومًا. - المعاملان
sinceوresource(مثلemployeeوorg_unitوjob_description) اختياريان، وlimitوcursorكالمعتاد. - لا ترى إلا آثار حذف الموارد التي يستطيع مفتاحك قراءتها. و
?resource=لمورد لا يستطيع قراءته تعيد403 forbidden، والمورد غير المعروف يعيد422 validation_failed. - إنهاء خدمة موظف (
DELETE /api/v1/employees/{id}) ليس حذفًا: يبقى السجل بالحالةFORMER_EMPLOYEE.
الكتابة
POSTينشئ، وPATCHيعدّل جزئيًا، وDELETEيحذف، وPUT …/by-external/…ينشئ أو يعدّل.PATCHلا يمسح أبدًا ما لم ترسله. تبقى الحقول غير المرسلة كما هي، بما فيها المصفوفات الفرعية مثل جدارات الوصف الوظيفي. أرسلnullلمسح حقل يقبل القيمة الفارغة.- لتغييرات الحالة نقاط خاصة بها (
…/archiveو…/closeو…/stageو…/hire)، فتعمل قواعد التطبيق نفسها.
الأخطاء
لكل خطأ الجسم نفسه:
{ "error": { "code": "unresolved_reference", "message": "Could not resolve org_unit reference", "details": { "resource": "org_unit", "ref": { "externalSystem": "oracle-hcm", "externalId": "ORG-999" } } } }
- اعتمد على
code(وعلىdetails.reasonحين يوجد)، لا علىmessage. الرسائل بالإنجليزية وقد تتغير. detailsاختياري ويختلف حسب الخطأ:issues(مشكلات على مستوى الحقول معpath)، وreason(القاعدة المحددة، مثلalready_appliedأوduplicate_person)، وrequired(مفاتيح الصلاحيات الناقصة)، وغيرها.- رموز أخطاء شاشات التطبيق لا تتسرب إلى الواجهة البرمجية؛ والقائمة التالية مغلقة. وتُعلن الرموز الجديدة في سجل التغييرات.
| الرمز | الحالة | المعنى |
|---|---|---|
unauthorized | 401 | مفتاح مفقود أو غير معروف أو ملغى أو منتهٍ. |
forbidden | 403 | المفتاح ينقصه صلاحية (details.required)، أو التكامل موقوف مؤقتًا، أو العنوان ليس في القائمة المسموحة، أو حاول مفتاح على مستوى النشر الكتابة. |
not_found | 404 | لا يوجد هذا السجل في مساحة عملك (وكذلك لسجلات مساحات العمل الأخرى). |
validation_failed | 422 | الطلب غير سليم أو يخالف قاعدة: الجسم ليس JSON أو غير صالح (details.issues أو details.reason)، أو قيمة خاطئة لـ limit أو cursor أو updatedSince أو since، أو resource غير معروف، أو غياب Idempotency-Key في الإدراج المجمّع. |
conflict | 409 | التغيير يتعارض مع الحالة الحالية؛ ويوضح details.reason كيف (مثل أن المعرّف الخارجي مربوط بسجل آخر، أو already_applied، أو opening_not_open). |
has_people | 409 | ما زال في الوظيفة موظفون. |
has_openings | 409 | ما زال للوظيفة شواغر أو نماذج تقييم مقابلات. |
has_children | 409 | ما زال للوحدة التنظيمية وحدات فرعية. |
unresolved_reference | 422 | مرجع في الجسم (parent أو orgUnit أو jobDescription أو manager …) غير موجود في مساحة عملك. |
ssco_managed | 409 | الوصف الوظيفي من الكتالوج الوطني SSCO وهو للقراءة فقط. |
idempotency_conflict | 409 | استُخدم Idempotency-Key لطلب مختلف، أو ما زال الطلب الأول به قيد التنفيذ. |
rate_limited | 429 | أكثر من 600 طلب في الدقيقة؛ انتظر Retry-After ثانية. |
too_many_jobs | 429 | للتكامل بالفعل مهمتا إدراج مجمّع في الانتظار أو قيد التشغيل. |
workspace_inactive | 403 | مساحة العمل موقوفة أو محذوفة. |
webhook_egress_not_configured | 422 | هذا النشر لا يسمح بأي خطافات ويب صادرة (لا توجد له قائمة مضيفين مسموحة). |
forbidden_host | 422 | مضيف عنوان خطاف الويب ليس عامًا أو ليس في القائمة المسموحة لهذا النشر. |
internal | 500 أو 502 | فشل شيء من جهتنا (502: تعذرت قراءة ملف محفوظ). أعد المحاولة مع مهلة متزايدة؛ ومع Idempotency-Key تكون إعادة المحاولة آمنة. |
منع التكرار
تقبل نقاط POST الترويسة Idempotency-Key (أي نص حتى 255 حرفًا، مثل UUID). وهي مطلوبة في الإدراج المجمّع.
- تُحفظ المفاتيح 24 ساعة لكل تكامل.
- المفتاح نفسه مع الطلب نفسه (الطريقة والمسار والجسم) يعيد الاستجابة المحفوظة (الحالة والجسم نفسيهما) دون تنفيذ الطلب مجددًا. وتحمل الاستجابة المعادة
Idempotent-Replayed: true؛ ولا تُعاد ترويسات الاستجابة الأصلية. - المفتاح نفسه مع طلب مختلف يعيد
409 idempotency_conflict. وكذلك طلب ثانٍ بينما الأول ما زال يعمل: أعد المحاولة بعد لحظة. وإذا لم يكتمل الطلب الأول (كأن انقطع)، يُحرَّر المفتاح بعد 90 ثانية من أول استخدام له، وعندها تُنفِّذ إعادة المحاولة الطلب. - استجابات 4xx تُحفظ أيضًا. بعد تصحيح طلب مرفوض أرسله بمفتاح جديد، وإلا عاد إليك الخطأ المحفوظ طوال 24 ساعة.
- استجابات 5xx لا تُحفظ: إعادة المحاولة بالمفتاح نفسه تنفذ الطلب مجددًا.
- لا يحتاج
PUT …/by-external/…إلى مفتاح: فهو بطبيعته لا يتكرر أثره.