الطلبات

للمسؤولين

الطلب هو مرشح واحد على شاغر واحد. يتنقّل بين مراحل التوظيف (تقدّم، فرز، مقابلات، عرض) حتى يُعيَّن المرشح أو يُرفض. استخدم هذه النقاط لإضافة المرشحين من منصة توظيف أو نظام تتبع متقدمين آخر، ولمتابعتهم ونقلهم بين المراحل، ولتعيينهم فيصبحوا موظفين.

جميع النقاط تحت /api/v1 وتتطلب مفتاح واجهة برمجية (Authorization: Bearer jdr_live_…) ينشئه مسؤول مساحة العمل من الإعدادات ← التكاملات.

النقاط

الطريقة والمسارما تفعلهالصلاحية
GET /api/v1/applicationsعرض الطلبات (ترقيم بالمؤشر، وupdatedSince، و?openingId=&candidateId=&stage=)recruitment.view
POST /api/v1/applicationsإضافة مرشح إلى شاغرrecruitment.act
GET /api/v1/applications/{id}عرض طلب واحدrecruitment.view
POST /api/v1/applications/{id}/stageنقل الطلب إلى مرحلةrecruitment.act (وOFFERED تتطلب أيضاً recruitment.offer.issue)
POST /api/v1/applications/{id}/rejectرفض الطلبrecruitment.act
POST /api/v1/applications/{id}/hireتعيين المرشحrecruitment.hire وrecruitment.candidate.contact

صلاحية recruitment.act تشمل recruitment.view. والمعرّف من مساحة عمل أخرى يُعيد 404 not_found.

كائن الطلب

الحقلالنوعملاحظات
idنصمعرّف الطلب.
openingId، positionIdنصالشاغر والوظيفة التي يجري التوظيف لها.
personIdنصالمرشح؛ وبعد التعيين يصبح المعرّف نفسه معرّف الموظف.
candidateكائن{ id, firstName, lastName, email, phone }. يُخفى email وphone دون recruitment.candidate.contact، حتى بعد التعيين.
stageنصAPPLIED أو SCREENED أو ASSESSMENT أو INTERVIEWING أو OFFERED أو HIRED أو REJECTED.
screeningكائنفرز السيرة الذاتية بالذكاء الاصطناعي: { status, score }. تكون status بقيمة PENDING أثناء الفرز (عند وجود سيرة ذاتية فقط)، ثم DONE أو FAILED أو QUOTA_EXCEEDED؛ وscore من 0 إلى 100 أو null.
rejectionReasonنص أو nullعند REJECTED بسبب موثّق (انظر أدناه).
hasOfferقيمة منطقيةصدر خطاب عرض؛ اقرأه من العروض بالمعرّف نفسه.
appliedAtISO 8601
externalRefsمصفوفة[{ system, externalId }] روابط إلى أنظمتك.
createdAt، updatedAtISO 8601

إضافة مرشح

يأخذ POST /api/v1/applications الصيغة { "openingId": "…", "candidate": { "id": "…" } }، ويمكن تحديد المرشح بالصيغة { "externalSystem", "externalId" } أيضاً. يجب أن يكون المرشح موجوداً (أنشئه من المرشحون)، وأن يكون الشاغر OPEN (409 conflict، opening_not_open).

  • يجب أن يكون مسار توظيف الشاغر مفتوحاً للمرشحين الخارجيين، كما في صفحة الوظائف لديك: الشاغر INTERNAL_ONLY يُعيد 409 conflict (opening_internal_only)، والشاغر INTERNAL_FIRST يُعيد 409 conflict (not_yet_external مع details.externalAt) حتى تنتهي فترة الأولوية الداخلية.
  • الوظيفة التي أُرشف وصفها الوظيفي لا تقبل طلبات جديدة (422 validation_failed، archived).
  • المرشح الموجود على الشاغر نفسه يُعيد 409 conflict مع details.reason بقيمة already_applied وdetails.applicationId.
  • الوصف الوظيفي المخصص للسعوديين فقط يتطلب مرشحاً سعودياً (422 validation_failed، saudi_only)، ويجب أن تكون جنسية المرشح معروفة للتحقق من ذلك (nationality_required).
  • عند وجود سيرة ذاتية للمرشح يعمل الفرز بالذكاء الاصطناعي بعد الاستجابة؛ تابع application.updated مع screening في changedFields.

النقل والرفض والتعيين

  • المرحلة: POST …/stage مع { "stage": "INTERVIEWING" }. المراحل المسموحة APPLIED وSCREENED وINTERVIEWING وOFFERED؛ واستخدم /reject و/hire لغيرها. النقل إلى المرحلة الحالية لا يغيّر شيئاً. والنقل إلى SCREENED يُسند تقييمات الوظيفة كما في التطبيق، وقد ينتقل الطلب بعدها إلى ASSESSMENT تلقائياً. ويتلقى المرشح بريد المرحلة الذي أعدّته مساحة عملك.
  • الرفض: POST …/reject مع { "reason": "withdrew", "note": "…" } اختيارياً. الأسباب: not-shortlisted وnot-saudi-saudization-restricted وwithdrew وover-qualified وunder-qualified وfailed-interview وother.
  • التعيين: POST …/hire مع { "startDate": "2026-11-01", "manager": { "id": "…" } } اختيارياً (manager موظف، بمعرّفه أو بمعرّفه الخارجي). يصبح المرشح موظفاً على وظيفة الشاغر بالمعرّف نفسه، ويظهر في GET /api/v1/employees. وتنتقل externalRefs الخاصة بالمرشح معه إلى الموظف. الوظيفة الممتلئة تُعيد 409 conflict (position_full)؛ والشخص الذي لم يعد مرشحاً يُعيد 409 conflict (not_a_candidate)؛ والطلب الذي أُغلق شاغره يُعيد 409 conflict (opening_not_open)؛ وإذا جرى تعيينان للمرشح نفسه في الوقت نفسه (عبر طلبين له مثلاً) ينجح أحدهما ويُعيد الآخر 409 conflict (concurrent_hire). ويتطلب التعيين recruitment.candidate.contact أيضاً لأنه يكشف بيانات تواصل الشخص (403 forbidden، candidate_contact_required).
  • الطلبات المعيَّنة والمرفوضة: الطلب في مرحلة HIRED نهائي. نقله أو رفضه أو تعيينه مرة أخرى يُعيد 409 conflict مع details.reason بقيمة already_hired، ولا يتغير شيء. والطلب REJECTED لا يمكن تعيينه: يُعيد /hire القيمة 409 conflict (already_rejected). أعده أولاً إلى مرحلة نشطة عبر /stage إن أردت إعادة النظر في المرشح. ورفض طلب مرفوض بالفعل ما زال لا يغيّر شيئاً. وتنطبق القواعد نفسها في التطبيق.

أحداث خطافات الويب

الحدثمتىdata.object
application.createdتقدّم مرشح من صفحة الوظائف، أو إضافته عبر الواجهة البرمجيةالطلب
application.stage_changedتغيّر المرحلة (من التطبيق أو الواجهة البرمجية أو الفرز التلقائي)الطلب
application.rejectedرفض الطلب (يُرسل مع application.stage_changed)الطلب
application.updatedانتهاء فرز السيرة الذاتية بالذكاء الاصطناعي أو إعادته (changedFields: ["screening"])الطلب
application.hiredتعيين المرشح (من التطبيق أو الواجهة البرمجية)الطلب

التعيين يرسل أيضاً employee.created للشخص (بالمعرّف نفسه). وتتبع الحمولات قاعدة الإخفاء نفسها: نقطة الاستقبال التي لا يملك تكاملها recruitment.candidate.contact تتلقى candidate.email وcandidate.phone مخفيين.

الأخطاء

الحالة والرمزالمعنى
403 forbiddenالمفتاح لا يملك صلاحية من الجدول أعلاه، أو candidate_contact_required عند التعيين.
404 not_foundلا يوجد طلب بهذا المعرّف في مساحة عملك.
409 conflictalready_applied أو opening_not_open أو opening_internal_only أو not_yet_external أو position_full أو not_a_candidate أو concurrent_hire أو already_hired أو already_rejected.
422 unresolved_referenceمرجع الشاغر أو المرشح أو المدير لا يطابق.
422 validation_failedالطلب غير صالح، أو saudi_only / nationality_required / archived.

مثال

curl -X POST https://jadiroon.com/api/v1/applications \
  -H "Authorization: Bearer $JADIROON_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: jobboard-APP-5531" \
  -d '{ "openingId": "cmvm6inad0002kncr1pytpf2x", "candidate": { "externalSystem": "jobboard", "externalId": "C-881" } }'

الاستجابة 201 Created. وللمفتاح الذي لا يملك recruitment.candidate.contact تكون:

{
  "id": "cmvm6j7au000jkncrm8jc4e3a",
  "openingId": "cmvm6inad0002kncr1pytpf2x",
  "positionId": "cmvikf8270086knoq85hjhu3u",
  "personId": "cmvm6it2n0008kncr3n9kpkkx",
  "candidate": { "id": "cmvm6it2n0008kncr3n9kpkkx", "firstName": "Faisal", "lastName": "Alqahtani", "email": "f•••@example.com", "phone": "05•• ••• •12" },
  "stage": "APPLIED",
  "screening": { "status": "DONE", "score": null },
  "rejectionReason": null,
  "hasOffer": false,
  "appliedAt": "2026-10-24T09:11:32.023Z",
  "externalRefs": [],
  "createdAt": "2026-10-24T09:11:32.023Z",
  "updatedAt": "2026-10-24T09:11:32.023Z"
}