الطلب هو مرشح واحد على شاغر واحد. يتنقّل بين مراحل التوظيف (تقدّم، فرز، مقابلات، عرض) حتى يُعيَّن المرشح أو يُرفض. استخدم هذه النقاط لإضافة المرشحين من منصة توظيف أو نظام تتبع متقدمين آخر، ولمتابعتهم ونقلهم بين المراحل، ولتعيينهم فيصبحوا موظفين.
جميع النقاط تحت /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 | قيمة منطقية | صدر خطاب عرض؛ اقرأه من العروض بالمعرّف نفسه. |
appliedAt | ISO 8601 | |
externalRefs | مصفوفة | [{ system, externalId }] روابط إلى أنظمتك. |
createdAt، updatedAt | ISO 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 conflict | already_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"
}