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 set Content-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 EMPLOYEE and TEAM_MANAGER), so role counts may overlap and their sum can exceed totalNumberOfPersonas.

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 callerApp values 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.