الأوصاف الوظيفية هي أوصاف مساحة عملك الخاصة في الهيكل الوظيفي: يُصنَّف كل وصف تحت قطاع فرعي ومجموعة وظيفية اخترتهما، ويسرد المهارات التي يتطلبها ومستوى كل منها، ويمكن أن يحمل مرتبة أجر افتراضية. والوظائف تتبع وصفاً وظيفياً. استخدم هذه النقاط لمزامنة الأوصاف الوظيفية في جديرون مع نظام تخطيط الموارد (ERP) أو نظام الموارد البشرية لديك.
جميع النقاط تحت /api/v1 وتتطلب مفتاح واجهة برمجية (Authorization: Bearer jdr_live_…) ينشئه مسؤول مساحة العمل من الإعدادات ← التكاملات.
النقاط
| الطريقة والمسار | ما تفعله | الصلاحية |
|---|---|---|
GET /api/v1/job-descriptions | عرض الأوصاف الوظيفية (ترقيم بالمؤشر، وupdatedSince، والبحث بالمعرّف الخارجي) | structure.functional.view أو recruitment.view |
POST /api/v1/job-descriptions | إنشاء وصف وظيفي | structure.functional.act |
GET /api/v1/job-descriptions/{id} | عرض وصف وظيفي واحد | structure.functional.view أو recruitment.view |
PATCH /api/v1/job-descriptions/{id} | تعديل وصف وظيفي؛ الحقول غير المرسلة تبقى كما هي | structure.functional.act |
POST /api/v1/job-descriptions/{id}/archive | أرشفة وصف وظيفي | structure.functional.act |
POST /api/v1/job-descriptions/{id}/unarchive | استعادة وصف وظيفي مؤرشف | structure.functional.act |
لا يوجد DELETE: أرشف الوصف الوظيفي بدلاً من حذفه. وتحديد مرتبة الأجر الافتراضية أو تغييرها (payScale وpayGrade) يتطلب أيضاً structure.functional.salary؛ وبدونها يُعاد 403 forbidden. وقراءة الأجر تتطلبها كذلك: بدون structure.functional.salary تكون payScaleId وpayGradeId وsalaryMin وsalaryMax بالقيمة null في كل استجابة (القوائم والقراءة المفردة واستجابات عمليات الكتابة) وفي حمولات خطافات الويب.
لا تُعرض إلا الأوصاف الوظيفية الخاصة بمساحة عملك. لمعرفة معرّفات القطاعات الفرعية والمجموعات الوظيفية والمهارات اقرأ GET /api/v1/sub-sectors وGET /api/v1/job-families (انظر الهيكل الوظيفي).
كائن الوصف الوظيفي
| الحقل | النوع | ملاحظات |
|---|---|---|
id | نص | معرّف جديرون. يختلف المعرّف بين بيئات جديرون؛ اربط سجلاتك عبر externalRefs. |
name | { ar, en } | اسم الوصف الوظيفي. |
purpose | { ar, en } | الغرض من الوظيفة. |
subSectorId | نص أو null | القطاع الفرعي الذي صُنّف تحته. يكون null فقط لوصف أُضيف بالمسمّى من الهيكل التنظيمي ولم يُصنَّف بعد. |
jobFamilyId | نص أو null | المجموعة الوظيفية (id في GET /api/v1/job-families). |
workspaceJobFamilyId | نص أو null | نسخة المجموعة (instances[].id في المجموعة الوظيفية) التي صُنّف تحتها. يكون null إذا أُزيلت تلك النسخة. |
mandate | نص أو null | REGULATORY أو EXECUTIVE أو INTERNAL: صفة تلك النسخة. |
jobType | نص | MANAGERIAL (إشرافية عليا) أو SUPERVISORY (إشرافية) أو SPECIALIST (تخصصية) أو SUPPORT (مساندة). |
workLocation | { ar, en } | موقع العمل الافتراضي. |
qualifications | كائن | education وspecialization وexperienceField وyearsExperience وcertifications: نص حر، كل منها نص أو null. |
desiredHeadcount | عدد صحيح | العدد المستهدف من الأشخاص لهذا الوصف. |
saudiPriority | نص | سياسة التوطين: NONE أو PREFER أو ONLY. |
payScaleId، payGradeId | نص أو null | سلم الرواتب والمرتبة الافتراضيان. تكون null بدون structure.functional.salary. |
salaryMin، salaryMax | عدد صحيح أو null | نطاق الراتب السنوي للمرتبة بالريال السعودي. للقراءة فقط: يُحدَّث مع المرتبة. تكون null بدون structure.functional.salary. |
skills | كائن | { technical: [...], general: [...] }، وكل عنصر { id, slug, name, requiredLevel }. مستويات المهارات الفنية من 1 إلى 5، والعامة من 1 إلى 3. يكون slug null لمهارات مساحة عملك الخاصة. |
sscoCode | نص أو null | رمز المهنة في التصنيف السعودي الموحد للمهن (SSCO) إذا اعتُمد الوصف من الدليل الوطني. هذه الأوصاف للقراءة فقط عبر الواجهة البرمجية. |
archivedAt | ISO 8601 أو null | يُضبط عند أرشفة الوصف الوظيفي. |
externalRefs | مصفوفة | [{ system, externalId }] روابط بأنظمتك. |
createdAt، updatedAt | ISO 8601 | يتغيّر updatedAt أيضاً عند تعديل الوصف من داخل التطبيق، أو عند إزالة نسخة مجموعته أو سلم رواتبه. |
الإنشاء
يتطلب POST الحقل name (بقيمتي ar وen) وsubSectorId وjobFamilyId. القواعد هي نفسها في محرر الأوصاف الوظيفية في التطبيق:
- يجب أن يكون القطاع الفرعي مختاراً في هيكلك الوظيفي (
422 validation_failedمعdetails.reasonبقيمةsub_sector_not_selected). - يجب أن تقع المجموعة الوظيفية تحت ذلك القطاع الفرعي (
job_family_not_in_sub_sector) وأن تكون مختارة في مساحة عملك (job_family_not_selected). - إذا كانت المجموعة في مساحة عملك أكثر من مرة (نسخة لكل صفة)، أرسل
mandateلاختيار النسخة (mandate_required؛ والصفة غير الموجودة تُعيدmandate_not_found). - يجب أن تكون المهارات من المهارات المختارة لتلك النسخة (
skill_not_in_job_familyمعdetails.skillId). لا يمكن إنشاء مهارات جديدة عبر الواجهة البرمجية. - قيمة
requiredLevelمن 1 إلى 5 للمهارات الفنية ومن 1 إلى 3 للعامة، وأي قيمة أخرى تُرفض. وإذا لم تُرسل تبقى للمهارة قيمتها الحالية، أو تأخذ المهارة المضافة حديثاً القيمة الافتراضية: 3 (فنية) أو 2 (عامة).
الحقول الاختيارية: purpose وmandate وjobType (الافتراضي SPECIALIST) وworkLocation وqualifications وdesiredHeadcount (الافتراضي 1) وsaudiPriority (الافتراضي NONE) وpayScale وpayGrade وskills وexternalRef. الحقول غير المعروفة والحقول للقراءة فقط (salaryMin وsalaryMax وsscoCode وarchivedAt) تُرفض بـ 422 validation_failed.
يحدد payScale السلم بمعرّف جديرون أو بمعرّفك، ويأخذ payGrade معرّف جديرون وهو مطلوب مع السلم. يجب أن يتبع السلم مساحة عملك (422 unresolved_reference) وأن تتبع المرتبة السلم (422 validation_failed مع details.reason بقيمة invalid_pay_grade).
يربط externalRef: { externalSystem, externalId } معرّفك بالوصف الوظيفي في الطلب نفسه، فتستطيع الوظائف الإشارة إليه بـ jobDescription: { externalSystem, externalId }، ويمكنك البحث عنه بـ GET /api/v1/job-descriptions?externalSystem=…&externalId=…. وإذا كان المعرّف مرتبطاً بوصف وظيفي آخر يكون الرد 409 conflict، أما الربط المتبقي من وصف وظيفي لم يعد موجوداً فيُزال ويرتبط المعرّف بهذا الوصف. ويقبله PATCH أيضاً لربط وصف موجود. وللوصف الوظيفي رابط واحد لكل نظام: إرسال externalRef لنظام مرتبط به مسبقاً يستبدل externalId القديم (فلا يعود المعرّف القديم يجده).
{
"externalRef": { "externalSystem": "oracle-hcm", "externalId": "JOB-12" },
"name": { "ar": "أخصائي موارد بشرية", "en": "HR Specialist" },
"purpose": { "ar": "إدارة عمليات الموارد البشرية اليومية", "en": "Runs day-to-day HR operations" },
"subSectorId": "cmvj…",
"jobFamilyId": "cmvj…",
"mandate": "EXECUTIVE",
"skills": {
"technical": [{ "id": "cmvj…", "requiredLevel": 4 }],
"general": [{ "id": "cmvj…" }]
}
}
التعديل
يغيّر PATCH الحقول التي ترسلها فقط. والمهارات تتبع القاعدة نفسها: إذا لم ترسل skills.technical (أو skills.general، أو skills كله) يحتفظ الوصف الوظيفي بكل مهاراته من ذلك النوع بمستوياتها الحالية. أما إرسال مصفوفة فيستبدل مهارات ذلك النوع ضمن مهارات نسخة المجموعة (المهارات المتاحة للاختيار)؛ والمهارات التي يحملها الوصف خارج تلك المجموعة تبقى كما هي، كما في محرر التطبيق. أرسل [] لإزالة كل مهارات ذلك النوع من تلك المجموعة. والمهارة المرسلة دون requiredLevel تحتفظ بمستواها الحالي.
- تغيير
jobFamilyIdأوmandateينقل الوصف إلى نسخة مجموعة أخرى. إذا لم ترسل مصفوفة مهارات فيجب أن تكون كل مهارة باقية مختارة أيضاً للنسخة الجديدة؛ وإلا يكون الرد422 validation_failedمعdetails.reasonبقيمةskills_not_in_new_job_family، وعليك إرسال المصفوفات. - القيمة
payScale: nullتزيل مرتبة الأجر الافتراضية وتمسحsalaryMinوsalaryMax. وتغيير السلم يتطلب مرتبة من السلم الجديد. وإرسالpayScaleأوpayGradeيعيد قراءة نطاق الراتب من المرتبة. - طلب
PATCHدونpayScaleوpayGradeيتركsalaryMinوsalaryMaxكما هما محفوظين، بما في ذلك نطاق حُدّد دون مرتبة أجر (في محرر البيانات مثلاً). - الوصف المُضاف بالمسمّى من الهيكل التنظيمي يحتاج
subSectorIdوjobFamilyIdقبل تعديله (taxonomy_required). - إذا أُزيلت نسخة مجموعة الوصف ولم تعد المجموعة موجودة في مساحة عملك إطلاقاً، يُعيد كل
PATCHالرمز422 validation_failedمعdetails.reasonبقيمةjob_family_not_selected(مع أن محرر التطبيق يفتحه). أرسلjobFamilyId(وsubSectorId) تستخدمه مساحة عملك لإعادة تصنيفه. - يُتحقق من زوج القطاع الفرعي والمجموعة في كل
PATCH: إذا أُزيل القطاع الفرعي من هيكلك الوظيفي يكون الردsub_sector_not_selected.
الأوصاف التي تحمل sscoCode جاءت من الدليل الوطني أثناء الإعداد الأولي وتُستبدل عند إعادة تلك الخطوة، لذلك هي للقراءة فقط عبر الواجهة البرمجية: يُعيد PATCH والأرشفة والاستعادة 409 ssco_managed. عدّلها من داخل التطبيق.
الأرشفة
يضبط POST /api/v1/job-descriptions/{id}/archive قيمة archivedAt ويغلق التوظيف على الوظائف المفتوحة التابعة للوصف وشواغرها المفتوحة. أرشفة وصف مؤرشف لا تغيّر شيئاً وتُعيده كما هو. ولا يمكن اختيار وصف مؤرشف لوظيفة جديدة. ويمسح POST /api/v1/job-descriptions/{id}/unarchive قيمة archivedAt، ويبقى التوظيف مغلقاً.
لا تُحذف الأوصاف الوظيفية أبداً عبر الواجهة البرمجية. لكن قد تُحذف من داخل التطبيق (مثلاً عند إلغاء اختيار قطاعها الفرعي أو مجموعتها الوظيفية، أو عبر محرر البيانات). يظهر هذا الحذف في GET /api/v1/deleted?resource=job_description لمدة 180 يوماً، وتبقى وظائفها مع jobDescriptionId: null.
أحداث خطافات الويب
| الحدث | متى | data.object |
|---|---|---|
job_description.created | إنشاء وصف وظيفي أو نسخه (من التطبيق أو الواجهة البرمجية)، ومنه الوصف المنسوخ عند نسخ مجموعة وظيفية مع أوصافها الوظيفية | الوصف الوظيفي |
job_description.updated | تعديل وصف وظيفي، ومنه إعادة تسمية مهارة خاصة بمساحة عملك يسردها أو حذفها (changedFields: ["skills"])، وتغيّر نطاقه عند تعديل مرتبة رواتبه (changedFields: ["salaryMin", "salaryMax"])؛ يسرد data.changedFields الحقول عند توفرها. وبدون structure.functional.salary تُستبعد حقول الأجر من changedFields، ولا يُرسل التعديل الذي لم يغيّر إلا الأجر | الوصف الوظيفي |
job_description.archived | أرشفة وصف وظيفي | الوصف الوظيفي |
job_description.unarchived | استعادة وصف وظيفي مؤرشف | الوصف الوظيفي |
job_description.deleted | حذف وصف وظيفي من داخل التطبيق | { id, externalRefs } |
job_description.bulk_changed | تغيّر عدد كبير من الأوصاف دفعة واحدة (الإعداد الأولي، محرر البيانات) | { resource: "job_description" } |
أرشفة وصف وظيفي أو حذفه، أو إزالة قطاعات فرعية أو مجموعات وظيفية من هيكلك الوظيفي، يرسل أيضاً position.updated لكل وظيفة أُغلق التوظيف عليها. وأرشفة وصف وظيفي أو حذفه ترسل كذلك opening.closed لكل شاغر أغلقته (وopening.bulk_changed إذا تجاوزت 50). بعد job_description.bulk_changed أعد قراءة القائمة مع updatedSince بقيمة occurredAt للحدث، واقرأ GET /api/v1/deleted?resource=job_description&since=… لمعرفة الأوصاف المحذوفة. تعديل أقسام بطاقة الوصف (المهام، مؤشرات الأداء، جهات التواصل، التقييم) لا يرسل حدثاً لأنها ليست جزءاً من كائن الواجهة البرمجية.
الأخطاء
| الحالة والرمز | المعنى |
|---|---|
403 forbidden | لا يملك المفتاح الصلاحية المذكورة في الجدول أعلاه، أو أُرسلت حقول الأجر دون structure.functional.salary. |
404 not_found | لا يوجد وصف وظيفي بهذا المعرّف في مساحة عملك. |
409 ssco_managed | الوصف من الدليل الوطني وهو للقراءة فقط عبر الواجهة البرمجية. |
409 conflict | قيمة externalRef مرتبطة بوصف وظيفي آخر. |
422 validation_failed | الطلب غير صالح أو يخالف إحدى القواعد أعلاه؛ يوضح details.reason السبب. |
422 unresolved_reference | تعذّر العثور على payScale في مساحة عملك. |
مثال
curl -X PATCH https://jadiroon.com/api/v1/job-descriptions/cmvk2a9d10007kn5s3x8e4ghi \
-H "Authorization: Bearer $JADIROON_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": { "en": "Senior HR Specialist" } }'
يتغيّر الاسم الإنجليزي فقط، وتبقى المهارات ومستوياتها كما كانت:
{
"id": "cmvk2a9d10007kn5s3x8e4ghi",
"name": { "ar": "أخصائي موارد بشرية", "en": "Senior HR Specialist" },
"purpose": { "ar": "إدارة عمليات الموارد البشرية اليومية", "en": "Runs day-to-day HR operations" },
"subSectorId": "cmvjx0h1t0001kn3o9c2a7def",
"jobFamilyId": "cmvjx0h1t0002kn3o1b5c8xyz",
"workspaceJobFamilyId": "cmvjx0h1t0003kn3o6d4e2uvw",
"mandate": "EXECUTIVE",
"jobType": "SPECIALIST",
"workLocation": { "ar": null, "en": null },
"qualifications": { "education": "بكالوريوس", "specialization": null, "experienceField": null, "yearsExperience": "3 سنوات", "certifications": null },
"desiredHeadcount": 2,
"saudiPriority": "NONE",
"payScaleId": null,
"payGradeId": null,
"salaryMin": null,
"salaryMax": null,
"skills": {
"technical": [{ "id": "cmvjx0h1t0004kn3o7f3g1rst", "slug": "hr-operations", "name": { "ar": "عمليات الموارد البشرية", "en": "HR operations" }, "requiredLevel": 4 }],
"general": [{ "id": "cmvjx0h1t0005kn3o8h2i9opq", "slug": "communication", "name": { "ar": "التواصل", "en": "Communication" }, "requiredLevel": 2 }]
},
"sscoCode": null,
"archivedAt": null,
"externalRefs": [],
"createdAt": "2026-10-22T15:02:11.204Z",
"updatedAt": "2026-10-22T16:40:03.518Z"
}