The Functional Structure is the part of the job taxonomy your workspace uses: its sector, the sub-sectors you selected, and the job families under them (job descriptions have their own page). These endpoints are read-only: the Functional Structure is set up in the app, and your ERP or HR system reads it to map its own job catalog.
All endpoints sit under /api/v1 and need an API key (Authorization: Bearer jdr_live_…) created by your Workspace Admin in Settings → Integrations.
Endpoints
| Method and path | What it does | Permission |
|---|---|---|
GET /api/v1/sectors | List your workspace's sectors | structure.functional.view |
GET /api/v1/sub-sectors | List the sub-sectors selected in your Functional Structure | structure.functional.view |
GET /api/v1/job-families | List the job families your workspace uses | structure.functional.view |
GET /api/v1/job-families/{jobFamilyId} | Get one job family | structure.functional.view |
Every list takes limit (1–100, default 50) and cursor and returns { data, nextCursor }. updatedSince (ISO 8601) returns only rows changed since then, archived rows included. ?externalSystem=&externalId= (both together) finds the row linked to your own id.
What each list contains
- Sectors: the sector your workspace operates in, plus any sector your workspace created.
- Sub-sectors: only the sub-sectors selected in your Functional Structure.
- Job families: only the families your workspace has added (shared catalog families and your own). Families other workspaces created are never listed, even when they sit under the same sub-sector.
Archived rows still in use are returned with archivedAt set.
Mapping across environments: slug
Shared catalog rows (sectors, sub-sectors, job families and skills from the Jadiroon catalog) return a slug, for example healthcare-services. The slug never changes and is the same in every Jadiroon environment, so map catalog rows by slug. Rows your workspace created return slug: null; map those by externalRefs.
Ids differ between Jadiroon environments and can change when sample data is re-seeded: never copy ids from one environment to another.
The sector object
| Field | Type | Notes |
|---|---|---|
id | string | Jadiroon id. |
slug | string or null | Stable key of a catalog sector; null for your own. |
name | { ar, en } | |
archivedAt | ISO 8601 or null | |
externalRefs | array | [{ system, externalId }]. |
createdAt, updatedAt | ISO 8601 |
The sub-sector object
| Field | Type | Notes |
|---|---|---|
id | string | Jadiroon id. |
slug | string or null | Stable key of a catalog sub-sector; null for your own. |
sectorId | string | The sector it belongs to. |
name | { ar, en } | |
sortOrder | integer | Your display order (lower first). |
archivedAt | ISO 8601 or null | |
externalRefs | array | [{ system, externalId }]. |
createdAt, updatedAt | ISO 8601 | updatedAt also moves when you select or reorder the sub-sector. |
The job family object
A job family is keyed by its family id. Your workspace can use the same family more than once, under different mandates; each use is an instance.
| Field | Type | Notes |
|---|---|---|
id | string | The job family id. |
slug | string or null | Stable key of a catalog family; null for your own. |
name | { ar, en } | |
archivedAt | ISO 8601 or null | |
instances | array | Your workspace's instances, see below. |
externalRefs | array | [{ system, externalId }]. |
createdAt, updatedAt | ISO 8601 | updatedAt is the latest change to the family or any of its instances, including removing one of its instances. |
Each instance has:
| Field | Type | Notes |
|---|---|---|
id | string | The instance id (job descriptions point at it as workspaceJobFamilyId). |
mandate | string | REGULATORY, EXECUTIVE or INTERNAL. |
subSectors | array | [{ id, sortOrder }]: your selected sub-sectors the family sits under, and the family's position in each (null until reordered). |
skills | object | { technical: [...], general: [...] }, the skills chosen for this instance, each { id, slug, name }. |
createdAt, updatedAt | ISO 8601 |
Webhook events
| Event | When | data.object |
|---|---|---|
sector.created | Your workspace creates its own sector during setup | The sector |
sector.updated | Your workspace switches to a sector | The sector |
sector.deleted | Your workspace stops using a catalog sector (it switched sectors) | { id, externalRefs } |
sub_sector.created | Your workspace creates its own sub-sector | The sub-sector |
sub_sector.updated | A sub-sector is selected or reordered | The sub-sector |
sub_sector.deleted | A sub-sector is deselected | { id, externalRefs } |
job_family.created | A family is created, or added to your workspace for the first time | The job family |
job_family.updated | A family's name, an instance's mandate, skills or order changes, an instance is added, duplicated or removed, a sub-sector the family sits under is selected or deselected (its subSectors change), or one of your own skills on an instance is renamed or deleted | The job family |
job_family.deleted | Your workspace stops using a family (its last instance was removed), or your own family was deleted | { id, externalRefs } |
<resource>.bulk_changed | Too many rows changed at once to list them | { resource } |
Duplicating a job family instance into another mandate sends job_family.updated and, when its job descriptions and positions are copied, job_description.created and position.created for each copy (or <resource>.bulk_changed beyond 50).
*.deleted here usually means the row left your Functional Structure: a catalog sector, sub-sector or family still exists in the catalog. Only a family your workspace created is really deleted, and it then also appears in GET /api/v1/deleted?resource=job_family. A deselection never appears in /deleted: if you may have missed a *.deleted event, re-read the full list (without updatedSince) and compare it with yours; anything missing from it has left your Functional Structure.
Changes to the shared catalog itself (made by Jadiroon) send no events. Re-read these lists from time to time, for example daily with updatedSince, to pick them up.
Errors
| Status and code | Meaning |
|---|---|
403 forbidden | The key lacks structure.functional.view. |
404 not_found | Your workspace doesn't use a job family with that id. |
422 validation_failed | limit, cursor or updatedSince is invalid. |
422 validation_failed | Only one of externalSystem and externalId was sent. |
Example
curl https://jadiroon.com/api/v1/job-families?limit=1 \
-H "Authorization: Bearer $JADIROON_KEY"
{
"data": [
{
"id": "cmvjx0h1t0001kn3o9c2a7def",
"slug": "nursing",
"name": { "ar": "التمريض", "en": "Nursing" },
"archivedAt": null,
"instances": [
{
"id": "cmvjx0h9k0003kn3oa1b2c3d4",
"mandate": "EXECUTIVE",
"subSectors": [{ "id": "cmvjx0g7r0000kn3o5e6f7a8b", "sortOrder": 0 }],
"skills": {
"technical": [{ "id": "cmvjx0f2a0007kn3o1a2b3c4d", "slug": "patient-assessment", "name": { "ar": "تقييم المرضى", "en": "Patient assessment" } }],
"general": [{ "id": "cmvjx0f3b0008kn3o5e6f7a8b", "slug": "teamwork", "name": { "ar": "العمل الجماعي", "en": "Teamwork" } }]
},
"createdAt": "2026-10-20T09:12:44.120Z",
"updatedAt": "2026-10-21T13:40:02.511Z"
}
],
"externalRefs": [],
"createdAt": "2026-09-01T00:00:00.000Z",
"updatedAt": "2026-10-21T13:40:02.511Z"
}
],
"nextCursor": "Y212angwaDF0MDAwMWtuM285YzJhN2RlZg"
}