Org units are the nodes of your Organizational Structure: the entity, sectors, agencies, general administrations, administrations, sections and units, each with one parent. Use these endpoints to keep the tree in Jadiroon in sync with your ERP or HR system.
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/org-units | List units (cursor pagination, updatedSince, external-id lookup) | structure.org.view |
POST /api/v1/org-units | Create a unit | structure.org.act |
GET /api/v1/org-units/{id} | Get one unit | structure.org.view |
PATCH /api/v1/org-units/{id} | Update a unit; omitted fields stay unchanged | structure.org.act |
DELETE /api/v1/org-units/{id} | Delete a unit that has no child units | structure.org.act |
PUT /api/v1/org-units/by-external/{system}/{externalId} | Create or update by your own system's id | structure.org.act |
POST /api/v1/org-units/bulk | Upsert up to 1,000 org units by external id, async (see Bulk upsert) | structure.org.act |
structure.org.act includes structure.org.view.
The org unit object
| Field | Type | Notes |
|---|---|---|
id | string | Jadiroon id. Ids differ between Jadiroon environments; link your records with externalRefs. |
name | { ar, en } | name.ar is required. |
type | string | ENTITY, SECTOR, AGENCY, BRANCH, GENERAL_ADMIN, ADMIN, SECTION or UNIT. |
parentId | string or null | null for a root unit. |
function | { ar, en } | The unit's function or specialization. |
headName, headRole | string or null | Who heads the unit and their title. |
headcount | integer | Current headcount (0 or more). |
ssoCode | string or null | Saudi Unified Classification code, read-only. |
status | string | DRAFT or APPROVED. |
sortOrder | integer or null | Display order, read-only. |
externalRefs | array | [{ system, externalId }] links to your systems. |
createdAt, updatedAt | ISO 8601 | updatedAt also moves when the unit's data changes through the app. |
Creating and updating
POST takes name, type and optionally parent, function, headName, headRole, headcount and status (new units are DRAFT unless you send status). Unknown fields are rejected.
parent names the parent unit either by Jadiroon id or by your own id:
{ "parent": { "id": "cmv…" } }
{ "parent": { "externalSystem": "oracle-hcm", "externalId": "ORG-100" } }
{ "parent": null }
null moves the unit to the root. A parent that can't be found in your workspace returns 422 unresolved_reference. Moving a unit under itself or under one of its own descendants returns 422 validation_failed with details.reason self_parent or cycle.
Upsert by external id
PUT /api/v1/org-units/by-external/oracle-hcm/ORG-200 looks up the unit linked to oracle-hcm / ORG-200:
- Linked unit found: the body is applied like a
PATCHand the response is200. - No linked unit: a unit is created from the body (send at least
name.arandtype) and linked to the external id, and the response is201.
system is up to 64 characters, externalId up to 128. To find a unit by your id without changing it, call GET /api/v1/org-units?externalSystem=oracle-hcm&externalId=ORG-200 (send both parameters; one alone returns 422 validation_failed).
Deleting
DELETE only removes a unit with no child units. Otherwise it returns 409 has_children with details.childCount: move or delete the children first.
When a unit is deleted:
- Positions placed in it stay, but become unplaced (no org unit). Their
updatedAtmoves, and aposition.updatedevent is sent for each, up to 500 positions; above that, oneposition.bulk_changedcovers the rest. - Workload tasks of the unit are deleted with it.
- Its external links are removed, and the deletion appears in
GET /api/v1/deleted?resource=org_unitfor 180 days.
Webhook events
| Event | When | data.object |
|---|---|---|
org_unit.created | A unit is created (app or API) | The org unit |
org_unit.updated | A unit changes; data.changedFields lists the fields | The org unit |
org_unit.deleted | A unit is deleted | { id, externalRefs } |
org_unit.bulk_changed | The structure was imported (file, template, URL) or replaced in the app | { resource: "org_unit" } |
After org_unit.bulk_changed, re-read the list with updatedSince set to the event's occurredAt, and read GET /api/v1/deleted?resource=org_unit&since=… for removed units. A URL import that also creates positions or people sends position.bulk_changed / employee.bulk_changed as well.
Errors
| Status and code | Meaning |
|---|---|
403 forbidden | The key lacks the permission in the table above. |
404 not_found | No unit with that id in your workspace. |
409 has_children | The unit still has child units. |
409 conflict | The external id is already linked to another unit. |
422 validation_failed | The body is invalid; details explains why. |
422 unresolved_reference | parent could not be found. |
Example
curl -X PUT https://jadiroon.com/api/v1/org-units/by-external/oracle-hcm/ORG-200 \
-H "Authorization: Bearer $JADIROON_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": { "ar": "إدارة الموارد البشرية", "en": "Human Resources" },
"type": "ADMIN",
"parent": { "externalSystem": "oracle-hcm", "externalId": "ORG-100" },
"headcount": 12
}'
The first call creates and links the unit and answers 201 Created; repeating it updates the same unit and answers 200 OK with the same body shape:
{
"id": "cmvjmf15k0008kn4q404rqwgw",
"name": { "ar": "إدارة الموارد البشرية", "en": "Human Resources" },
"type": "ADMIN",
"parentId": "cmvjmeq4p0002kn4qq820gqll",
"function": { "ar": null, "en": null },
"headName": null,
"headRole": null,
"headcount": 12,
"ssoCode": null,
"status": "DRAFT",
"sortOrder": null,
"externalRefs": [{ "system": "oracle-hcm", "externalId": "ORG-200" }],
"createdAt": "2026-10-22T14:12:52.761Z",
"updatedAt": "2026-10-22T14:12:52.761Z"
}