Skip to main content

Workers

A worker is a person record in your organisation — a staff member, volunteer, or contractor whose compliance you track. Workers hold the person's identifying details and link to every credential, Recruitment Check, ban, and check that's ever been run for them.

A person whose journey started via a Recruitment Check (and hasn't been formally onboarded yet) is called an applicant instead. The two are closely related — see Applicants vs. workers below.

What a worker represents​

One person. Examples:

  • A nurse you employ, with an active AHPRA registration and a current WWC.
  • A teacher at your school, with a registration plus a police check.
  • A contractor with NDIS worker screening and right-to-work documentation.

A worker always belongs to exactly one organisation, chosen when the record is created and not editable afterwards — see Moving a worker to another organisation for what to do when someone transfers. If two organisations engage the same physical person, each keeps its own worker record — same human, different records. Records are never shared across organisations. And because every customer runs on its own single-tenant Oho deployment, reached at its own <tenant>.weareoho.com subdomain, records are never shared across tenants either.

Applicants vs. workers​

The platform separates people you're considering from people you've onboarded:

ApplicantWorker
When createdAutomatically by a Recruitment CheckImported from your HRIS, created directly, or created when an applicant is hired
Lifecycle stageOnboarding / pre-employmentActive / employed
Public IDapp_<id>wkr_<id>
Counts toward active headcountNoYes
Eligible for renewal flowsNo (still being onboarded)Yes

Hiring an applicant isn't a single rename — you create a worker record and move the applicant's credentials onto it (a credential ownership transfer; see Credentials). The applicant record is retired and the worker carries on with the same verified history. Most of this guide talks about workers; everything carries over to applicants unless noted.

Core fields​

Worker attributes are grouped into nested objects — identity, contact, employment, and source — rather than a flat list. The fields you'll use most:

FieldRequiredNotes
identity.displayName✓The only field required on create. How the person is shown across Oho.
identity.firstName, identity.lastName—Used for matching during credential verification. A person with one legal name puts it in lastName — see People with one name.
contact.workEmail—The destination for Recruitment Check emails. (contact.personalEmail is also available.)
contact.workPhone / contact.personalPhone—Recommended for SMS-based flows and identity verification.
identity.birthDateconditionalISO-8601 date (YYYY-MM-DD). Required for some credential types (NSW WWC, SA WWC, NDIS Worker Screening, etc.).
source.externalId—Strongly recommended. Your internal employee/contractor ID. Becomes the join key with your HRIS. Queryable via GET /workers?externalId=....
employment.status—HR lifecycle status, e.g. ACTIVE, INACTIVE, ON_LEAVE, TERMINATED. Recorded and filterable; it does not start or stop checking.
isActive—Top level, not inside employment. Oho's monitoring switch. false pauses scheduled verification. Defaults to true.
employment.manager—The worker's direct manager (another worker), set by id or externalId. Drives the manager copy of credential expiry notifications.
idautoSynthetic wkr_ identifier assigned by Oho on creation. The internal URN is never exposed.

If you don't have a birth date at create time, submit without it — you can update later, and Oho can also auto-enrich the worker's identity.birthDate from data the person provides during a Recruitment Check or a successful registry check.

API minimum vs. the app wizard

The required set above is the API minimum — a POST /workers needs only identity.displayName. The app's Add Worker wizard asks for a little more: Legal Last Name and Organisation. (Legal First Name is optional there, so a person with one legal name can be recorded as they are.) That's a deliberate UI guardrail to capture clean data up front, not an API constraint. Date of Birth and Work Email are prompted for but not enforced there either — the wizard only validates them when you fill them in (it won't accept a date of birth less than 12 years ago, and a work email must be unique). The 12-year floor is the wizard's alone — the API applies no age floor at all, so a POST /workers (and a spreadsheet import, which takes the same path) accepts any valid ISO-8601 date. If you're following the Add a Worker guide in the app, use its required set; if you're integrating directly against the API, displayName alone will create the record.

People with one name​

Not everyone has a given name and a family name. Record a person who holds one legal name by putting that name in Legal Last Name (identity.lastName) and leaving Legal First Name blank. The app says as much under the field — "Leave blank if this worker goes by a single name" — and the wizard saves without it.

The last-name field is the one to use because it is what the registers are searched on. VEVO, the VIC and WA Working With Children registers and the QLD Blue Card portal all match on the family name; several of them take nothing else but a card number.

Never put a placeholder in the surname

A -, a ., N/A or a repeat of the given name is submitted to the register literally, so the check errors or comes back not found, and it goes on failing on every re-check. One worker loaded with the surname - had her VEVO passport check fail for exactly this reason, while the credential that happened to hold her real single name as its surname verified first time.

If a worker already carries a placeholder, edit the worker, move the real name into Legal Last Name, clear Legal First Name, and then correct the same fields on each of their credentials.

Credentials carry their own holder name — the name as printed on the card — and that, not the worker record, is what a check is run under. So set the credential's Last name / Surname to the single name as well.

A few credential forms still require a given name: AHPRA, QLD Blue Card, NT Ochre Card, NSW teacher registration and NDIS Worker Screening. If the holder has only one name, email support@weareoho.com rather than inventing a given name — an invented name is what the register would then be searched under, which is the problem this section exists to avoid. SA Working With Children already accepts a blank first name.

A worker with no surname on record at all is skipped by some checks outright, so the one field that must never be empty is the last name.

Active vs. inactive​

A worker carries two independent states, and they answer different questions:

FieldQuestion it answersWhere it comes fromWhat it changes
employment.statusDoes this person still work here?Your HR system, a spreadsheet import, or an editNothing on its own. It is recorded, shown on the profile, and available as a Status filter.
isActive (top level)Is Oho still checking this person?An admin, in Oho or over the APIEverything. false takes every credential they hold out of scheduled verification and out of compliance triage.

employment.status does not stop Oho checking anyone. A worker whose HR record says TERMINATED but whose isActive is still true goes on being scanned against the registers, goes on raising expiry alerts, and goes on counting in the compliance dashboards. Setting the status is how you record the fact; setting isActive is how you act on it.

The reverse is just as true: isActive: false on its own doesn't record that anyone left. Most offboarding sets both — the status for your records, the switch for Oho.

Connectors and spreadsheet imports do set both

This is about writing the fields directly. A connector maps your HR system's own status values to Oho's, and derives the monitoring switch from that mapping, so a leaver your HR feed marks terminated does stop being checked. A spreadsheet import works the same way — its Status column sets both. It's the direct API write that has to set isActive itself.

isActive is not inside employment

It sits at the top level of the worker body, alongside identity, employment and source. Send it anywhere else — nested under employment, or inside the attributes wrapper that only appears in responses — and it is ignored, with no error. The request succeeds, the status changes, and the worker carries on being scanned.

{
"employment": { "status": "INACTIVE", "endDate": "2026-10-09" },
"isActive": false
}

See Offboard a worker for the full offboarding path, in the app and over the API, including why a PUT that omits isActive quietly switches scanning back on.

Relationships​

Organisation
└── Worker (one person)
├── Credentials (their checks, licences, clearances)
├── Recruitment Checks (information requests sent to them)
├── Bans (any disqualifying register entries)
└── Checks history (police checks, etc.)
  • Worker → Organisation (N:1) — every worker belongs to one organisation. There's no way to move one in the app; see Moving a worker to another organisation.
  • Worker → Credentials (1:N) — a person can hold many credentials, in any combination, with their own statuses and expiries.
  • Worker → Recruitment Checks (1:N) — a person can have any number of Recruitment Checks sent to them over time. Each one is a distinct event.
  • Worker → Bans (0:N) — bans are surfaced as flags but stored separately so they preserve their public-register provenance.

Lifecycle​

Onboard
│ Create applicant via Check ─┐
│ OR ├── First compliance picture
│ Create worker directly ─┘
▼
Active
│ Receive webhooks as credential statuses change
│ Periodically re-check or send renewal Recruitment Checks
▼
Offboard
Pause monitoring (isActive = false) — stops the checking, history preserved
AND/OR record the HR fact (employment.status = INACTIVE)
OR Delete — only for genuine errors (e.g. wrong person created)

Common operations​

These are the conceptual operations — the exact REST/GraphQL syntax is in the API Reference.

Create​

Create a worker before doing anything else with them. Even minimal details (name + email) are enough — you can enrich later.

create_worker(identity.displayName, [identity.firstName], [identity.lastName],
[contact.workEmail], [source.externalId], [identity.birthDate])
→ returns Worker with synthetic wkr_ id

Only identity.displayName is required; everything else can be filled in later. To avoid duplicates, look the person up first by their HRIS identifier (GET /workers?externalId=...) before creating a new record — source.externalId is the strongest match key, with contact.workEmail (unique within your organisation) as a fallback.

Read​

Fetch a worker by their public wkr_ id. The response includes their fields plus links to their credentials, Recruitment Checks, and any bans.

Update​

Patch any of the editable fields. Sensitive updates (DOB after creation) require admin role.

Deactivate​

Patch top-level isActive to false. This is the one that stops the checking, and it's what you want on offboarding. Patch employment.status alongside it if you also want the HR lifecycle recorded — on its own it changes nothing. Use PATCH, not PUT: a replace that omits isActive resets it to true.

Delete​

Hard-delete a worker. Reserved for genuine errors. Removes the person record but preserves audit log entries. Prefer deactivation in almost every case.

Linking to your HR system​

Every customer eventually needs to join Oho's worker records back to their HRIS. Two reliable joins exist:

FieldStrengthNotes
source.externalIdStrongestYour authoritative employee ID. Set at create time and never reuse it.
contact.workEmailStrongUnique within an organisation. Watch for email changes when staff change surname.

Avoid relying on first/last name combinations — they're not unique and they change.

Auto-enrichment​

When the platform receives new identifying data about a worker (from a successful registry check, from a Recruitment Check submission, from a state-government webhook), it can update the worker record. Examples:

  • A WWC verification returns a different DOB than you supplied → the worker's DOB is corrected.
  • A Recruitment Check submission supplies a phone number you didn't have → it's added.

Enrichment is non-destructive by default: missing fields are filled in, existing fields aren't overwritten unless the new value comes from a higher-trust source (e.g. a government registry overrides a self-asserted value).

Enrichment is auditable — every change is recorded.

Validation rules​

  • Email uniqueness — contact.workEmail is unique within your organisation only. The same email can exist in another organisation.
  • Birth date format — identity.birthDate is an ISO-8601 date (YYYY-MM-DD). Required for state checks that match on date of birth.
  • External ID — source.externalId is an opaque string, your choice. Recommended to be globally unique within your HR system.

Privacy & access​

Worker records store personally identifiable information (PII). Your responsibilities under the Australian Privacy Principles (and any other applicable law) apply.

  • Only users assigned to a worker's organisation can see that worker — access is scoped by organisation for every role except Super Admin. Separately, single-tenant isolation walls your whole deployment off from every other customer's.
  • Roles (Super Admin / Admin / Manager / Observer) further restrict who can read PII, edit it, or delete records. See Roles & access.
  • Subject-access requests are served by GET on the worker.
  • Correction requests are served by PATCH.
  • Right-to-erasure requests can be served by deactivation; full deletion may have audit implications — check with support@weareoho.com before hard-deleting for compliance reasons.

Best practice​

  1. Create the record first. Always create the worker (or let a Recruitment Check create the applicant) before submitting their first credential. It costs you nothing and gives you a clean history.
  2. Always set source.externalId. Future-you, debugging a webhook 18 months from now, will thank you.
  3. Deactivate, don't delete. Set isActive to false — and employment.status to INACTIVE as well if you want the lifecycle on record. Hard deletion is for genuine mistakes.
  4. Re-use, don't recreate. Look the person up by source.externalId before creating — duplicates are the most common avoidable error.

Identifiers​

Workers and applicants are addressed by a synthetic, prefixed public ID minted by the server at create time:

  • Worker: wkr_<id> (e.g. wkr_V1StGXR8Z5jdHi6B)
  • Applicant: app_<id> (e.g. app_Qz7yT2mB)

You never supply these — the server returns them in the create response and the Location header. To find a worker by your own upstream HRIS identifier, use GET /workers?externalId=.... See API Basics for the full identifier convention.

Internal URNs are not exposed

Internally each record has a URN (urn:li:worker:wkr_..., urn:li:applicant:app_...) built from the public ID. This is an implementation detail — it is never returned by the API and must not be used as a resource identifier.

Next​