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. 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:
| Applicant | Worker | |
|---|---|---|
| When created | Automatically by a Recruitment Check | Imported from your HRIS, created directly, or created when an applicant is hired |
| Lifecycle stage | Onboarding / pre-employment | Active / employed |
| Public ID | app_<id> | wkr_<id> |
| Counts toward active headcount | No | Yes |
| Eligible for renewal flows | No (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:
| Field | Required | Notes |
|---|---|---|
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. |
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.birthDate | conditional | ISO-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 | — | Lifecycle status, e.g. ACTIVE, INACTIVE, ON_LEAVE, TERMINATED. |
id | auto | Synthetic 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.
The required set above is the API minimum — a POST /workers needs only identity.displayName. The app's Add Worker wizard asks for more: Legal First Name, Legal Last Name, Date of Birth (DD/MM/YYYY, at least 12 years ago), Organisation, and Work Email. That's a deliberate UI guardrail to capture clean data up front, not an API constraint. 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.
Active vs. inactive
A worker's lifecycle is carried on employment.status:
employment.status | Behaviour |
|---|---|
ACTIVE | Shows in active staff lists. Eligible for new checks, Recruitment Checks, and renewal reminders. Counts toward compliance metrics. |
INACTIVE / TERMINATED | Read-only. History preserved, but the worker is excluded from active reports and no new operations are run against them. |
Setting the status to INACTIVE is the right move when employment ends — it preserves the audit trail without cluttering live reports. A hard delete is also possible but rarely the right answer.
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, can't be moved between them.
- 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
Deactivate (employment.status = INACTIVE) — history preserved
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 employment.status to INACTIVE. Use this on offboarding.
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:
| Field | Strength | Notes |
|---|---|---|
source.externalId | Strongest | Your authoritative employee ID. Set at create time and never reuse it. |
contact.workEmail | Strong | Unique 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.workEmailis unique within your organisation only. The same email can exist in another organisation. - Birth date format —
identity.birthDateis an ISO-8601 date (YYYY-MM-DD). Required for state checks that match on date of birth. - External ID —
source.externalIdis 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 in your organisation can see its worker records — access is scoped by organisation within your deployment. Separately, single-tenant isolation walls your whole deployment off from every other customer's.
- Roles (Admin / Manager / Staff) further restrict who can read PII, edit it, or delete records.
- Subject-access requests are served by
GETon 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.combefore hard-deleting for compliance reasons.
Best practice
- 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.
- Always set
source.externalId. Future-you, debugging a webhook 18 months from now, will thank you. - Deactivate, don't delete. Set
employment.statustoINACTIVE; hard deletion is for genuine mistakes. - Re-use, don't recreate. Look the person up by
source.externalIdbefore 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.
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
- Credentials → — the credentials that hang off a worker.
- Applicants → — people in recruitment, before they become workers.
- API Reference → — the exact endpoints for managing workers.