Introduction
TIP
View the Job Management API Reference
The Job Management APIs give programmatic access to your organisation's job structure: the jobs themselves, the job functions and job levels they are classified against, the job-related custom OUs they belong to, and the assignment of jobs to users.
All endpoints sit under https://{corpname}.csod.com/services/api/x/chr-jobmgmt-app/v1/.
Resource model
The API is organised into five families, each with its own section in the reference.
| Family | Manages |
|---|---|
| Jobs | Job records, plus their status, job function, job level and custom OU assignments, next jobs, and the users assigned to them |
| Job Functions | Job function records, their status timeline and their position in the job function hierarchy |
| Job Levels | Job level records, their status timeline and their position in the job level hierarchy |
| Job-related Custom OUs | Custom OU types, the custom OUs within a type, and their status and parent timelines |
| User Job Assignments | Which job a user holds, over time |
Hierarchies are read one level at a time. Ask a record for its children to walk down, or for its parents timeline to see where it has sat over time. See Hierarchies.
Effective dating
This is the concept that most distinguishes the API from a plain CRUD surface. Status changes, hierarchy changes and assignments are not overwritten, they are recorded as timelines. Every entry carries the dates it applies for, so history and future-dated changes are both preserved and readable.
A timeline entry looks like this:
{
"assignmentId": "7c1f2d4e-9a3b-4c5d-8e6f-0a1b2c3d4e5f",
"active": true,
"dateEffective": "2026-01-01",
"dateUnassign": null,
"endDate": null,
"isCurrent": true,
"isHistoric": false,
"isFuture": false,
"notes": "Approved by HR."
}
Read isCurrent, isHistoric and isFuture rather than comparing dates yourself. At most one entry on a timeline is current.
See Effective dating for how supersession works, how to schedule and correct changes, and the date rules the API enforces.
All dates are calendar dates, YYYY-MM-DD, in the portal's time zone.
Reading data
Collections are token-paged. Pass pageSize to set the page length and pageToken to continue:
GET /services/api/x/chr-jobmgmt-app/v1/jobs?pageSize=100
{
"results": [],
"paging": { "tokens": { "next": "opaque-or-null" } }
}
Pass paging.tokens.next back as pageToken to fetch the next page. An absent token means you have reached the last page.
A short page is not the end
Only the absence of a next token indicates the last page. A page with fewer than pageSize records does not.
Use fields to limit the representation, either repeated or comma-separated:
GET .../v1/jobs?fields=jobId&fields=displayTitle
Some collections exclude expensive members such as titles, descriptions and customFields by default; request them explicitly through fields when you need a full export. An unrecognised name returns 400 INVALID_FIELDS and names every field it did not recognise.
The job, job function, job level and custom OU collections also double as their own search endpoints. Filter with titleOrCode, narrow with activeOnly or rootsOnly, and sort with orderBy and orderDirection. Archived records are never returned.
Writing data
Create with POST, and update with PATCH using a JSON Merge Patch document:
PATCH /services/api/x/chr-jobmgmt-app/v1/jobs/{jobId}
Content-Type: application/merge-patch+json
Send only the members you are changing. A member that is absent keeps its current value, a member with a value replaces it, and a nullable member sent explicitly as null is cleared. There is no lost-update guard, so concurrent writes to the same record are last-write-wins.
Archiving is a soft delete that cannot be undone
DELETE archives a record. It is retained for reporting but stops appearing in reads and lists, and there is no endpoint to restore it. Records still in use cannot be archived, so remove the assignments first.
Errors
Every failure uses the standard Cornerstone error envelope. The code is what your integration should branch on; the messages are for humans.
{
"errors": [
{
"code": "DATE_UNASSIGN_BEFORE_DATE_EFFECTIVE",
"details": [
{ "message": "dateUnassign must not fall before dateEffective.",
"field": "dateUnassign",
"value": "2025-12-31" }
]
}
]
}
field names the part of the request at fault, either a body member or a query parameter, and is null when the error concerns the request as a whole. Each endpoint documents the codes it can return in its reference entry.
Scopes and permissions
Every request needs an OAuth 2.0 scope on the application and a security permission on the linked user account. Scopes follow a <resource>:<operation> shape:
| Resource | Scopes |
|---|---|
| Jobs | job:read, job:create, job:update, job:delete |
| Job functions | job-function:read, job-function:create, job-function:update, job-function:delete |
| Job levels | job-level:read, job-level:create, job-level:update, job-level:delete |
| Job-related custom OUs | job-custom-ou:read, job-custom-ou:create, job-custom-ou:update, job-custom-ou:delete |
| User job assignments | job-assignment:read, job-assignment:create, job-assignment:update, job-assignment:delete |
The matching security permissions are Job Management API - Jobs - View and - Manage, Job Management API - Job Structure - View and - Manage, and for user assignments Job Management API - Assignment - View (User), - Manage (User) and - Manage (Job). Assigning a job to a user needs both the user-side and job-side Manage permissions.
Reads are constrained to the records the caller's permission covers. Each endpoint lists the exact scope and permission it requires in its reference entry, and every endpoint is listed individually in List of Scopes and Security Permissions for APIs.