الأوصاف الوظيفية

للمسؤولين

الأوصاف الوظيفية هي أوصاف مساحة عملك الخاصة في الهيكل الوظيفي: يُصنَّف كل وصف تحت قطاع فرعي ومجموعة وظيفية اخترتهما، ويسرد المهارات التي يتطلبها ومستوى كل منها، ويمكن أن يحمل مرتبة أجر افتراضية. والوظائف تتبع وصفاً وظيفياً. استخدم هذه النقاط لمزامنة الأوصاف الوظيفية في جديرون مع نظام تخطيط الموارد (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نص أو nullREGULATORY أو 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) إذا اعتُمد الوصف من الدليل الوطني. هذه الأوصاف للقراءة فقط عبر الواجهة البرمجية.
archivedAtISO 8601 أو nullيُضبط عند أرشفة الوصف الوظيفي.
externalRefsمصفوفة[{ system, externalId }] روابط بأنظمتك.
createdAt، updatedAtISO 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"
}