This guide shows how to keep an ERP or HR system (Oracle HCM, SAP SuccessFactors, Odoo, an in-house system) and Jadiroon in step: your system stays the source of truth for the records it owns, and Jadiroon tells you about everything that changes on its side.
1. Plan who owns what
| Data | Usually owned by | Direction |
|---|---|---|
| Organizational Structure (org units), positions | ERP | ERP → Jadiroon |
| Employees (people on positions, managers) | ERP | ERP → Jadiroon |
| Job descriptions | Jadiroon (or ERP, if it holds them) | either |
| Functional Structure catalog (sectors, sub-sectors, job families) | Jadiroon | Jadiroon → ERP (read only) |
| Candidates, openings, applications, interviews, offers | Jadiroon | Jadiroon → ERP |
| Hires | Jadiroon | Jadiroon → ERP (application.hired, employee.created) |
Give the integration only the permissions for what it writes and reads (see Scopes).
2. Link records with external ids
Each workspace record can carry links to your ids: externalRefs: [{ system, externalId }]. Pick one system name per source system and environment pair you sync with (for example oracle-hcm) and keep it forever.
Write with upsert by external id:
curl -X PUT https://jadiroon.com/api/v1/employees/by-external/oracle-hcm/EMP-1002 \
-H "Authorization: Bearer $JADIROON_KEY" -H "Content-Type: application/json" \
-d '{
"firstName": "Omar", "lastName": "Alqahtani",
"manager": { "externalSystem": "oracle-hcm", "externalId": "EMP-1001" },
"currentPosition": { "externalSystem": "oracle-hcm", "externalId": "POS-310" }
}'
- No record linked to
oracle-hcm/EMP-1002: one is created from the body and linked; the answer is201. - A linked record exists: the body is applied like a
PATCH(omitted fields stay); the answer is200. - Upserts exist for org units, positions and employees (
PUT /api/v1/{org-units|positions|employees}/by-external/{system}/{externalId}), and in bulk for those plus candidates. - Job descriptions have no upsert endpoint: create them with
POST /api/v1/job-descriptionsand sendexternalRef: { externalSystem, externalId }in the body (or in a laterPATCH) to link your id. Positions can then name them by your id. - Find a record by your id without changing it:
GET /api/v1/employees?externalSystem=oracle-hcm&externalId=EMP-1002(both parameters, or neither). - One external id links to one record, and one record has at most one id per
system. Linking an id that is already taken returns409 conflict, unless the record that held it no longer exists (for example it was deleted in the app): the old link is then dropped and the id links to the new record.
3. Reference other records by your ids
Bodies name related records either by Jadiroon id or by your id:
{ "orgUnit": { "id": "cmv…" } }
{ "orgUnit": { "externalSystem": "oracle-hcm", "externalId": "ORG-200" } }
| Field | On | Points to |
|---|---|---|
parent | org unit | org unit |
orgUnit, jobDescription | position | org unit, job description |
manager, currentPosition | employee | employee, position |
position | opening | position |
candidate | application | candidate |
A reference that can't be found in your workspace returns 422 unresolved_reference, with the reference in details. Load parents before children: org units top-down, then job descriptions, then positions, then employees (managers before their reports, or a second pass to set manager).
4. Catalog rows: slugs, not ids
Sectors, sub-sectors and job families of the national catalog are shared by every workspace. Map them by their slug, which never changes and is the same in every Jadiroon environment. Ids are not: they differ per environment and change when a test workspace is reseeded. Never copy an id from one Jadiroon environment to another.
Rows your workspace created itself (custom families or sectors) have slug: null; link them with your own mapping table.
5. Keep Jadiroon's changes flowing back
Two options, often combined:
- Webhooks (near real time): subscribe an endpoint to the events you care about, for example
employee.*andapplication.hired. See Webhooks. - Polling: read each list with
updatedSinceand the deletion feed on a schedule. This is also the safety net if your endpoint was down longer than the retry window.
Every webhook payload and every object carries externalRefs, so you can match it to your record without storing Jadiroon ids.
6. What happens to links when records go away
- A hard delete (in the app or the API) removes the record's links in the same step and writes a tombstone with the links it had, readable for 180 days at
GET /api/v1/deleted. - If a linked record was deleted in the app and you upsert the same external id again, Jadiroon creates a new record and links it: you don't need to clean up first.
- Hiring moves a candidate's links to the new employee record.
- Offboarding (
DELETE /api/v1/employees/{id}) keeps the record and its links; the status becomesFORMER_EMPLOYEE.
7. Checklist
- One integration per environment, with the narrowest scope that works.
- One
systemname per source system. - Load order: org units → job descriptions → positions → employees.
- First load in bulk (see Bulk migration), then upsert changes one by one or in small batches.
- Subscribe to webhooks and also poll daily with
updatedSince+/deletedas a safety net. - Re-read the catalog lists (
/sectors,/sub-sectors,/job-families) daily.