Entity-level read

For HR administrators

On a dedicated deployment, an entity or holding system can read every workspace at once through a deployment-level read integration. It is the one exception to the rule that a request never names another workspace, so it is read-only and tightly controlled.

The integration is created by a super admin in the Platform Console → Integrations (console permission integrations.act, held by the Owner role), not by a Workspace Admin. See Console integrations for creating it, its keys and webhooks.

What it can do

  • Read-only: every GET endpoint of the public API, across all active workspaces. Suspended and deleted workspaces are never read. Every write (POST, PATCH, PUT, DELETE) returns 403 forbidden.
  • Full read: no permission set and no contact masking. Candidate email, phone and national ID are returned in full.
  • Webhooks across all workspaces: its endpoints receive events from every active workspace. Each envelope carries workspaceId.
  • Audit feed: GET /api/v1/audit-events returns the audit rows of every active workspace plus platform rows (workspaceId: null, for example console actions), in one oldest-first order.
  • Not available: GET /api/v1/bulk-jobs/{id} (bulk jobs belong to the workspace integration that posted them).

Safeguards

  • The integration must have an IP allowlist (IP addresses or CIDRs; a range covering every address is refused) before a key can be created (422 ip_allowlist_required). A key whose integration has no allowlist is refused at request time.
  • Every key needs an expiry date (422 expires_at_required).
  • API reads are not audited. Key and endpoint changes are written to the platform audit log (admin.integration.*).

workspaceId on objects and ?workspaceId=

EndpointDeployment-level key
Lists (/employees, /candidates, /org-units, /positions, /job-descriptions, /pay-scales, /openings, /applications, /offers, /interviews, /users, /roles, /deleted)All active workspaces. Every object gets workspaceId. ?workspaceId= narrows to one workspace (404 if it is unknown or not active).
Get by id (/employees/{id}, /candidates/{id}, …, /candidates/{id}/cv, /offers/{id}/file)The record's own workspace; workspaceId is added. 404 if the workspace is not active, or ?workspaceId= names another one.
Functional Structure (/sectors, /sub-sectors, /job-families, /job-families/{jobFamilyId})?workspaceId= is required (422 without it). Returns that workspace's view, without workspaceId on the rows: catalog rows are shared, so they have no single owner.
/audit-eventsItems already carry workspaceId (null for platform rows). ?workspaceId= narrows to one workspace and leaves platform rows out.

Workspace keys ignore ?workspaceId= and never get workspaceId on objects.

Pagination across workspaces

Lists walk workspaces in id order, and inside each workspace use the usual order (id, or updatedAt then id with updatedSince). The nextCursor remembers the workspace and the last row, so pages stay stable when workspaces are added or deactivated in between. With updatedSince, rows are ordered per workspace, not globally: read every page, then move your watermark to the time the sync started. The audit feed is the exception: it is one global oldest-first order.

Key lifetime and rotation

Every key of a deployment-level integration expires. Plan the rotation before the date: create a new key in the console (it is shown once), deploy it to the entity system, check that its Last used time moves, then revoke the old key. Keys work only from addresses on the integration's allowlist, so add the entity system's new addresses there before moving it.

What the audit feed adds

Platform rows (workspaceId: null) are Platform Console activity: workspace creation and lifecycle changes, super-admin entries into and exits from workspaces, console role, admin and integration changes (including when a webhook signing secret is revealed), edits to the Jadiroon catalog (taxonomy.*: sectors, sub-sectors, job families, skills and their links; target.type is snake_case, such as sub_sector or sub_sector_job_family, and a link's target.id is <fromId>:<toId>), and failed console sign-in attempts (admin.login_failed, kept on purpose: the feed is a full read). Filter on action if the entity SIEM only needs some of them. See Audit feed for SIEM.

A first call

curl "https://<deployment>/api/v1/employees?limit=100" -H "Authorization: Bearer $ENTITY_KEY"
curl "https://<deployment>/api/v1/job-families?workspaceId=cmv…" -H "Authorization: Bearer $ENTITY_KEY"

The first call pages through the employees of every active workspace, each with its workspaceId; the second reads one workspace's Functional Structure.