A secure, read-only way to pull wellbeing and office-ergonomics reporting about your people, organised by group.
Which teams and groups exist in our organisation?
An unpaginated call returning every group you can report on.
For each group you getHow is everyone in this group tracking on wellbeing?
A per-person scorecard across four everyday areas, each a rating plus a number.
The four wellbeing areasWhere is each person up to with their ergonomic assessments?
A status board across the four assessment types, with eleven filters so you can ask for just the exceptions.
For each assessmentWho has done their ergonomics training, and who is behind?
The same shape as assessment status, for the single ergonomics training.
Training statusAssessments and training in one call - the older way.
Returns assessments and training together with no filters and no totalCount; use the two endpoints above instead.
Returns per personSteps 1 to 5 must be completed by an administrator in your Wellbeing site. Steps 6 onwards are for the developer who will build your integration.
API access tokens are an enterprise feature and are switched on per site by Wellnomics. Sign in and look for Admin → API access tokens. If it is not there, contact Wellnomics Support and ask for API access tokens to be enabled.
You need the Wellnomics Administrator right to create or revoke API tokens.
Go to Admin → API access tokens and choose Create. Set the type to Customer Reporting. Give it a name that says what will use it - 3 to 100 characters, letters, numbers, hyphen and underscore only, and unique among your active tokens. Pick an expiry: 1, 7, 30, 90 or 180 days, or never.
The token is displayed once, on creation. It cannot be retrieved afterwards - if you lose it, revoke it and create another.
The API is served from the regional server that hosts your site, so the base URL cannot be worked out from the address you sign in at - email support@wellnomics.com and we will give you the one for your site. The tenant header is a different value: the hostname you sign in at, for example acme.wellnomics.com.
Call GET /v1/echo/groups with both headers. It is unpaginated and a good way to prove your token, your tenant header and your network path all work before you touch a reporting endpoint.
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$headers = @{
Authorization = "Bearer $env:WELLNOMICS_API_TOKEN"
tenant = 'acme.wellnomics.com'
}
$groups = Invoke-RestMethod -Method GET `
-Uri 'https://api.your-region.wellnomics.com/v1/echo/groups' `
-Headers $headers
$groups.data | Sort-Object name | Format-Table id, name, groupType
curl 'https://api.your-region.wellnomics.com/v1/echo/groups' \
-H "Authorization: Bearer $WELLNOMICS_API_TOKEN" \
-H 'tenant: acme.wellnomics.com'
Bearer <token>. A missing or misspelled tenant header gives a 400 instead.Take an id from step 6 - usually the group with groupType 4, which will be the everyone group for your organisation - and call a reporting endpoint with it. Remember limit and offset are required. Read totalCount in the response and keep paging until you have collected that many rows.
$groupId = 4
$uri = "https://api.your-region.wellnomics.com/v1/echo/groups/$groupId/ergonomics-training-reports?limit=500&offset=0&overdue=true"
$page = Invoke-RestMethod -Method GET -Uri $uri -Headers $headers
"{0} of {1} people are overdue" -f $page.data.Count, $page.totalCount
$page.data | Select-Object name, email, @{n='dueDate';e={$_.training.dueDate}}
curl 'https://api.your-region.wellnomics.com/v1/echo/groups/4/ergonomics-training-reports?limit=500&offset=0&overdue=true' \
-H "Authorization: Bearer $WELLNOMICS_API_TOKEN" \
-H 'tenant: acme.wellnomics.com'
Boolean filters are booleans: send true or false. Lowercase is the form to write, though the server matches case-insensitively, so True from .NET or Python works too — you do not need to normalise before sending. What does matter: build the query string so an unset filter is left out altogether rather than appended empty — ?overdue= is a 400, not "no filter".
# Build the query from only the filters that are actually set, so an
# unset one is absent rather than empty.
$filters = @{ limit = 500; offset = 0 }
if ($PSBoundParameters.ContainsKey('Overdue')) { $filters.overdue = $Overdue.ToString().ToLower() }
$query = ($filters.GetEnumerator() | ForEach-Object {
"{0}={1}" -f [Uri]::EscapeDataString($_.Key), [Uri]::EscapeDataString([string]$_.Value)
}) -join '&'
$uri = "https://api.your-region.wellnomics.com/v1/echo/groups/4/ergonomics-training-reports?$query"
# Correct - filter applied
curl '.../ergonomics-training-reports?limit=500&offset=0&overdue=true'
# Correct - no filter at all
curl '.../ergonomics-training-reports?limit=500&offset=0'
# Wrong - 400, not "no filter"
curl '.../ergonomics-training-reports?limit=500&offset=0&overdue='
When logged in to the Wellbeing site your administrators will see a banner 14 days before a token expires, and an error banner once it has. Do not rely on spotting it: put the expiry date in a calendar and ensure your integration treats a 401 as 'get a new token', not as a fatal crash. The sample scripts show one way to do that.
| Name | Sent as | Required | Type | What it does |
|---|---|---|---|---|
tenant — Your site hostname |
header | Required | string |
Sent as a header on every request. Use the hostname you sign in at, e.g. acme.wellnomics.com. Resolved before authentication, so a wrong value returns 400 even with a valid token. |
| Field | Type | What it does |
|---|---|---|
data[].id |
integer |
Unique identifier for the group. |
data[].groupType |
integer (enum) |
How the group is put together.2 Direct3 AllStaffUnderMe4 Everyone5 Custom |
data[].groupCategory |
integer (enum) |
How the group's membership is maintained.1 System2 Static3 Dynamic |
data[].groupAccess |
integer (enum) |
Whether the group is private to the person who created it or shared with administrators.1 Owner2 RestrictedAdmin |
data[].name |
string |
The group's display name - what the team or unit is called in Wellbeing. |
data[].userGroupCategory |
string |
Where the group came from: `System`, `Organisation`, `LocalAdministration` or `Personal`. |
401 403 500
| Name | Sent as | Required | Type | What it does |
|---|---|---|---|---|
groupId — Group ID |
path | Required | string |
Which group to report on. Get it from GET /v1/echo/groups. |
tenant — Your site hostname |
header | Required | string |
Sent as a header on every request. Use the hostname you sign in at, e.g. acme.wellnomics.com. Resolved before authentication, so a wrong value returns 400 even with a valid token. |
limit — Page size |
query | Required | integer |
Required. How many records to return, 1 to 2000. Larger pages mean fewer calls; 1000 is a sensible default. |
offset — Skip |
query | Required | integer |
Required. How many records to skip. Start at 0, then add your page size for each subsequent page. |
type — Assessment type filter |
query | Required | string |
Limit results to one or more assessment types. Repeat the parameter for several types. Omit for all types. |
hasEverCompleted — Ever completed filter |
query | Optional | boolean |
true returns only people who have completed at least once; false returns only people who never have. Set false to build a 'never started' list. |
overdue — Overdue filter |
query | Optional | boolean |
true returns only overdue records. This is the intended way to build a compliance chase-up list. |
expired — Expired filter |
query | Optional | boolean |
true returns only assessments whose completion has passed its expiry date and needs redoing. Omit the parameter entirely to mean "no filter". Sending it empty ( ?expired=) is a 400, not an absent filter. |
enabled — Switched-on filter |
query | Optional | boolean |
true limits results to assessments or training actually switched on for the person. Use it to avoid reporting on things nobody is expected to do. |
includeOnDemandAssessments — Include self-started |
query | Optional | boolean |
Defaults to false. When false, assessments a person started themselves are treated as not done. Leave it off for scheduled-compliance reporting; turn it on to see all activity. Omit the parameter entirely to mean "no filter". Sending it empty ( ?includeOnDemandAssessments=) is a 400, not an absent filter. |
lastCompletedDate.before — Completed before |
query | Optional | string (date) |
Plain date, YYYY-MM-DD. Returns records last completed before this date - the way to find people whose last completion is going stale. |
lastCompletedDate.after — Completed after |
query | Optional | string (date) |
Plain date, YYYY-MM-DD. Returns records last completed after this date - the way to report on activity in a period. |
lastCompletedDate.isNull — Never completed |
query | Optional | boolean |
true returns only records with no completion date at all. false returns only those with one. Omit the parameter entirely to mean "no filter". Sending it empty ( ?lastCompletedDate.isNull=) is a 400, not an absent filter. |
| Field | Type | What it does |
|---|---|---|
data[].userId |
integer |
The internal identifier for this record. |
data[].uniqueId |
string |
The person's identifier from your own HR system. |
data[].name |
string |
The person's first and last name as a single value. |
data[].email |
string |
The person's email address. |
data[].assessments[].type |
string (enum) |
Which of the four ergonomic assessments this row is about.PostureAndWorkstationWorkEnvironmentDiscomfortIndividual |
data[].assessments[].enabled |
boolean |
Whether this assessment or training is switched on for the person. |
data[].assessments[].dueDate |
string (date-time), nullable |
The date this is due to be completed by. |
data[].assessments[].scheduledDate |
string (date-time), nullable |
When this assessment or training was created for the person. |
data[].assessments[].expiryDate |
string (date-time), nullable |
When a completed assessment stops counting as current. |
data[].assessments[].lastCompletedDate |
string (date-time), nullable |
When the person last completed this. |
data[].assessments[].overdue |
boolean |
Whether this is past its due date and still not done. |
data[].assessments[].onDemand |
boolean, nullable |
True when the person started this assessment themselves rather than being scheduled for it. |
data[].assessments[].expired |
boolean |
Whether a previously completed assessment has passed its expiry date and needs doing again. |
data[].assessments[].hasEverCompleted |
boolean |
Whether the person has ever completed this, at any point. |
totalCount |
integer |
How many records exist in total, before limit and offset are applied. |
400 401 403 404 500
| Name | Sent as | Required | Type | What it does |
|---|---|---|---|---|
groupId — Group ID |
path | Required | string |
Which group to report on. Get it from GET /v1/echo/groups. |
tenant — Your site hostname |
header | Required | string |
Sent as a header on every request. Use the hostname you sign in at, e.g. acme.wellnomics.com. Resolved before authentication, so a wrong value returns 400 even with a valid token. |
limit — Page size |
query | Required | integer |
Required. How many records to return, 1 to 2000. Larger pages mean fewer calls; 1000 is a sensible default. |
offset — Skip |
query | Required | integer |
Required. How many records to skip. Start at 0, then add your page size for each subsequent page. |
hasEverCompleted — Ever completed filter |
query | Optional | boolean |
true returns only people who have completed at least once; false returns only people who never have. Set false to build a 'never started' list. |
overdue — Overdue filter |
query | Optional | boolean |
true returns only overdue records. This is the intended way to build a compliance chase-up list. |
enabled — Switched-on filter |
query | Optional | boolean |
true limits results to assessments or training actually switched on for the person. Use it to avoid reporting on things nobody is expected to do. |
lastCompletedDate.before — Completed before |
query | Optional | string (date) |
Plain date, YYYY-MM-DD. Returns records last completed before this date - the way to find people whose last completion is going stale. |
lastCompletedDate.after — Completed after |
query | Optional | string (date) |
Plain date, YYYY-MM-DD. Returns records last completed after this date - the way to report on activity in a period. |
lastCompletedDate.isNull — Never completed |
query | Optional | boolean |
true returns only records with no completion date at all. false returns only those with one. Omit the parameter entirely to mean "no filter". Sending it empty ( ?lastCompletedDate.isNull=) is a 400, not an absent filter. |
| Field | Type | What it does |
|---|---|---|
data[].userId |
integer |
The internal identifier for this record. |
data[].uniqueId |
string |
The person's identifier from your own HR system. |
data[].name |
string |
The person's first and last name as a single value. |
data[].email |
string |
The person's email address. |
data[].training.enabled |
boolean |
Whether this assessment or training is switched on for the person. |
data[].training.dueDate |
string (date-time), nullable |
The date this is due to be completed by. |
data[].training.scheduledDate |
string (date-time), nullable |
When this assessment or training was created for the person. |
data[].training.lastCompletedDate |
string (date-time), nullable |
When the person last completed this. |
data[].training.overdue |
boolean |
Whether this is past its due date and still not done. |
data[].training.hasEverCompleted |
boolean |
Whether the person has ever completed this, at any point. |
totalCount |
integer |
How many records exist in total, before limit and offset are applied. |
400 401 403 404 500
| Name | Sent as | Required | Type | What it does |
|---|---|---|---|---|
groupId — Group ID |
path | Required | string |
Which group to report on. Get it from GET /v1/echo/groups. |
tenant — Your site hostname |
header | Required | string |
Sent as a header on every request. Use the hostname you sign in at, e.g. acme.wellnomics.com. Resolved before authentication, so a wrong value returns 400 even with a valid token. |
limit — Page size |
query | Required | integer |
Required. How many records to return, 1 to 2000. Larger pages mean fewer calls; 1000 is a sensible default. |
offset — Skip |
query | Required | integer |
Required. How many records to skip. Start at 0, then add your page size for each subsequent page. |
| Field | Type | What it does |
|---|---|---|
data.groupReport[].id |
integer |
The internal identifier for this record. |
data.groupReport[].uniqueId |
string |
The person's identifier from your own HR system. |
data.groupReport[].firstName |
string |
The person's first name. |
data.groupReport[].lastName |
string |
The person's last name. |
data.groupReport[].accountCreated |
string (date-time) |
When the person's Wellbeing account was created. |
data.groupReport[].firstSync |
string (date-time), nullable |
The first time the person's Wellnomics app sent data in. |
data.groupReport[].lastSync |
string (date-time), nullable |
The last time the person's app sent data in. |
data.groupReport[].clientVersion |
string, nullable |
The version of the Wellnomics desktop app the person is running. |
data.groupReport[].dataDate |
string (date-time) |
The date the wellbeing figures on this row describe. |
data.groupReport[].reportData.overallWellbeing.rating |
string (enum) |
The overall wellbeing band for this person.ExcellentGoodFairImproveImproveASAP |
data.groupReport[].reportData.overallWellbeing.score |
number |
The numeric value behind the rating. |
data.groupReport[].reportData.computerUse.rating |
string (enum) |
How much computer exposure this person has.LowModerateHighVeryHigh |
data.groupReport[].reportData.computerUse.score |
number |
The numeric value behind the rating. |
data.groupReport[].reportData.breaks.rating |
string (enum) |
How well this person breaks up their computer work.ExcellentGoodFairPoor |
data.groupReport[].reportData.breaks.score |
number |
The numeric value behind the rating. |
data.groupReport[].reportData.sitStand.rating |
string (enum) |
How this person varies between sitting and standing.ExcellentGoodFairPoor |
data.groupReport[].reportData.sitStand.score |
number |
The numeric value behind the rating. |
totalCount |
integer |
How many records exist in total, before limit and offset are applied. |
400 401 403 404 500
| Name | Sent as | Required | Type | What it does |
|---|---|---|---|---|
groupId — Group ID |
path | Required | string |
Which group to report on. Get it from GET /v1/echo/groups. |
tenant — Your site hostname |
header | Required | string |
Sent as a header on every request. Use the hostname you sign in at, e.g. acme.wellnomics.com. Resolved before authentication, so a wrong value returns 400 even with a valid token. |
limit — Page size |
query | Required | integer |
Required. How many records to return, 1 to 2000. Larger pages mean fewer calls; 1000 is a sensible default. |
offset — Skip |
query | Required | integer |
Required. How many records to skip. Start at 0, then add your page size for each subsequent page. |
| Field | Type | What it does |
|---|---|---|
data[].userId |
integer |
The internal identifier for this record. |
data[].uniqueId |
string |
The person's identifier from your own HR system. |
data[].name |
string |
The person's first and last name as a single value. |
data[].email |
string |
The person's email address. |
data[].assessments[].type |
string (enum) |
Which of the four ergonomic assessments this row is about.PostureAndWorkstationWorkEnvironmentDiscomfortIndividual |
data[].assessments[].enabled |
boolean |
Whether this assessment or training is switched on for the person. |
data[].assessments[].dueDate |
string (date-time), nullable |
The date this is due to be completed by. |
data[].assessments[].scheduledDate |
string (date-time), nullable |
When this assessment or training was created for the person. |
data[].assessments[].expiryDate |
string (date-time), nullable |
When a completed assessment stops counting as current. |
data[].assessments[].lastCompletedDate |
string (date-time), nullable |
When the person last completed this. |
data[].assessments[].overdue |
boolean |
Whether this is past its due date and still not done. |
data[].assessments[].expired |
boolean |
Whether a previously completed assessment has passed its expiry date and needs doing again. |
data[].assessments[].hasEverCompleted |
boolean |
Whether the person has ever completed this, at any point. |
data[].training.enabled |
boolean |
Whether this assessment or training is switched on for the person. |
data[].training.dueDate |
string (date-time), nullable |
The date this is due to be completed by. |
data[].training.scheduledDate |
string (date-time), nullable |
When this assessment or training was created for the person. |
data[].training.lastCompletedDate |
string (date-time), nullable |
When the person last completed this. |
data[].training.overdue |
boolean |
Whether this is past its due date and still not done. |
data[].training.hasEverCompleted |
boolean |
Whether the person has ever completed this, at any point. |
400 401 403 404 500