Download OpenAPI specification:
Read-only reporting API for wellbeing and office-ergonomics data, organised by group.
Filters such as overdue, enabled, expired and hasEverCompleted travel as query string values.
Send lowercase true or false. That is what this specification declares and what every client library produces correctly.
The server is more forgiving than that, and will stay so: values are matched case-insensitively, and 1/0, yes/no, on/off, y/n and enabled/disabled are all accepted. You do not need to normalise case before sending. This matters because .NET and Python capitalise by default — bool.ToString() and str(True) both give True — so the natural idiom in those languages works as-is. Anything outside those sets is rejected with a 400.
One thing to build for:
Omitting a filter is not the same as sending it empty. ?overdue= is a 400, not "no filter". Leave the parameter out of the query string entirely when you do not want to filter on it. Watch for this when you build URLs by string concatenation from optional values — an unset variable easily becomes an empty parameter rather than an absent one.
The API is served from the regional server that hosts your site, not from the address you sign in at, so the two are different hostnames. Ask Wellnomics Support for your base URL; it is fixed for your site and does not change.
The tenant header is a separate value: the hostname you sign in at, for example acme.wellnomics.com.
Every request needs two headers:
| Header | Value |
|---|---|
Authorization |
Bearer <your access token> |
tenant |
Your site hostname, e.g. acme.wellnomics.com |
The tenant header selects which customer database the request runs against. It is resolved before authentication, so a missing or unknown tenant fails the request even when the token is perfectly valid.
Create tokens in your Wellbeing site under Admin -> API access tokens, choosing the Customer Reporting token type. The token is shown once, at creation. Tokens can be given a lifetime of 1, 7, 30, 90 or 180 days, or no expiry at all; they can be revoked at any time from the same screen.
Treat the token as a credential with organisation-wide read access to your reporting data. Store it in a secret manager or an environment variable, never in source control, and rotate it on a schedule.
limit and offset are required on every reporting endpoint. limit accepts 1 to 2000. Responses that paginate also return totalCount, which is the number of records before pagination is applied - use it to decide whether to fetch another page.
GET /v1/echo/groups is not paginated and returns every group in one response.
All dates are ISO 8601 UTC timestamps, for example 2026-07-14T09:00:00.000Z. Convert to local time in your own system. Date filters such as lastCompletedDate.before take a plain YYYY-MM-DD date.
Errors use a problem-detail body: status, title, details and type.
| Status | Means | What to do |
|---|---|---|
| 400 | The query is invalid, or the tenant header is missing or unrecognised |
Fix the query, or check the tenant header. limit must be 1-2000 |
| 401 | Missing, malformed, expired or revoked token | If the token expired, create a new one |
| 403 | The site licence is not active, or the token lacks the required right | Contact Wellnomics Support |
| 404 | The group does not exist on this site | Re-read GET /v1/echo/groups |
| 500 | Server-side failure | Retry with backoff, then contact Wellnomics Support |
An unrecognised tenant fails as a 400 before authentication runs, so a token problem and a tenant problem give different status codes.
Every user has a personal "Me" group. These are excluded from GET /v1/echo/groups, and asking for a report on one returns 400. Report on real teams and groups only.
Assessment and training status per person: what is scheduled, completed, overdue or expired. Filterable, so you can ask for just the exceptions.
Deprecated. This endpoint returns assessments and training together and cannot be filtered. Replace it with GET /v1/echo/groups/{groupId}/ergonomics-assessments-reports for assessments and GET /v1/echo/groups/{groupId}/ergonomics-training-reports for training. The replacements return the same fields, add totalCount for pagination, and accept filters so you can ask for only the records you need. It remains available for existing integrations; new work should not use it.
| groupId required | string Example: 1 The group ID |
| limit required | integer ( 0 .. 2000 ] Example: limit=100 The number of items in the response |
| offset required | integer >= 0 Example: offset=0 The number of items to offset |
| tenant required | string Example: acme.wellnomics.com Tenant URL identifier. |
# Windows PowerShell 5.1 and PowerShell 7+ [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $headers = @{ Authorization = "Bearer $env:WELLNOMICS_API_TOKEN" tenant = "acme.wellnomics.com" } $response = Invoke-RestMethod -Method GET ` -Uri 'https://api.your-region.wellnomics.com/v1/echo/groups/1/ergonomics-report?limit=100&offset=0' ` -Headers $headers $response | ConvertTo-Json -Depth 8
{- "data": [
- {
- "userId": 1,
- "uniqueId": "jdory",
- "name": "John Dory",
- "email": "jdory@example.com",
- "assessments": [
- {
- "type": "Discomfort",
- "enabled": true,
- "dueDate": "2026-09-15T00:00:00.000Z",
- "scheduledDate": "2026-07-14T09:00:00.000Z",
- "expiryDate": "2027-01-14T09:00:00.000Z",
- "lastCompletedDate": "2026-07-14T09:32:11.000Z",
- "overdue": false,
- "expired": false,
- "hasEverCompleted": true
}, - {
- "type": "Discomfort",
- "enabled": true,
- "dueDate": "2026-09-15T00:00:00.000Z",
- "scheduledDate": "2026-07-14T09:00:00.000Z",
- "expiryDate": "2027-01-14T09:00:00.000Z",
- "lastCompletedDate": "2026-07-14T09:32:11.000Z",
- "overdue": false,
- "expired": false,
- "hasEverCompleted": true
}
], - "training": {
- "enabled": true,
- "dueDate": "2026-09-15T00:00:00.000Z",
- "scheduledDate": "2026-07-14T09:00:00.000Z",
- "lastCompletedDate": "2026-07-14T09:32:11.000Z",
- "overdue": false,
- "hasEverCompleted": true
}
}, - {
- "userId": 2,
- "uniqueId": "aputa",
- "name": "Anaru Puta",
- "email": "aputa@example.com",
- "assessments": [
- {
- "type": "Discomfort",
- "enabled": true,
- "dueDate": "2026-09-15T00:00:00.000Z",
- "scheduledDate": "2026-07-14T09:00:00.000Z",
- "expiryDate": "2027-01-14T09:00:00.000Z",
- "lastCompletedDate": "2026-07-14T09:32:11.000Z",
- "overdue": false,
- "expired": false,
- "hasEverCompleted": true
}, - {
- "type": "Discomfort",
- "enabled": true,
- "dueDate": "2026-09-15T00:00:00.000Z",
- "scheduledDate": "2026-07-14T09:00:00.000Z",
- "expiryDate": "2027-01-14T09:00:00.000Z",
- "lastCompletedDate": "2026-07-14T09:32:11.000Z",
- "overdue": false,
- "expired": false,
- "hasEverCompleted": true
}
], - "training": {
- "enabled": true,
- "dueDate": "2026-09-15T00:00:00.000Z",
- "scheduledDate": "2026-07-14T09:00:00.000Z",
- "lastCompletedDate": "2026-07-14T09:32:11.000Z",
- "overdue": false,
- "hasEverCompleted": true
}
}
]
}| groupId required | string Example: 1 The group ID |
| limit required | integer ( 0 .. 2000 ] Example: limit=100 The number of items in the response |
| offset required | integer >= 0 Example: offset=0 The number of items to offset |
| type required | string Example: type=PostureAndWorkstation Filter by assessment type(s). If omitted, all types included. |
| hasEverCompleted | boolean Example: hasEverCompleted=true Filter by assessment completion status. |
| overdue | boolean Example: overdue=true Filter by assessment overdue status. |
| expired | boolean Example: expired=false Filter by assessment expiry status. |
| enabled | boolean Example: enabled=true Filter by assessment enabled status. |
| includeOnDemandAssessments | boolean Example: includeOnDemandAssessments=true Defaulting to false, filters whether onDemand assessments should be presented in the report. If onDemand assessments are not presented in the report it will be treated as if users have not done that onDemand assessment |
| lastCompletedDate.before | string <date> Example: lastCompletedDate.before=2026-01-28 Optional ISO date to filter lastCompletedDate by. If provided, will limit results to all those with a last completed date prior to this. |
| lastCompletedDate.after | string <date> Example: lastCompletedDate.after=2026-01-28 Optional ISO date to filter lastCompletedDate by. If provided, will limit results to all those with a last completed date after to this. |
| lastCompletedDate.isNull | boolean Example: lastCompletedDate.isNull=true Optional boolean to filter lastCompletedDate by. If provided, will limit results to all those with a null last completed date when true, and all those with a non-null last completed date when false. |
| tenant required | string Example: acme.wellnomics.com Tenant URL identifier. |
# Windows PowerShell 5.1 and PowerShell 7+ [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $headers = @{ Authorization = "Bearer $env:WELLNOMICS_API_TOKEN" tenant = "acme.wellnomics.com" } $response = Invoke-RestMethod -Method GET ` -Uri 'https://api.your-region.wellnomics.com/v1/echo/groups/1/ergonomics-assessments-reports?limit=100&offset=0&type=PostureAndWorkstation' ` -Headers $headers $response | ConvertTo-Json -Depth 8
{- "data": [
- {
- "userId": 1,
- "uniqueId": "jdory",
- "name": "John Dory",
- "email": "jdory@example.com",
- "assessments": [
- {
- "type": "Discomfort",
- "enabled": true,
- "dueDate": "2026-09-15T00:00:00.000Z",
- "scheduledDate": "2026-07-14T09:00:00.000Z",
- "expiryDate": "2027-01-14T09:00:00.000Z",
- "lastCompletedDate": "2026-07-14T09:32:11.000Z",
- "overdue": false,
- "onDemand": false,
- "expired": false,
- "hasEverCompleted": true
}, - {
- "type": "Discomfort",
- "enabled": true,
- "dueDate": "2026-09-15T00:00:00.000Z",
- "scheduledDate": "2026-07-14T09:00:00.000Z",
- "expiryDate": "2027-01-14T09:00:00.000Z",
- "lastCompletedDate": "2026-07-14T09:32:11.000Z",
- "overdue": false,
- "onDemand": false,
- "expired": false,
- "hasEverCompleted": true
}
]
}, - {
- "userId": 2,
- "uniqueId": "aputa",
- "name": "Anaru Puta",
- "email": "aputa@example.com",
- "assessments": [
- {
- "type": "Discomfort",
- "enabled": true,
- "dueDate": "2026-09-15T00:00:00.000Z",
- "scheduledDate": "2026-07-14T09:00:00.000Z",
- "expiryDate": "2027-01-14T09:00:00.000Z",
- "lastCompletedDate": "2026-07-14T09:32:11.000Z",
- "overdue": false,
- "onDemand": false,
- "expired": false,
- "hasEverCompleted": true
}, - {
- "type": "Discomfort",
- "enabled": true,
- "dueDate": "2026-09-15T00:00:00.000Z",
- "scheduledDate": "2026-07-14T09:00:00.000Z",
- "expiryDate": "2027-01-14T09:00:00.000Z",
- "lastCompletedDate": "2026-07-14T09:32:11.000Z",
- "overdue": false,
- "onDemand": false,
- "expired": false,
- "hasEverCompleted": true
}
]
}
], - "totalCount": 47
}| groupId required | string Example: 1 The group ID |
| limit required | integer ( 0 .. 2000 ] Example: limit=100 The number of items in the response |
| offset required | integer >= 0 Example: offset=0 The number of items to offset |
| hasEverCompleted | boolean If provided, will filter reports to users who have completed training at least once when true and users who have never completed training when false. |
| overdue | boolean Example: overdue=true If provided, will filter reports to those with a matching true/false overdue status. |
| enabled | boolean Example: enabled=true If provided, will filter reports to those with a matching true/false enabled status. |
| lastCompletedDate.before | string <date> Example: lastCompletedDate.before=2026-01-28 Optional ISO date to filter lastCompletedDate by. If provided, will filter reports to all those with a last completed date prior. |
| lastCompletedDate.after | string <date> Example: lastCompletedDate.after=2026-01-28 Optional ISO date to filter lastCompletedDate by. If provided, will filter reports to all those with a last completed date after. |
| lastCompletedDate.isNull | boolean Example: lastCompletedDate.isNull=true Optional boolean to filter lastCompletedDate by. If provided, will filter reports to all those with a null last completed date when true, and all those with a non-null last completed date when false. |
| tenant required | string Example: acme.wellnomics.com Tenant URL identifier. |
# Windows PowerShell 5.1 and PowerShell 7+ [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $headers = @{ Authorization = "Bearer $env:WELLNOMICS_API_TOKEN" tenant = "acme.wellnomics.com" } $response = Invoke-RestMethod -Method GET ` -Uri 'https://api.your-region.wellnomics.com/v1/echo/groups/1/ergonomics-training-reports?limit=100&offset=0' ` -Headers $headers $response | ConvertTo-Json -Depth 8
{- "data": [
- {
- "userId": 1,
- "uniqueId": "jdory",
- "name": "John Dory",
- "email": "jdory@example.com",
- "training": {
- "enabled": true,
- "dueDate": "2026-09-15T00:00:00.000Z",
- "scheduledDate": "2026-07-14T09:00:00.000Z",
- "lastCompletedDate": "2026-07-14T09:32:11.000Z",
- "overdue": false,
- "hasEverCompleted": true
}
}, - {
- "userId": 2,
- "uniqueId": "aputa",
- "name": "Anaru Puta",
- "email": "aputa@example.com",
- "training": {
- "enabled": true,
- "dueDate": "2026-09-15T00:00:00.000Z",
- "scheduledDate": "2026-07-14T09:00:00.000Z",
- "lastCompletedDate": "2026-07-14T09:32:11.000Z",
- "overdue": false,
- "hasEverCompleted": true
}
}
], - "totalCount": 47
}Look up the teams and groups in your organisation. Start here to find the group ID the reporting calls need.
| tenant required | string Example: acme.wellnomics.com Tenant URL identifier. |
# Windows PowerShell 5.1 and PowerShell 7+ [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $headers = @{ Authorization = "Bearer $env:WELLNOMICS_API_TOKEN" tenant = "acme.wellnomics.com" } $response = Invoke-RestMethod -Method GET ` -Uri 'https://api.your-region.wellnomics.com/v1/echo/groups' ` -Headers $headers $response | ConvertTo-Json -Depth 8
{- "data": [
- {
- "id": 1,
- "groupType": 1,
- "groupCategory": 1,
- "groupAccess": 1,
- "name": "John Dory",
- "userGroupCategory": "Organisation"
}, - {
- "id": 2,
- "groupType": 1,
- "groupCategory": 1,
- "groupAccess": 1,
- "name": "Anaru Puta",
- "userGroupCategory": "Organisation"
}
]
}Wellbeing reporting: a per-person rating and score across overall wellbeing, computer use, breaks and sit-stand behaviour.
| groupId required | string Example: 1 The group ID |
| limit required | integer ( 0 .. 2000 ] Example: limit=100 The number of items in the response |
| offset required | integer >= 0 Example: offset=0 The number of items to offset |
| tenant required | string Example: acme.wellnomics.com Tenant URL identifier. |
# Windows PowerShell 5.1 and PowerShell 7+ [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $headers = @{ Authorization = "Bearer $env:WELLNOMICS_API_TOKEN" tenant = "acme.wellnomics.com" } $response = Invoke-RestMethod -Method GET ` -Uri 'https://api.your-region.wellnomics.com/v1/echo/groups/1/reports?limit=100&offset=0' ` -Headers $headers $response | ConvertTo-Json -Depth 8
{- "data": {
- "groupReport": [
- {
- "id": 1,
- "uniqueId": "jdory",
- "firstName": "John",
- "lastName": "Doe",
- "accountCreated": "2025-11-03T21:14:07.000Z",
- "firstSync": "2025-11-04T08:02:55.000Z",
- "lastSync": "2026-08-21T18:41:09.000Z",
- "clientVersion": "5.4.0.219",
- "dataDate": "2026-08-21T00:00:00.000Z",
- "reportData": {
- "overallWellbeing": {
- "rating": "Good",
- "score": 1
}, - "computerUse": {
- "rating": "Good",
- "score": 1
}, - "breaks": {
- "rating": "Good",
- "score": 1
}, - "sitStand": {
- "rating": "Good",
- "score": 1
}
}
}, - {
- "id": 2,
- "uniqueId": "aputa",
- "firstName": "Anaru",
- "lastName": "Puta",
- "accountCreated": "2025-11-03T21:14:07.000Z",
- "firstSync": "2025-11-04T08:02:55.000Z",
- "lastSync": "2026-08-21T18:41:09.000Z",
- "clientVersion": "5.4.0.219",
- "dataDate": "2026-08-21T00:00:00.000Z",
- "reportData": {
- "overallWellbeing": {
- "rating": "Good",
- "score": 1
}, - "computerUse": {
- "rating": "Good",
- "score": 1
}, - "breaks": {
- "rating": "Good",
- "score": 1
}, - "sitStand": {
- "rating": "Good",
- "score": 1
}
}
}
]
}, - "totalCount": 1
}