Organisation Service API
The Organisation Service handles organisation records, master/reference data, and assessment-related features. It runs on internal port 9107 and is exposed through the gateway at the /organisation prefix.
Base paths:
| Environment | URL |
|---|---|
| Production | https://api.zeswa.com/organisation |
| Local | https://localhost:18443/organisation |
All endpoints require a valid Bearer token unless otherwise noted.
The Service Request module also lives in this service (under
/admin/service-requests/*and/hub/service-requests/*). It has its own dedicated docs:
Organisation Endpoints
GET /organisation/organisation
Retrieves a list of all organisations.
Authentication: Required.
Success response – 200 OK
[
{
"_id": "64c3d4e5f6a7b8c9d0e1f2a3",
"name": "Acme Corp",
"industry": "64d4e5f6a7b8c9d0e1f2a3b4",
"country": "64e5f6a7b8c9d0e1f2a3b4c5",
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
]
POST /organisation/organisation
Creates a new organisation. Accepts multipart/form-data (not JSON).
Authentication: Required.
Request — multipart/form-data
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Organisation name (max 100 chars). |
urlName |
string | Yes | URL-safe identifier (max 100 chars). |
logo |
file | No | Logo image. Allowed: png, webp, jpg, jpeg. Max 5 MB. Uploaded to Cloudinary (zeswa/ folder); the returned logo field in the response is a Cloudinary CDN URL. |
algorithmVersion |
"v1" | "v2" |
No | Defaults to "v1". |
genderInputOnRegister |
"true" | "false" |
No | Defaults to "false". |
includeMatchUserInTeam |
"true" | "false" |
No | Defaults to "false". |
isLocationPriority |
"true" | "false" |
No | Defaults to "false". |
isPublic |
"true" | "false" |
No | Defaults to "false". |
licenses |
number | No | Defaults to 0. |
showMatches |
"true" | "false" |
No | Defaults to "false". |
userChange |
"true" | "false" |
No | Defaults to "false". |
templatePrefix |
string | No | |
workstyleWeight |
number | No | |
productExpireTimestamp |
ISO 8601 string | No | e.g. 2025-12-31T00:00:00Z |
sampleAddTimestamp |
ISO 8601 string | No |
⚠️ All boolean and number fields must be sent as strings in multipart form data (e.g.
"true","false","50"). Do not setContent-Type: application/json.
Example (curl)
curl -X POST https://api.zeswa.com/organisation/organisation \
-H "Authorization: Bearer <accessToken>" \
-F "name=Acme Corp" \
-F "urlName=acme-corp" \
-F "isPublic=true" \
-F "licenses=50" \
-F "logo=@/path/to/logo.png"
Success response — 200 OK
{
"organisation": {
"id": "a1b2c3d4-...",
"name": "Acme Corp",
"urlName": "acme-corp",
"logo": "https://res.cloudinary.com/your-cloud/image/upload/v.../zeswa/xxx.png",
"isPublic": true,
"licenses": 50,
"createdAt": "2025-01-15T10:30:00.000Z",
"updatedAt": "2025-01-15T10:30:00.000Z"
}
}
Error responses
| Status | Condition |
|---|---|
400 |
Validation failed or invalid/oversized image file. |
401 |
Missing Authorization header. |
403 |
Invalid or expired token. |
409 |
Organisation with this name or urlName already exists. |
500 |
Internal server error. |
GET /organisation/organisation/:id
Retrieves a single organisation by ID.
Authentication: Required.
Path parameters
| Parameter | Type | Description |
|---|---|---|
id |
string | UUID of the organisation. |
Success response — 200 OK
Returns the organisation object.
Error responses
| Status | Condition |
|---|---|
401 |
Missing Authorization header. |
403 |
Invalid or expired token. |
404 |
Organisation not found. |
500 |
Internal server error. |
PUT /organisation/organisation/:id
Updates an existing organisation. Accepts multipart/form-data (not JSON). Include only the fields you want to change.
Authentication: Required.
Path parameters
| Parameter | Type | Description |
|---|---|---|
id |
string (UUID) | ID of the organisation to update. |
Request — multipart/form-data
All fields are optional. Same field definitions as POST above, except:
| Field | Type | Notes |
|---|---|---|
logo |
file | If provided, replaces the existing logo. Stored in Cloudinary as zeswa/org-{id}, overwriting the previous asset. |
Example (curl)
# Update name only
curl -X PUT https://api.zeswa.com/organisation/organisation/a1b2c3d4-... \
-H "Authorization: Bearer <accessToken>" \
-F "name=Acme Corporation"
# Update logo only
curl -X PUT https://api.zeswa.com/organisation/organisation/a1b2c3d4-... \
-H "Authorization: Bearer <accessToken>" \
-F "logo=@/path/to/new-logo.jpg"
Success response — 200 OK
Returns the updated organisation object.
Error responses
| Status | Condition |
|---|---|
400 |
Validation failed or invalid/oversized image file. |
401 |
Missing Authorization header. |
403 |
Invalid or expired token. |
404 |
Organisation not found. |
500 |
Internal server error. |
DELETE /organisation/organisation/:id
Deletes an organisation.
Authentication: Required.
Path parameters
| Parameter | Type | Description |
|---|---|---|
id |
string | MongoDB ObjectId of the organisation. |
Success response – 200 OK
{
"message": "Organisation deleted successfully"
}
Error responses
| Status | Condition |
|---|---|
401 |
Missing Authorization header. |
403 |
Invalid or expired token. |
404 |
Organisation not found. |
500 |
Internal server error. |
Account Endpoints
GET /organisation/account
Retrieves a list of accounts.
Authentication: Required.
POST /organisation/account
Creates a new account.
Authentication: Required.
GET /organisation/account/:id
Retrieves a single account by ID.
Authentication: Required.
PUT /organisation/account/:id
Updates an existing account.
Authentication: Required.
DELETE /organisation/account/:id
Deletes an account.
Authentication: Required.
All account endpoints follow the same request/response patterns as the organisation endpoints above.
Master Data Endpoints
The Organisation Service manages several collections of reference data. Each collection follows a consistent CRUD pattern with the same endpoint structure. All master data endpoints require authentication.
Common Pattern
For each master data type, the following endpoints are available:
| Method | Path | Description |
|---|---|---|
GET |
/organisation/{type} |
List all records of this type. |
POST |
/organisation/{type} |
Create a new record. |
GET |
/organisation/{type}/:id |
Get a single record by ID. |
PUT |
/organisation/{type}/:id |
Update a record by ID. |
DELETE |
/organisation/{type}/:id |
Delete a record by ID. |
Available Master Data Types
Country
Path prefix: /organisation/country
Manages the list of countries available in the platform.
{
"_id": "64e5f6a7b8c9d0e1f2a3b4c5",
"name": "Australia",
"code": "AU"
}
Industry
Path prefix: /organisation/industry
Manages industry classifications.
{
"_id": "64d4e5f6a7b8c9d0e1f2a3b4",
"name": "Technology"
}
Function
Path prefix: /organisation/function
Manages business function classifications (e.g., Engineering, Marketing, Sales).
{
"_id": "64f6a7b8c9d0e1f2a3b4c5d6",
"name": "Engineering"
}
Education Level
Path prefix: /organisation/education-level
Manages education level options (e.g., Bachelor’s, Master’s, PhD).
{
"_id": "64a7b8c9d0e1f2a3b4c5d6e7",
"name": "Master's Degree"
}
Study Major
Path prefix: /organisation/study-major
Manages academic study major options.
{
"_id": "64b8c9d0e1f2a3b4c5d6e7f8",
"name": "Computer Science"
}
Skill
Path prefix: /organisation/skill
Manages the skills taxonomy used for teammate profiles and assessments.
{
"_id": "64c9d0e1f2a3b4c5d6e7f8a9",
"name": "TypeScript"
}
Location
Path prefix: /organisation/location
Manages location records (offices, sites, or regions).
{
"_id": "64d0e1f2a3b4c5d6e7f8a9b0",
"name": "Sydney Office",
"country": "64e5f6a7b8c9d0e1f2a3b4c5"
}
Master Data – Example Requests
List all countries:
curl -X GET https://api.zeswa.com/organisation/country \
-H "Authorization: Bearer <accessToken>"
Create a new skill:
curl -X POST https://api.zeswa.com/organisation/skill \
-H "Authorization: Bearer <accessToken>" \
-H "Content-Type: application/json" \
-d '{"name": "TypeScript"}'
Update an industry:
curl -X PUT https://api.zeswa.com/organisation/industry/64d4e5f6a7b8c9d0e1f2a3b4 \
-H "Authorization: Bearer <accessToken>" \
-H "Content-Type: application/json" \
-d '{"name": "Information Technology"}'
Delete a location:
curl -X DELETE https://api.zeswa.com/organisation/location/64d0e1f2a3b4c5d6e7f8a9b0 \
-H "Authorization: Bearer <accessToken>"
Assessment Data Endpoints
The Organisation Service also manages assessment-related data: questions, question groups, and question answers. These entities use auto-generated numeric IDs. All endpoints require authentication.
Common Pattern
For each assessment data type, the following endpoints are available:
| Method | Path | Description |
|---|---|---|
GET |
/organisation/{type} |
List all records (supports pagination and filtering). |
POST |
/organisation/{type} |
Create a new record. |
GET |
/organisation/{type}/:id |
Get a single record by numeric ID. |
PUT |
/organisation/{type}/:id |
Update a record by numeric ID. |
DELETE |
/organisation/{type}/:id |
Delete a record by numeric ID. |
Question
Path prefix: /organisation/question
Manages assessment questions. Each question belongs to a question group.
{
"id": 1,
"questionGroupId": 1,
"orderIndex": 1,
"type": "LIKERT",
"text": "I enjoy working in a team environment",
"summary": "Measures how much a person values and enjoys collaborative work. High scorers tend to thrive in group settings and prioritise shared effort over solo achievement.",
"likertAnswerSet": "agree",
"metadata": null,
"faking": false,
"reverseScore": false,
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
| Field | Type | Required | Description |
|---|---|---|---|
questionGroupId |
number | Yes | ID of the parent question group. |
orderIndex |
number | No | Display order within the group. |
type |
string | Yes | MULTIPLE_CHOICE or LIKERT. |
text |
string | Yes | The short question statement shown to the respondent. |
summary |
string | No | ~200-character explanation of what the question measures. Useful for displaying context in the UI. |
likertAnswerSet |
string | No | Likert scale type: important, agree, or usually. |
metadata |
string | No | Additional metadata (e.g. conflict sub-group). |
faking |
boolean | Yes | Whether this is a validity/social desirability check question. |
reverseScore |
boolean | Yes | Whether scoring is reversed. |
List query parameters:
| Parameter | Type | Description |
|---|---|---|
search |
string | Filter by question text (case-insensitive regex). |
questionGroupId |
number | Filter by question group. |
page |
number | Page number (default: 1). |
limit |
number | Items per page (default: 10). |
Question Group
Path prefix: /organisation/question-group
Manages groups of questions used in assessments. Each group defines a scoring type.
{
"id": 1,
"name": "teamwork",
"title": "Teamwork Assessment",
"strapline": "Evaluate your teamwork capabilities",
"scoreType": "COMPLEMENTARY",
"questionIds": [1, 2, 3, 4, 5],
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Unique identifier name. |
title |
string | Yes | Display title. |
strapline |
string | Yes | Short description/subtitle. |
scoreType |
string | Yes | One of: SUPPLEMENTARY, COMPLEMENTARY, TOP_TEN, INDIVIDUAL_SUPPLEMENTARY, CONFLICT, MAX_MEAN, MIN_MEAN, GROUP_AVERAGE. |
questionIds |
number[] | Yes | Array of question IDs belonging to this group. |
List query parameters:
| Parameter | Type | Description |
|---|---|---|
search |
string | Filter by name (case-insensitive regex). |
page |
number | Page number (default: 1). |
limit |
number | Items per page (default: 10). |
Question Answer
Path prefix: /organisation/question-answer
Manages answer options for questions. Each answer belongs to a specific question.
{
"id": 1,
"orderIndex": 1,
"text": "Strongly Agree",
"value": 5,
"questionId": 1,
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
| Field | Type | Required | Description |
|---|---|---|---|
orderIndex |
number | Yes | Display order of the answer. |
text |
string | No | Answer label text (max 200 chars). |
value |
number | Yes | Numeric score value. |
questionId |
number | Yes | ID of the parent question. |
List query parameters:
| Parameter | Type | Description |
|---|---|---|
search |
string | Filter by answer text (case-insensitive regex). |
questionId |
number | Filter by parent question. |
page |
number | Page number (default: 1). |
limit |
number | Items per page (default: 10). |
Unique constraints: A question cannot have duplicate value entries or duplicate orderIndex entries.
Assessment Data – Example Requests
List all questions in a group:
curl -X GET "https://api.zeswa.com/organisation/question?questionGroupId=1" \
-H "Authorization: Bearer <accessToken>"
Create a new question group:
curl -X POST https://api.zeswa.com/organisation/question-group \
-H "Authorization: Bearer <accessToken>" \
-H "Content-Type: application/json" \
-d '{"name": "leadership", "title": "Leadership Assessment", "strapline": "Evaluate leadership skills", "scoreType": "COMPLEMENTARY", "questionIds": [1, 2, 3]}'
Add an answer to a question:
curl -X POST https://api.zeswa.com/organisation/question-answer \
-H "Authorization: Bearer <accessToken>" \
-H "Content-Type: application/json" \
-d '{"orderIndex": 1, "text": "Strongly Agree", "value": 5, "questionId": 1}'
Update a question:
curl -X PUT https://api.zeswa.com/organisation/question/1 \
-H "Authorization: Bearer <accessToken>" \
-H "Content-Type: application/json" \
-d '{"questionGroupId": 1, "type": "LIKERT", "text": "Updated question text", "faking": false, "reverseScore": true}'
Delete an answer:
curl -X DELETE https://api.zeswa.com/organisation/question-answer/1 \
-H "Authorization: Bearer <accessToken>"
Utility Endpoints
GET /organisation/stats
Returns aggregated dashboard statistics across all platform entities in a single request. All counts are executed in parallel for optimal performance.
Authentication: Required.
Success response — 200 OK
{
"organisation": {
"totalNumberOfOrganisation": 12
},
"user": {
"totalActiveUsers": 340,
"totalInactiveUsers": 58
},
"evaluations": {
"totalEvaluations": 720,
"totalEvaluationsInProgress": 45,
"totalEvaluationsCompleted": 620
},
"persona": {
"totalNumberOfPersonas": 398,
"totalNumberOfCandidates": 120,
"totalNumberOfEmployee": 210,
"totalNumberOfHR": 18,
"totalNumberOfTeamManager": 30,
"totalNumberOfManager": 20
},
"team": {
"totalNumberOfTeam": 55
}
}
Field reference
| Field | Source | Notes |
|---|---|---|
organisation.totalNumberOfOrganisation |
Organisation collection |
Total document count |
user.totalActiveUsers |
Persona collection |
Personas with status: "ACTIVE" |
user.totalInactiveUsers |
Persona collection |
Personas with status: "BLOCKED" or "PENDING" |
evaluations.totalEvaluations |
Evaluation collection |
Total document count |
evaluations.totalEvaluationsInProgress |
Evaluation collection |
status: "in_progress" |
evaluations.totalEvaluationsCompleted |
Evaluation collection |
status: "complete" |
persona.totalNumberOfPersonas |
Persona collection |
Total document count |
persona.totalNumberOfCandidates |
Persona collection |
roles array contains "CANDIDATE" |
persona.totalNumberOfEmployee |
Persona collection |
roles array contains "EMPLOYEE" |
persona.totalNumberOfHR |
Persona collection |
roles array contains "HR" |
persona.totalNumberOfTeamManager |
Persona collection |
roles array contains "TEAM_MANAGER" |
persona.totalNumberOfManager |
Persona collection |
roles array contains "MANAGER" |
team.totalNumberOfTeam |
Team collection |
Total document count |
Note: A single Persona can hold multiple roles (e.g., both
EMPLOYEEandTEAM_MANAGER), so role counts may overlap and their sum can exceedtotalNumberOfPersonas.
Example
curl -X GET https://api.zeswa.com/organisation/stats \
-H "Authorization: Bearer <accessToken>"
Error responses
| Status | Condition |
|---|---|
401 |
Missing Authorization header. |
403 |
Invalid or expired token. |
500 |
Internal server error. |
GET /organisation/stats/visitors
Returns daily API call counts grouped by device type for the last 90 days, sorted by date ascending.
Authentication: Required.
Device type classification
Device type is determined by inspecting the User-Agent header of each logged API request:
| Device Type | User-Agent matches |
|---|---|
mobile |
mobile, android, iphone, ipad, ios (case-insensitive) |
desktop |
mozilla, chrome, safari, firefox, opera, edge (case-insensitive) |
unknown |
Everything else (node, curl, postman, API clients, etc.) |
Only device types that have data on a given day will appear as keys in that day’s object.
Success response — 200 OK
[
{ "date": "2024-04-01", "desktop": 222, "mobile": 150 },
{ "date": "2024-04-02", "desktop": 97, "mobile": 180, "unknown": 5 },
{ "date": "2024-04-03", "desktop": 167, "mobile": 120 },
{ "date": "2024-06-30", "desktop": 446, "mobile": 400, "unknown": 12 }
]
Example
curl -X GET https://api.zeswa.com/organisation/stats/visitors \
-H "Authorization: Bearer <accessToken>"
Error responses
| Status | Condition |
|---|---|
401 |
Missing Authorization header. |
403 |
Invalid or expired token. |
500 |
Internal server error. |
GET /organisation/stats/byapp
Returns daily API call counts grouped by calling application (callerApp field) for the last 90 days, sorted by date ascending.
Authentication: Required.
callerApp values
| Value | Description |
|---|---|
hub |
Request originated from the Zeswa Hub app |
admin |
Request originated from the Admin portal |
postman |
Auto-detected Postman client |
unknown |
Caller not identified |
Keys in the response are dynamic — only apps with calls on that day will appear. New
callerAppvalues will appear automatically without any backend changes.
Success response — 200 OK
[
{ "date": "2024-04-01", "hub": 222, "admin": 150 },
{ "date": "2024-04-02", "hub": 97, "admin": 180 },
{ "date": "2024-04-03", "hub": 167, "admin": 120 },
{ "date": "2024-06-30", "hub": 446, "admin": 400, "postman": 12 }
]
Example
curl -X GET https://api.zeswa.com/organisation/stats/byapp \
-H "Authorization: Bearer <accessToken>"
Error responses
| Status | Condition |
|---|---|
401 |
Missing Authorization header. |
403 |
Invalid or expired token. |
500 |
Internal server error. |
GET /organisation/health
Returns the health status of the Organisation Service.
Authentication: None required.
GET /organisation/_ping
Lightweight liveness probe.
Authentication: None required.