Overview: authentication, keys and scopes

For HR administrators

The Jadiroon public API lets your ERP, HR system or data platform push and pull every core record of your workspace: the Organizational and Functional Structure, positions, employees, candidates, openings, applications, interviews and offers. Webhooks tell your systems about every change, bulk upsert loads up to 1,000 records per request for migrations, and an audit feed streams the audit log to your SIEM.

The API applies the same rules as the app. A record written through the API goes through the same validation, permission checks and side effects as the same action on screen, and it is recorded in the audit log with your integration as the actor.

Base URL and format

  • Base path: https://<your Jadiroon domain>/api/v1, for example https://jadiroon.com/api/v1.
  • JSON only, in and out (Content-Type: application/json). Field names are camelCase; bilingual text is { "ar": "…", "en": "…" }; times are ISO 8601 in UTC.
  • The machine-readable description is at /api/v1/openapi.json (OpenAPI 3.1, no key needed). The API reference page renders it.
  • Ids, pagination, errors and idempotency follow the conventions.

Integrations and API keys

An integration is a named machine client, for example "Oracle HCM – production". It owns:

  • a permission scope (which modules it may read or change),
  • one or more API keys,
  • an optional IP allowlist,
  • zero or more webhook endpoints.

Only holders of the locked Workspace Admin role manage integrations, in Settings → Integrations (see Integrations). Each environment (for example a test and a production workspace) needs its own integration and keys.

Keys

  • A key looks like jdr_live_ followed by 40 letters and digits. It is shown once, when it is created; Jadiroon stores only a SHA-256 hash and the first 12 characters (the prefix you see in the list and in the audit log).
  • A key may have an expiry date. A revoked or expired key gets 401 unauthorized.
  • An integration can hold several keys at once, so you can rotate without downtime: create a new key, deploy it, check its Last used time, then revoke the old one.
  • Keep keys in a secret store, never in source code or browser apps.

Authenticating

Send the key as a bearer token on every request:

curl https://jadiroon.com/api/v1/ping -H "Authorization: Bearer $JADIROON_KEY"

GET /api/v1/ping needs no permission and answers with the integration the key belongs to, which makes it a good first call:

{ "ok": true, "actor": { "kind": "integration", "integrationId": "cmv…", "name": "Oracle HCM – production", "keyPrefix": "jdr_live_8Gq" }, "workspaceId": "cmv…" }

Scopes (permissions)

An integration holds workspace permission keys from the same catalog as the Roles tab: View and Act per module, plus a few named keys. Its data scope is always the whole workspace.

KeyWhat it unlocks in the API
structure.org.view / structure.org.actRead / write org units and positions
structure.functional.view / structure.functional.actRead the Functional Structure (sectors, sub-sectors, job families) and job descriptions / write job descriptions
structure.functional.salaryRead pay scales and the pay fields of positions and job descriptions (without it they are null in responses and webhook payloads, and pay changes are left out of the audit feed); write pay fields
people.view / people.actRead / write employees
recruitment.view / recruitment.actRead candidates, openings, applications, interviews and offers / create and update candidates, applications and interviews
recruitment.hiring.openOpen and close openings
recruitment.offer.issueMove an application to the offer stage
recruitment.hireHire a candidate (also needs recruitment.candidate.contact)
recruitment.candidate.contactSee candidate email, phone and national ID; without it they are masked in responses and webhook payloads, and CV and offer-letter downloads return 403
users.viewRead staff users and roles
audit.viewRead the audit feed and subscribe to audit.recorded

Rules that come with the catalog:

  • Act includes View for the same module. recruitment.candidate.contact does not imply anything else.
  • A key without the permission an endpoint needs gets 403 forbidden with details.required listing the keys.
  • Webhooks follow the same scope: an endpoint only receives events of resources its integration can read.
  • Each resource page lists the exact permission per endpoint, and so does the reference (x-permission).

Rate limits

  • 600 requests per minute per key, counted in fixed one-minute windows shared by every server.
  • Above the limit the API answers 429 rate_limited with a Retry-After header (seconds until the next window). Wait that long, then continue.
  • A bulk upsert request counts as one request, whatever its row count.
  • Each key has its own budget; rotating keys does not reset anyone else's.

IP allowlist

A Workspace Admin can restrict an integration to IP addresses or CIDR ranges (IPv4 or IPv6), in the integration's Access tab. A request from any other address gets 403 forbidden ("Request IP is not on the integration allowlist"). An empty list allows every address for a workspace integration. A deployment-level read integration must always have a list.

The address checked is the client's public IP as seen by the server. On Jadiroon's cloud it comes from the hosting edge, which overwrites X-Forwarded-For and X-Real-IP, so a client cannot fake it by sending those headers. On a self-hosted deployment, the operator sets TRUSTED_PROXY to the number of reverse proxies in front of Jadiroon (for example 1) or to a comma list of the proxies' IP addresses or CIDR ranges; the client IP is then read from the right of X-Forwarded-For, skipping those proxies, and entries a client added on the left are ignored. A self-hosted deployment behind a proxy must set TRUSTED_PROXY. Without it, the deployment trusts no forwarded header: every integration with an allowlist gets 403 forbidden, and sign-in limits apply per account instead of per address (someone who knows an account's email can keep that account rate-limited).

Responses that stop every request

Status and codeWhen
401 unauthorizedNo Authorization: Bearer header, an unknown key, or a revoked or expired key.
403 forbiddenThe integration is paused, or the request IP is not on its allowlist. Every key of the integration gets this until it is resumed or the list is fixed.
403 workspace_inactiveThe workspace is suspended or deleted.
429 rate_limitedToo many requests this minute; see Retry-After.

What is recorded

  • Every write is recorded in the workspace audit log with the actor Integration · (integration name), the key prefix, and the request's IP address and user agent. It shows in Settings → Audit log and in the record's History panel.
  • Reads are not recorded.
  • Key, permission, allowlist and endpoint changes are recorded as settings.integration.* actions.

Where to go next