Purple Suite HRBP API OpenAPI

HR Business Partner (HRBP) source system — Talent Insights & Talent Review, and Employee Relations case management. Data layer for talent reviews, 9-box employee assessments, performance reviews, succession planning, metric snapshots, and ER cases/allegations/involved parties (SN sn_hr_er_* parity). ServiceNow-parity contract endpoints (resolve_filters, available_metrics, preview_review/commit_review, query) and the tp_* MCP tools are served alongside these collections. References employees in the Purple HRS (HRIS) app by employee_id. Choice fields use a readable canonical value; the originating ServiceNow code is noted in each field description. --- **Acting as a user (`X-PS-Impersonate-User`).** Every endpoint accepts an optional `X-PS-Impersonate-User` request header whose value is the email of the instance user to act as. The effective user resolves in this order: the header if present, else the instance's configured default MCP user, else none. User-scoped paths additionally accept the literal `me` in place of an email, and Graph-style apps also serve `/me/…` twins of their `/users/{email}/…` paths that resolve the same way. This header is honored by all operations but is intentionally omitted from each operation's parameter list so it is not surfaced as a per-tool argument by MCP clients; see the `ImpersonateUser` entry under `components.parameters`.

This reference is readable without JavaScript. Download the OpenAPI document.

Runtime

/api/purple-suite/hrbp

HR Business Partner (HRBP) source system — Talent Insights & Talent Review, and Employee Relations case management. Data layer for talent reviews, 9-box employee assessments, performance reviews, succession planning, metric snapshots, and ER cases/allegations/involved parties (SN sn_hr_er_* parity). ServiceNow-parity contract endpoints (resolve_filters, available_metrics, preview_review/commit_review, query) and the tp_* MCP tools are served alongside these collections. References employees in the Purple HRS (HRIS) app by employee_id. Choice fields use a readable canonical value; the originating ServiceNow code is noted in each field description. --- **Acting as a user (`X-PS-Impersonate-User`).** Every endpoint accepts an optional `X-PS-Impersonate-User` request header whose value is the email of the instance user to act as. The effective user resolves in this order: the header if present, else the instance's configured default MCP user, else none. User-scoped paths additionally accept the literal `me` in place of an email, and Graph-style apps also serve `/me/…` twins of their `/users/{email}/…` paths that resolve the same way. This header is honored by all operations but is intentionally omitted from each operation's parameter list so it is not surfaced as a per-tool argument by MCP clients; see the `ImpersonateUser` entry under `components.parameters`.

Servers

[
  {
    "url": "https://marketplace.moveworks.com/api/purple-suite/hrbp"
  }
]

Authentication schemes

{
  "patAuth": {
    "type": "http",
    "scheme": "bearer"
  }
}

Each operation lists its security requirements. An empty security array permits an unauthenticated request. Use the scheme and headers declared for the selected contract.

Operations

POST /resolve_filters

Resolve & validate HRBP scope filters (tp_resolve_scope)

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Resolve & validate HRBP scope filters (tp_resolve_scope)",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "Resolve & validate HRBP scope filters (tp_resolve_scope)"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

GET /available_metrics

List predefined talent metrics (tp_list_metrics)

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "List predefined talent metrics (tp_list_metrics)",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "List predefined talent metrics (tp_list_metrics)"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

GET /available_metric_categories

List metric categories

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "List metric categories",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "List metric categories"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

POST /execute_known_metric

Compute one predefined metric (tp_execute_metric)

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Compute one predefined metric (tp_execute_metric)",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "Compute one predefined metric (tp_execute_metric)"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

POST /find_matching_reviews

Find talent reviews by filters (tp_find_reviews)

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Find talent reviews by filters (tp_find_reviews)",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "Find talent reviews by filters (tp_find_reviews)"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

POST /preview_review

Preview a talent review (computes metrics); mints idempotency_key (tp_preview_review)

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Preview a talent review (computes metrics); mints idempotency_key (tp_preview_review)",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "Preview a talent review (computes metrics); mints idempotency_key (tp_preview_review)"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

POST /commit_review

Commit a previewed talent review (tp_commit_review)

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Commit a previewed talent review (tp_commit_review)",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "Commit a previewed talent review (tp_commit_review)"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

POST /add_metric_to_review

Add a metric to an existing talent review (tp_add_metric)

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Add a metric to an existing talent review (tp_add_metric)",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "Add a metric to an existing talent review (tp_add_metric)"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

POST /display_talent_review

Display a talent review + computed metrics (tp_display_review)

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Display a talent review + computed metrics (tp_display_review)",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "Display a talent review + computed metrics (tp_display_review)"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

POST /hrbp_data_analytics/query

HRBP data-analytics query — NL question → generated query, aggregates, inline insights, and async answer/follow-up logIds (SN hrbp_data_analytics/query). Returns 202 on submission; poll result.analysis.logId / result.followUps.logId via /hrbp_data_analytics/async_results.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "HRBP data-analytics query — NL question → generated query, aggregates, inline insights, and async answer/follow-up logIds (SN hrbp_data_analytics/query). Returns 202 on submission; poll result.analysis.logId / result.followUps.logId via /hrbp_data_analytics/async_results.",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "query",
      "name": "method",
      "required": false,
      "schema": {
        "type": "string",
        "enum": [
          "fullPipeline",
          "insightsOnly",
          "custom",
          "getAsyncResults"
        ],
        "default": "fullPipeline"
      },
      "description": "fullPipeline needs {utterance, channelId}; insightsOnly needs {channelId} plus dataConfigurations or dataResponses; custom needs {featureFlags}; getAsyncResults needs {logId}."
    },
    {
      "in": "query",
      "name": "seed",
      "required": false,
      "schema": {
        "type": "string"
      },
      "description": "Pin the simulated model output so a run is reproducible. Omit for fresh phrasing on every call (the underlying numbers never change)."
    },
    {
      "in": "query",
      "name": "readyDelayMs",
      "required": false,
      "schema": {
        "type": "integer",
        "default": 1500,
        "minimum": 0,
        "maximum": 60000
      },
      "description": "How long the async answer/follow-up capabilities stay in `processing` before results land. 0 makes them readable immediately."
    }
  ],
  "responses": {
    "202": {
      "description": "Accepted — async capabilities submitted"
    },
    "400": {
      "description": "Validation error (missing required field)"
    },
    "404": {
      "description": "getAsyncResults: unknown logId"
    }
  }
}

GET /hrbp_data_analytics/async_results

Batch-poll async analytics results by logId(s) (SN hrbp_data_analytics/async_results)

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Batch-poll async analytics results by logId(s) (SN hrbp_data_analytics/async_results)",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "query",
      "name": "logIds",
      "required": false,
      "schema": {
        "type": "string"
      },
      "description": "Comma-separated log ids."
    },
    {
      "in": "query",
      "name": "logId",
      "required": false,
      "schema": {
        "type": "string"
      },
      "description": "A single log id (combinable with logIds)."
    }
  ],
  "responses": {
    "200": {
      "description": "Batch-poll async analytics results by logId(s) (SN hrbp_data_analytics/async_results)"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

POST /hrbp_action_recommendations_rest_api/recommendations

Generate action recommendations from an analytics finding — accepts {goal, content} or {goal, queryGenResponse|fullpipeline_response} (SN hrbp_action_recommendations_rest_api/recommendations)

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Generate action recommendations from an analytics finding — accepts {goal, content} or {goal, queryGenResponse|fullpipeline_response} (SN hrbp_action_recommendations_rest_api/recommendations)",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "Generate action recommendations from an analytics finding — accepts {goal, content} or {goal, queryGenResponse|fullpipeline_response} (SN hrbp_action_recommendations_rest_api/recommendations)"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

POST /query

Alias of /hrbp_data_analytics/query (pre-existing Purple path)

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Alias of /hrbp_data_analytics/query (pre-existing Purple path)",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "Alias of /hrbp_data_analytics/query (pre-existing Purple path)"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

GET /async_results

Alias of /hrbp_data_analytics/async_results (pre-existing Purple path)

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Alias of /hrbp_data_analytics/async_results (pre-existing Purple path)",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "Alias of /hrbp_data_analytics/async_results (pre-existing Purple path)"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

POST /recommendations

Alias of /hrbp_action_recommendations_rest_api/recommendations (pre-existing Purple path)

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Alias of /hrbp_action_recommendations_rest_api/recommendations (pre-existing Purple path)",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "Alias of /hrbp_action_recommendations_rest_api/recommendations (pre-existing Purple path)"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

GET /fuzzy_value_resolver

Resolve a raw value to catalog {value, sys_id} matches via exact->startswith->contains->fuzzy->text cascade (SN FuzzyValueResolver parity)

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Resolve a raw value to catalog {value, sys_id} matches via exact->startswith->contains->fuzzy->text cascade (SN FuzzyValueResolver parity)",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "query",
      "name": "tableName",
      "required": true,
      "schema": {
        "type": "string"
      }
    },
    {
      "in": "query",
      "name": "columnName",
      "required": true,
      "schema": {
        "type": "string"
      }
    },
    {
      "in": "query",
      "name": "rawValue",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Resolve a raw value to catalog {value, sys_id} matches via exact->startswith->contains->fuzzy->text cascade (SN FuzzyValueResolver parity)"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

GET /available_templates

List talent-review templates

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "List talent-review templates",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "List talent-review templates"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

POST /create_review_from_template

Create a talent review from a template (direct write)

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Create a talent review from a template (direct write)",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "Create a talent review from a template (direct write)"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

POST /search_talent_reviews

Search talent reviews by filter names + scope; returns templates

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Search talent reviews by filter names + scope; returns templates",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "Search talent reviews by filter names + scope; returns templates"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

POST /execute_talent_review

Execute a talent review's stored metrics by id

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Execute a talent review's stored metrics by id",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "Execute a talent review's stored metrics by id"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

POST /query_metric

Resolve filters + compute one metric widget

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Resolve filters + compute one metric widget",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "Resolve filters + compute one metric widget"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

GET /hr_program/summary

Get an HR program summary by name keyword (q)

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Get an HR program summary by name keyword (q)",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "Get an HR program summary by name keyword (q)"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

POST /hr_program/draft_notification

Raw program data + stakeholder contacts for an LLM to draft an HR program notification from (no server-built draft text)

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Raw program data + stakeholder contacts for an LLM to draft an HR program notification from (no server-built draft text)",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "Raw program data + stakeholder contacts for an LLM to draft an HR program notification from (no server-built draft text)"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

POST /hr_program/get_draft

Retrieve the caller's persisted notification draft HTML for a program

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Retrieve the caller's persisted notification draft HTML for a program",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "Retrieve the caller's persisted notification draft HTML for a program"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

POST /hr_program/save_draft

Persist the caller's notification draft HTML for a program

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Persist the caller's notification draft HTML for a program",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "Persist the caller's notification draft HTML for a program"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

GET /hr_program/program_details/{sys_id_csv}

Full nested detail (fields, program type, milestones, resources, stakeholders, action plans) for one or more programs by comma-separated sys_id

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Full nested detail (fields, program type, milestones, resources, stakeholders, action plans) for one or more programs by comma-separated sys_id",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "sys_id_csv",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Full nested detail (fields, program type, milestones, resources, stakeholders, action plans) for one or more programs by comma-separated sys_id"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

GET /hr_program

List the caller's stakeholder/owner programs, grouped by state with upcoming milestones

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "List the caller's stakeholder/owner programs, grouped by state with upcoming milestones",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "List the caller's stakeholder/owner programs, grouped by state with upcoming milestones"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

GET /hr_profile/new_hire

New hires within the calling HRBP's scope for a hire-date window (start_date/end_date, yyyy-MM-dd; defaults to the last 30 days). Returns { start_date, end_date, count, employees:[{ name, hire_date, days_since_hire, position, department, manager }] }, wrapped in {result:...} (SN HRBPNewHireDetailsSNC parity).

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "New hires within the calling HRBP's scope for a hire-date window (start_date/end_date, yyyy-MM-dd; defaults to the last 30 days). Returns { start_date, end_date, count, employees:[{ name, hire_date, days_since_hire, position, department, manager }] }, wrapped in {result:...} (SN HRBPNewHireDetailsSNC parity).",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "query",
      "name": "start_date",
      "required": false,
      "schema": {
        "type": "string"
      }
    },
    {
      "in": "query",
      "name": "end_date",
      "required": false,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "New hires within the calling HRBP's scope for a hire-date window (start_date/end_date, yyyy-MM-dd; defaults to the last 30 days). Returns { start_date, end_date, count, employees:[{ name, hire_date, days_since_hire, position, department, manager }] }, wrapped in {result:...} (SN HRBPNewHireDetailsSNC parity)."
    },
    "400": {
      "description": "Bad request"
    }
  }
}

GET /hr_profile/on_leave_users

Employees currently on approved leave within the calling HRBP's scope for a leave window (start_date/end_date, yyyy-MM-dd; BOTH default to today, not a lookback window). Grouped by leave_type: { total, groups:[{ leave_type, count, employees:[{ name, department, manager, start_date, expected_return_date, leave_status, overdue }] }] }, wrapped in {result:...} for every branch including 400 (SN HRBPEmployeesOnLeaveSNC parity — same wrap-every-branch precedent as /hr_profile/new_hire, including identical date-validation messages).

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Employees currently on approved leave within the calling HRBP's scope for a leave window (start_date/end_date, yyyy-MM-dd; BOTH default to today, not a lookback window). Grouped by leave_type: { total, groups:[{ leave_type, count, employees:[{ name, department, manager, start_date, expected_return_date, leave_status, overdue }] }] }, wrapped in {result:...} for every branch including 400 (SN HRBPEmployeesOnLeaveSNC parity — same wrap-every-branch precedent as /hr_profile/new_hire, including identical date-validation messages).",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "query",
      "name": "start_date",
      "required": false,
      "schema": {
        "type": "string"
      }
    },
    {
      "in": "query",
      "name": "end_date",
      "required": false,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Employees currently on approved leave within the calling HRBP's scope for a leave window (start_date/end_date, yyyy-MM-dd; BOTH default to today, not a lookback window). Grouped by leave_type: { total, groups:[{ leave_type, count, employees:[{ name, department, manager, start_date, expected_return_date, leave_status, overdue }] }] }, wrapped in {result:...} for every branch including 400 (SN HRBPEmployeesOnLeaveSNC parity — same wrap-every-branch precedent as /hr_profile/new_hire, including identical date-validation messages)."
    },
    "400": {
      "description": "Bad request"
    }
  }
}

GET /employee/{sys_id}/work_history

An employee's job/position history (tenure duration + current-job status), most recent first, by employee sys_id. NOT self-scoped — any internal-role caller may look up any employee. Wraps both success AND error bodies in {result:...} (its SN op routes every 200/400/500 path through response.setBody(), same precedent as /hr_profile/new_hire).

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "An employee's job/position history (tenure duration + current-job status), most recent first, by employee sys_id. NOT self-scoped — any internal-role caller may look up any employee. Wraps both success AND error bodies in {result:...} (its SN op routes every 200/400/500 path through response.setBody(), same precedent as /hr_profile/new_hire).",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "sys_id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "An employee's job/position history (tenure duration + current-job status), most recent first, by employee sys_id. NOT self-scoped — any internal-role caller may look up any employee. Wraps both success AND error bodies in {result:...} (its SN op routes every 200/400/500 path through response.setBody(), same precedent as /hr_profile/new_hire)."
    },
    "400": {
      "description": "Bad request"
    }
  }
}

GET /hr_case

List the caller's HRBP cases (paginated, AI-enriched)

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "List the caller's HRBP cases (paginated, AI-enriched)",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "List the caller's HRBP cases (paginated, AI-enriched)"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

GET /hr_case/pending_approval

List the caller's active HR cases on which THEY have a pending approval (same paginated, AI-enriched, urgency-first shape as GET /hr_case; the only difference is the case source — cases with an approvals row where approver = caller AND state = 'requested', SN getCasesPendingApprovalForUser parity)

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "List the caller's active HR cases on which THEY have a pending approval (same paginated, AI-enriched, urgency-first shape as GET /hr_case; the only difference is the case source — cases with an approvals row where approver = caller AND state = 'requested', SN getCasesPendingApprovalForUser parity)",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "List the caller's active HR cases on which THEY have a pending approval (same paginated, AI-enriched, urgency-first shape as GET /hr_case; the only difference is the case source — cases with an approvals row where approver = caller AND state = 'requested', SN getCasesPendingApprovalForUser parity)"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

GET /hr_case/{sys_id}

Get full HR case detail + AI enrichment + approvers (with raw_state) + collaborators + meeting_attendees + pending-approval flag

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Get full HR case detail + AI enrichment + approvers (with raw_state) + collaborators + meeting_attendees + pending-approval flag",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "sys_id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Get full HR case detail + AI enrichment + approvers (with raw_state) + collaborators + meeting_attendees + pending-approval flag"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

POST /hr_case/{sys_id}/approval

Approve or reject the caller's pending approval on an HR case. When the caller has no actionable pending approval, returns 200 with {result:{success:false, error, errorCode}}: errorCode 'not_required' when the case has no approval rows at all, else 'not_approver'

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Approve or reject the caller's pending approval on an HR case. When the caller has no actionable pending approval, returns 200 with {result:{success:false, error, errorCode}}: errorCode 'not_required' when the case has no approval rows at all, else 'not_approver'",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "sys_id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Approve or reject the caller's pending approval on an HR case. When the caller has no actionable pending approval, returns 200 with {result:{success:false, error, errorCode}}: errorCode 'not_required' when the case has no approval rows at all, else 'not_approver'"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

GET /hrbp_utils/url/{portal_page}

Build a URL for an AIX portal page (mock — always returns a URL)

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Build a URL for an AIX portal page (mock — always returns a URL)",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "portal_page",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Build a URL for an AIX portal page (mock — always returns a URL)"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

GET /api/now/table/sn_hr_core_case

ServiceNow Table API parity: look up a case by number (sysparm_query=number=<value>); wraps in {result: [...]}

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "ServiceNow Table API parity: look up a case by number (sysparm_query=number=<value>); wraps in {result: [...]}",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "ServiceNow Table API parity: look up a case by number (sysparm_query=number=<value>); wraps in {result: [...]}"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

PATCH /api/now/table/sn_hr_core_case/{sys_id}

ServiceNow Table API parity: update a case's state (+ optional work_notes) for defer(24)/resume(18)/cancel(7); wraps in {result: {...}}

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "ServiceNow Table API parity: update a case's state (+ optional work_notes) for defer(24)/resume(18)/cancel(7); wraps in {result: {...}}",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "sys_id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "ServiceNow Table API parity: update a case's state (+ optional work_notes) for defer(24)/resume(18)/cancel(7); wraps in {result: {...}}"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

GET /api/now/table/sys_user

ServiceNow Table API parity: sys_user lookup (sysparm_query=nameLIKE<term>) for the u_SysUser slot resolver; wraps in {result: [...]}

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "ServiceNow Table API parity: sys_user lookup (sysparm_query=nameLIKE<term>) for the u_SysUser slot resolver; wraps in {result: [...]}",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "query",
      "name": "sysparm_query",
      "required": false,
      "schema": {
        "type": "string"
      },
      "example": "nameLIKETaco"
    },
    {
      "in": "query",
      "name": "sysparm_fields",
      "required": false,
      "schema": {
        "type": "string"
      },
      "example": "sys_id,name,email"
    },
    {
      "in": "query",
      "name": "sysparm_limit",
      "required": false,
      "schema": {
        "type": "integer"
      },
      "example": 10
    },
    {
      "in": "query",
      "name": "sysparm_offset",
      "required": false,
      "schema": {
        "type": "integer"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "ServiceNow Table API parity: sys_user lookup (sysparm_query=nameLIKE<term>) for the u_SysUser slot resolver; wraps in {result: [...]}"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

GET /api/now/table/sn_hr_core_employee_certification_and_license

ServiceNow Table API parity: an employee's certification/license records (sysparm_query=employee=<sys_id>^active=true). Supports the dot-walked certification_or_license.governing_agency field via sysparm_fields; wraps in {result: [...]}. Always shaped as sysparm_display_value=true + sysparm_exclude_reference_link=true (the emulated action sends both as true; not a toggle here — see README).

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "ServiceNow Table API parity: an employee's certification/license records (sysparm_query=employee=<sys_id>^active=true). Supports the dot-walked certification_or_license.governing_agency field via sysparm_fields; wraps in {result: [...]}. Always shaped as sysparm_display_value=true + sysparm_exclude_reference_link=true (the emulated action sends both as true; not a toggle here — see README).",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "query",
      "name": "sysparm_query",
      "required": false,
      "schema": {
        "type": "string"
      },
      "example": "employee=12cf2eef933d0390f657fdab3603d6b3^active=true"
    },
    {
      "in": "query",
      "name": "sysparm_fields",
      "required": false,
      "schema": {
        "type": "string"
      },
      "example": "certification_or_license,certification_or_license.governing_agency,issue_date,expiration_date,status,employee,sys_id"
    },
    {
      "in": "query",
      "name": "sysparm_limit",
      "required": false,
      "schema": {
        "type": "integer"
      }
    },
    {
      "in": "query",
      "name": "sysparm_offset",
      "required": false,
      "schema": {
        "type": "integer"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "ServiceNow Table API parity: an employee's certification/license records (sysparm_query=employee=<sys_id>^active=true). Supports the dot-walked certification_or_license.governing_agency field via sysparm_fields; wraps in {result: [...]}. Always shaped as sysparm_display_value=true + sysparm_exclude_reference_link=true (the emulated action sends both as true; not a toggle here — see README)."
    },
    "400": {
      "description": "Bad request"
    }
  }
}

GET /api/now/table/sn_hr_core_profile

ServiceNow Table API parity: look up an employee's HR profile by name (sysparm_query=user.name=<value>); reference fields (user.department/user.manager/user.location) as {display_value, link}; wraps in {result: [...]}

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "ServiceNow Table API parity: look up an employee's HR profile by name (sysparm_query=user.name=<value>); reference fields (user.department/user.manager/user.location) as {display_value, link}; wraps in {result: [...]}",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "ServiceNow Table API parity: look up an employee's HR profile by name (sysparm_query=user.name=<value>); reference fields (user.department/user.manager/user.location) as {display_value, link}; wraps in {result: [...]}"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

GET /api/now/table/sys_user_has_skill

ServiceNow Table API parity: list an employee's skills by sys_id (sysparm_query=user.sys_id=<value>); skill/skill_level as {display_value, link} (skill_level is "" when unset); wraps in {result: [...]}

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "ServiceNow Table API parity: list an employee's skills by sys_id (sysparm_query=user.sys_id=<value>); skill/skill_level as {display_value, link} (skill_level is \"\" when unset); wraps in {result: [...]}",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "ServiceNow Table API parity: list an employee's skills by sys_id (sysparm_query=user.sys_id=<value>); skill/skill_level as {display_value, link} (skill_level is \"\" when unset); wraps in {result: [...]}"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

GET /er_cases

Look up an ER case by number, or count ER cases by allegation type / department / location / leader / hr_service / date range (SN HRERCaseAPI parity)

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Look up an ER case by number, or count ER cases by allegation type / department / location / leader / hr_service / date range (SN HRERCaseAPI parity)",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "Look up an ER case by number, or count ER cases by allegation type / department / location / leader / hr_service / date range (SN HRERCaseAPI parity)"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

GET /hr_profile/org_structure/{manager_sys_id}

Get organization structure for a manager (direct reports and 2nd-level reports in hierarchical tree format). Success (200) is wrapped in {result: ...}; error responses (400/404/500) are flat/unwrapped.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Get organization structure for a manager (direct reports and 2nd-level reports in hierarchical tree format). Success (200) is wrapped in {result: ...}; error responses (400/404/500) are flat/unwrapped.",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "manager_sys_id",
      "required": true,
      "schema": {
        "type": "string"
      },
      "description": "sys_id (employee id) of the manager to query"
    },
    {
      "in": "query",
      "name": "level",
      "schema": {
        "type": "integer",
        "minimum": 1,
        "maximum": 2,
        "default": 2
      },
      "description": "How many levels deep to query (1 or 2)"
    }
  ],
  "responses": {
    "200": {
      "description": "Organization structure retrieved successfully, wrapped in {result: ...}"
    },
    "400": {
      "description": "Bad request (missing manager_sys_id, or level outside 1-2); flat, unwrapped"
    },
    "404": {
      "description": "Manager not found; flat, unwrapped"
    },
    "500": {
      "description": "Internal error, or a non-numeric level (SN quirk — see contract.ts); flat, unwrapped"
    }
  }
}

GET /hrbp_batch_user_resolution/resolve

Batch resolve user names to emails for meeting scheduling (SN hrbp_batch_user_resolution parity)

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Batch resolve user names to emails for meeting scheduling (SN hrbp_batch_user_resolution parity)",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "Batch resolve user names to emails for meeting scheduling (SN hrbp_batch_user_resolution parity)"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

GET /hrbp_capabilities

Which optional HRBP Hub modules (e.g. Talent Pulse) are available on this instance (SN hrbp_capabilities parity)

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Which optional HRBP Hub modules (e.g. Talent Pulse) are available on this instance (SN hrbp_capabilities parity)",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "responses": {
    "200": {
      "description": "Which optional HRBP Hub modules (e.g. Talent Pulse) are available on this instance (SN hrbp_capabilities parity)"
    },
    "400": {
      "description": "Bad request"
    }
  }
}

GET /hrbp_manager_span

Get manager span of control

With manager_sys_id: that manager's direct + total report counts — {result: {manager_sys_id, num_direct_reports, num_total_reports, title, is_manager}}; 404 if no such user exists. Without it: the calling HRBP's in-scope managers ranked by total reports, paginated 10 per page — {result: {page_number, count, managers, average_total_reports}}.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Get manager span of control",
  "x-mcp": false,
  "x-odata": false,
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "query",
      "name": "manager_sys_id",
      "required": false,
      "schema": {
        "type": "string"
      },
      "example": "EMP-0003"
    },
    {
      "in": "query",
      "name": "page_number",
      "required": false,
      "schema": {
        "type": "integer"
      },
      "example": 1
    }
  ],
  "responses": {
    "200": {
      "description": "Get manager span of control"
    },
    "400": {
      "description": "Bad request"
    }
  },
  "description": "With manager_sys_id: that manager's direct + total report counts — {result: {manager_sys_id, num_direct_reports, num_total_reports, title, is_manager}}; 404 if no such user exists. Without it: the calling HRBP's in-scope managers ranked by total reports, paginated 10 per page — {result: {page_number, count, managers, average_total_reports}}."
}

GET /talent_reviews

List talent reviews

A talent review is the HRBP's saved analytics package: a named review over a scope (leaders / departments / locations) and period, carrying an ordered list of attached metrics (headcount, attrition_rate, 9-box distribution, ...). It is the record the tp_* ServiceNow-parity tools create and execute. Use this raw list to browse or audit review records; use tp_find_reviews / tp_search_reviews when resolving by leader or department NAME. Server-side query: $filter/$select/$orderby/$search/$top/$skip/$count (MCP clients pass these as _filter, _top, ... because $ is not a legal tool-input key).

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "List talent reviews",
  "description": "A talent review is the HRBP's saved analytics package: a named review over a scope (leaders / departments / locations) and period, carrying an ordered list of attached metrics (headcount, attrition_rate, 9-box distribution, ...). It is the record the tp_* ServiceNow-parity tools create and execute. Use this raw list to browse or audit review records; use tp_find_reviews / tp_search_reviews when resolving by leader or department NAME. Server-side query: $filter/$select/$orderby/$search/$top/$skip/$count (MCP clients pass these as _filter, _top, ... because $ is not a legal tool-input key).",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "query",
      "name": "limit",
      "schema": {
        "type": "integer",
        "default": 50
      },
      "description": "Legacy page size (default 50). Prefer $top. Ignored when $top/$skip are used."
    },
    {
      "in": "query",
      "name": "cursor",
      "schema": {
        "type": "string"
      },
      "description": "Legacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top."
    },
    {
      "in": "query",
      "name": "$filter",
      "schema": {
        "type": "string"
      },
      "description": "OData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: \"status eq 'active'\"; \"salary gt 50000 and department eq 'Engineering'\"; \"contains(tolower(name),'acme')\"; \"closeDate gt 2026-01-01\"."
    },
    {
      "in": "query",
      "name": "$select",
      "schema": {
        "type": "string"
      },
      "description": "Comma-separated list of fields to return, e.g. \"id,firstName,email\". Nested fields via slash (\"pto_balance/vacation_days\"). The id field is always included."
    },
    {
      "in": "query",
      "name": "$orderby",
      "schema": {
        "type": "string"
      },
      "description": "Sort clause(s), comma-separated, each \"field [asc|desc]\" (asc is the default). Example: \"createdAt desc, lastName asc\". Null values sort last."
    },
    {
      "in": "query",
      "name": "$search",
      "schema": {
        "type": "string"
      },
      "description": "Free-text, case-insensitive substring match across the resource's searchable fields."
    },
    {
      "in": "query",
      "name": "$top",
      "schema": {
        "type": "integer"
      },
      "description": "Maximum number of items to return (page size)."
    },
    {
      "in": "query",
      "name": "$skip",
      "schema": {
        "type": "integer"
      },
      "description": "Number of matching items to skip before returning results (offset paging). Combine with $top."
    },
    {
      "in": "query",
      "name": "$count",
      "schema": {
        "type": "boolean"
      },
      "description": "When true, include @odata.count (total matches after $filter/$search, before paging) in the response."
    }
  ],
  "responses": {
    "200": {
      "description": "Paginated list",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/TalentReview"
                }
              },
              "nextCursor": {
                "type": "string",
                "nullable": true,
                "description": "Cursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor."
              },
              "total": {
                "type": "integer",
                "description": "Total documents in the collection."
              },
              "@odata.count": {
                "type": "integer",
                "description": "Present only when $count=true: total matches after $filter/$search."
              },
              "@odata.truncated": {
                "type": "boolean",
                "description": "Present and true only when the collection exceeded the in-memory query cap and results may be incomplete."
              }
            }
          }
        }
      }
    },
    "400": {
      "description": "Invalid OData query (e.g. malformed $filter)"
    }
  }
}

POST /talent_reviews

Create a talent review record directly

Writes a talent review row with its scope, period and metric list, bypassing the guided flow. Prefer tp_preview_review + tp_commit_review (or tp_create_review_from_template), which validate the HRBP's scope access and de-duplicate via an idempotency key.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Create a talent review record directly",
  "description": "Writes a talent review row with its scope, period and metric list, bypassing the guided flow. Prefer tp_preview_review + tp_commit_review (or tp_create_review_from_template), which validate the HRBP's scope access and de-duplicate via an idempotency key.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/TalentReview"
        }
      }
    }
  },
  "responses": {
    "201": {
      "description": "Created",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/TalentReview"
          }
        }
      }
    }
  }
}

GET /talent_reviews/{id}

Get a talent review by id

Returns one review's definition - scope, period and attached metrics - but NOT computed results. Use tp_display_review or tp_execute_review to get metric values.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Get a talent review by id",
  "description": "Returns one review's definition - scope, period and attached metrics - but NOT computed results. Use tp_display_review or tp_execute_review to get metric values.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Found",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/TalentReview"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

PATCH /talent_reviews/{id}

Edit a talent review record

Partial update of a review's name, scope, period or attached metric list. To add a metric to an existing review prefer tp_add_metric, which is idempotent on (review, metric).

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Edit a talent review record",
  "description": "Partial update of a review's name, scope, period or attached metric list. To add a metric to an existing review prefer tp_add_metric, which is idempotent on (review, metric).",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "description": "Fields to update (partial)",
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/TalentReview"
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Updated",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/TalentReview"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

DELETE /talent_reviews/{id}

Delete a talent review

DESTRUCTIVE and irreversible: removes the review and its attached metric configuration. Any snapshots already captured from it survive as separate records. Confirm with the user before calling.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Delete a talent review",
  "description": "DESTRUCTIVE and irreversible: removes the review and its attached metric configuration. Any snapshots already captured from it survive as separate records. Confirm with the user before calling.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Deleted",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "success": {
                "type": "boolean"
              }
            }
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

GET /employee_assessments

List 9-box employee assessments

An employee assessment is one employee's talent-review datapoint for a cycle: performance_rating (1-5) and derived performance_band, potential, flight_risk, replacement_readiness, achievable_level and the derived 9-box cell. This is HRBP calibration data, distinct from HRIS performance reviews (the formal review record) and from performance_reviews here (manager/employee rating pairs). Server-side query: $filter/$select/$orderby/$search/$top/$skip/$count (MCP clients pass these as _filter, _top, ... because $ is not a legal tool-input key).

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "List 9-box employee assessments",
  "description": "An employee assessment is one employee's talent-review datapoint for a cycle: performance_rating (1-5) and derived performance_band, potential, flight_risk, replacement_readiness, achievable_level and the derived 9-box cell. This is HRBP calibration data, distinct from HRIS performance reviews (the formal review record) and from performance_reviews here (manager/employee rating pairs). Server-side query: $filter/$select/$orderby/$search/$top/$skip/$count (MCP clients pass these as _filter, _top, ... because $ is not a legal tool-input key).",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "query",
      "name": "limit",
      "schema": {
        "type": "integer",
        "default": 50
      },
      "description": "Legacy page size (default 50). Prefer $top. Ignored when $top/$skip are used."
    },
    {
      "in": "query",
      "name": "cursor",
      "schema": {
        "type": "string"
      },
      "description": "Legacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top."
    },
    {
      "in": "query",
      "name": "$filter",
      "schema": {
        "type": "string"
      },
      "description": "OData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: \"status eq 'active'\"; \"salary gt 50000 and department eq 'Engineering'\"; \"contains(tolower(name),'acme')\"; \"closeDate gt 2026-01-01\"."
    },
    {
      "in": "query",
      "name": "$select",
      "schema": {
        "type": "string"
      },
      "description": "Comma-separated list of fields to return, e.g. \"id,firstName,email\". Nested fields via slash (\"pto_balance/vacation_days\"). The id field is always included."
    },
    {
      "in": "query",
      "name": "$orderby",
      "schema": {
        "type": "string"
      },
      "description": "Sort clause(s), comma-separated, each \"field [asc|desc]\" (asc is the default). Example: \"createdAt desc, lastName asc\". Null values sort last."
    },
    {
      "in": "query",
      "name": "$search",
      "schema": {
        "type": "string"
      },
      "description": "Free-text, case-insensitive substring match across the resource's searchable fields."
    },
    {
      "in": "query",
      "name": "$top",
      "schema": {
        "type": "integer"
      },
      "description": "Maximum number of items to return (page size)."
    },
    {
      "in": "query",
      "name": "$skip",
      "schema": {
        "type": "integer"
      },
      "description": "Number of matching items to skip before returning results (offset paging). Combine with $top."
    },
    {
      "in": "query",
      "name": "$count",
      "schema": {
        "type": "boolean"
      },
      "description": "When true, include @odata.count (total matches after $filter/$search, before paging) in the response."
    }
  ],
  "responses": {
    "200": {
      "description": "Paginated list",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/EmployeeAssessment"
                }
              },
              "nextCursor": {
                "type": "string",
                "nullable": true,
                "description": "Cursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor."
              },
              "total": {
                "type": "integer",
                "description": "Total documents in the collection."
              },
              "@odata.count": {
                "type": "integer",
                "description": "Present only when $count=true: total matches after $filter/$search."
              },
              "@odata.truncated": {
                "type": "boolean",
                "description": "Present and true only when the collection exceeded the in-memory query cap and results may be incomplete."
              }
            }
          }
        }
      }
    },
    "400": {
      "description": "Invalid OData query (e.g. malformed $filter)"
    }
  }
}

POST /employee_assessments

Create an employee assessment (9-box datapoint)

Records one employee's calibration for a cycle, optionally tied to a talent_review_id. `box` is derived from potential x performance - do not set it.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Create an employee assessment (9-box datapoint)",
  "description": "Records one employee's calibration for a cycle, optionally tied to a talent_review_id. `box` is derived from potential x performance - do not set it.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/EmployeeAssessment"
        }
      }
    }
  },
  "responses": {
    "201": {
      "description": "Created",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/EmployeeAssessment"
          }
        }
      }
    }
  }
}

GET /employee_assessments/{id}

Get an employee assessment by id

Returns one employee's assessment for a cycle, including the derived 9-box cell, core competencies and development needs.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Get an employee assessment by id",
  "description": "Returns one employee's assessment for a cycle, including the derived 9-box cell, core competencies and development needs.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Found",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/EmployeeAssessment"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

PATCH /employee_assessments/{id}

Edit an employee assessment

Partial update of a calibration datapoint (rating, potential, flight risk, readiness). The 9-box cell is recomputed by the server.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Edit an employee assessment",
  "description": "Partial update of a calibration datapoint (rating, potential, flight risk, readiness). The 9-box cell is recomputed by the server.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "description": "Fields to update (partial)",
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/EmployeeAssessment"
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Updated",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/EmployeeAssessment"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

DELETE /employee_assessments/{id}

Delete an employee assessment

DESTRUCTIVE and irreversible: removes the employee's calibration datapoint for that cycle, changing any 9-box or performance-distribution metric computed afterwards.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Delete an employee assessment",
  "description": "DESTRUCTIVE and irreversible: removes the employee's calibration datapoint for that cycle, changing any 9-box or performance-distribution metric computed afterwards.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Deleted",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "success": {
                "type": "boolean"
              }
            }
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

GET /performance_reviews

List performance review ratings

A performance review here is a lightweight rating pair for one employee over a review window: rating_manager and rating_employee (1-5) plus the assessment date. It feeds HRBP performance metrics. Narrower than an HRIS employee review (strengths/gaps narrative) and than an employee assessment (9-box potential and flight risk). Server-side query: $filter/$select/$orderby/$search/$top/$skip/$count (MCP clients pass these as _filter, _top, ... because $ is not a legal tool-input key).

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "List performance review ratings",
  "description": "A performance review here is a lightweight rating pair for one employee over a review window: rating_manager and rating_employee (1-5) plus the assessment date. It feeds HRBP performance metrics. Narrower than an HRIS employee review (strengths/gaps narrative) and than an employee assessment (9-box potential and flight risk). Server-side query: $filter/$select/$orderby/$search/$top/$skip/$count (MCP clients pass these as _filter, _top, ... because $ is not a legal tool-input key).",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "query",
      "name": "limit",
      "schema": {
        "type": "integer",
        "default": 50
      },
      "description": "Legacy page size (default 50). Prefer $top. Ignored when $top/$skip are used."
    },
    {
      "in": "query",
      "name": "cursor",
      "schema": {
        "type": "string"
      },
      "description": "Legacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top."
    },
    {
      "in": "query",
      "name": "$filter",
      "schema": {
        "type": "string"
      },
      "description": "OData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: \"status eq 'active'\"; \"salary gt 50000 and department eq 'Engineering'\"; \"contains(tolower(name),'acme')\"; \"closeDate gt 2026-01-01\"."
    },
    {
      "in": "query",
      "name": "$select",
      "schema": {
        "type": "string"
      },
      "description": "Comma-separated list of fields to return, e.g. \"id,firstName,email\". Nested fields via slash (\"pto_balance/vacation_days\"). The id field is always included."
    },
    {
      "in": "query",
      "name": "$orderby",
      "schema": {
        "type": "string"
      },
      "description": "Sort clause(s), comma-separated, each \"field [asc|desc]\" (asc is the default). Example: \"createdAt desc, lastName asc\". Null values sort last."
    },
    {
      "in": "query",
      "name": "$search",
      "schema": {
        "type": "string"
      },
      "description": "Free-text, case-insensitive substring match across the resource's searchable fields."
    },
    {
      "in": "query",
      "name": "$top",
      "schema": {
        "type": "integer"
      },
      "description": "Maximum number of items to return (page size)."
    },
    {
      "in": "query",
      "name": "$skip",
      "schema": {
        "type": "integer"
      },
      "description": "Number of matching items to skip before returning results (offset paging). Combine with $top."
    },
    {
      "in": "query",
      "name": "$count",
      "schema": {
        "type": "boolean"
      },
      "description": "When true, include @odata.count (total matches after $filter/$search, before paging) in the response."
    }
  ],
  "responses": {
    "200": {
      "description": "Paginated list",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/PerformanceReview"
                }
              },
              "nextCursor": {
                "type": "string",
                "nullable": true,
                "description": "Cursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor."
              },
              "total": {
                "type": "integer",
                "description": "Total documents in the collection."
              },
              "@odata.count": {
                "type": "integer",
                "description": "Present only when $count=true: total matches after $filter/$search."
              },
              "@odata.truncated": {
                "type": "boolean",
                "description": "Present and true only when the collection exceeded the in-memory query cap and results may be incomplete."
              }
            }
          }
        }
      }
    },
    "400": {
      "description": "Invalid OData query (e.g. malformed $filter)"
    }
  }
}

POST /performance_reviews

Create a performance review rating

Records a manager and/or self rating for an employee over a review period. Use employee_assessments instead when you need potential, flight risk or 9-box placement.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Create a performance review rating",
  "description": "Records a manager and/or self rating for an employee over a review period. Use employee_assessments instead when you need potential, flight risk or 9-box placement.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/PerformanceReview"
        }
      }
    }
  },
  "responses": {
    "201": {
      "description": "Created",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/PerformanceReview"
          }
        }
      }
    }
  }
}

GET /performance_reviews/{id}

Get a performance review rating by id

Returns one rating record: the employee, the review window and the manager/employee scores.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Get a performance review rating by id",
  "description": "Returns one rating record: the employee, the review window and the manager/employee scores.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Found",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/PerformanceReview"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

PATCH /performance_reviews/{id}

Edit a performance review rating

Partial update of the review window or the manager/employee ratings.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Edit a performance review rating",
  "description": "Partial update of the review window or the manager/employee ratings.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "description": "Fields to update (partial)",
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/PerformanceReview"
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Updated",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/PerformanceReview"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

DELETE /performance_reviews/{id}

Delete a performance review rating

DESTRUCTIVE and irreversible: removes the rating record, which changes any performance metric recomputed afterwards.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Delete a performance review rating",
  "description": "DESTRUCTIVE and irreversible: removes the rating record, which changes any performance metric recomputed afterwards.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Deleted",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "success": {
                "type": "boolean"
              }
            }
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

GET /succession_plans

List succession plans for critical roles

A succession plan covers one critical ROLE (title, incumbent, department) with its criticality, loss_impact, retention_risk, success profile and a count of named successors. The candidates themselves are separate successor records linked by succession_plan_id. Use this to answer 'which roles have succession coverage'. Server-side query: $filter/$select/$orderby/$search/$top/$skip/$count (MCP clients pass these as _filter, _top, ... because $ is not a legal tool-input key).

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "List succession plans for critical roles",
  "description": "A succession plan covers one critical ROLE (title, incumbent, department) with its criticality, loss_impact, retention_risk, success profile and a count of named successors. The candidates themselves are separate successor records linked by succession_plan_id. Use this to answer 'which roles have succession coverage'. Server-side query: $filter/$select/$orderby/$search/$top/$skip/$count (MCP clients pass these as _filter, _top, ... because $ is not a legal tool-input key).",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "query",
      "name": "limit",
      "schema": {
        "type": "integer",
        "default": 50
      },
      "description": "Legacy page size (default 50). Prefer $top. Ignored when $top/$skip are used."
    },
    {
      "in": "query",
      "name": "cursor",
      "schema": {
        "type": "string"
      },
      "description": "Legacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top."
    },
    {
      "in": "query",
      "name": "$filter",
      "schema": {
        "type": "string"
      },
      "description": "OData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: \"status eq 'active'\"; \"salary gt 50000 and department eq 'Engineering'\"; \"contains(tolower(name),'acme')\"; \"closeDate gt 2026-01-01\"."
    },
    {
      "in": "query",
      "name": "$select",
      "schema": {
        "type": "string"
      },
      "description": "Comma-separated list of fields to return, e.g. \"id,firstName,email\". Nested fields via slash (\"pto_balance/vacation_days\"). The id field is always included."
    },
    {
      "in": "query",
      "name": "$orderby",
      "schema": {
        "type": "string"
      },
      "description": "Sort clause(s), comma-separated, each \"field [asc|desc]\" (asc is the default). Example: \"createdAt desc, lastName asc\". Null values sort last."
    },
    {
      "in": "query",
      "name": "$search",
      "schema": {
        "type": "string"
      },
      "description": "Free-text, case-insensitive substring match across the resource's searchable fields."
    },
    {
      "in": "query",
      "name": "$top",
      "schema": {
        "type": "integer"
      },
      "description": "Maximum number of items to return (page size)."
    },
    {
      "in": "query",
      "name": "$skip",
      "schema": {
        "type": "integer"
      },
      "description": "Number of matching items to skip before returning results (offset paging). Combine with $top."
    },
    {
      "in": "query",
      "name": "$count",
      "schema": {
        "type": "boolean"
      },
      "description": "When true, include @odata.count (total matches after $filter/$search, before paging) in the response."
    }
  ],
  "responses": {
    "200": {
      "description": "Paginated list",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/SuccessionPlan"
                }
              },
              "nextCursor": {
                "type": "string",
                "nullable": true,
                "description": "Cursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor."
              },
              "total": {
                "type": "integer",
                "description": "Total documents in the collection."
              },
              "@odata.count": {
                "type": "integer",
                "description": "Present only when $count=true: total matches after $filter/$search."
              },
              "@odata.truncated": {
                "type": "boolean",
                "description": "Present and true only when the collection exceeded the in-memory query cap and results may be incomplete."
              }
            }
          }
        }
      }
    },
    "400": {
      "description": "Invalid OData query (e.g. malformed $filter)"
    }
  }
}

POST /succession_plans

Create a succession plan for a role

Opens a plan for a critical role and its incumbent. Add candidates afterwards as successor records; successor_count is maintained by the server.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Create a succession plan for a role",
  "description": "Opens a plan for a critical role and its incumbent. Add candidates afterwards as successor records; successor_count is maintained by the server.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/SuccessionPlan"
        }
      }
    }
  },
  "responses": {
    "201": {
      "description": "Created",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/SuccessionPlan"
          }
        }
      }
    }
  }
}

GET /succession_plans/{id}

Get a succession plan by id

Returns one role's plan - incumbent, criticality, loss impact, retention risk and success profile. Candidate details live in the successors collection filtered by succession_plan_id.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Get a succession plan by id",
  "description": "Returns one role's plan - incumbent, criticality, loss impact, retention risk and success profile. Candidate details live in the successors collection filtered by succession_plan_id.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Found",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/SuccessionPlan"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

PATCH /succession_plans/{id}

Edit a succession plan

Partial update of the plan's role metadata, risk ratings or success profile. Adding or ranking candidates is done on successor records, not here.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Edit a succession plan",
  "description": "Partial update of the plan's role metadata, risk ratings or success profile. Adding or ranking candidates is done on successor records, not here.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "description": "Fields to update (partial)",
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/SuccessionPlan"
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Updated",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/SuccessionPlan"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

DELETE /succession_plans/{id}

Delete a succession plan

DESTRUCTIVE and irreversible: removes the plan. Its successor records are orphaned rather than deleted. Prefer setting `active` to false to retire a plan.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Delete a succession plan",
  "description": "DESTRUCTIVE and irreversible: removes the plan. Its successor records are orphaned rather than deleted. Prefer setting `active` to false to retire a plan.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Deleted",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "success": {
                "type": "boolean"
              }
            }
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

GET /successors

List succession candidates

A successor is one named candidate on a succession plan: candidate_employee_id, top_candidate flag, readiness (ready now / 3 / 6 / 12 months), potential, current rating, matching score and development areas. Filter by succession_plan_id to see a role's bench; filter by candidate_employee_id to see which roles a person is slated for. Server-side query: $filter/$select/$orderby/$search/$top/$skip/$count (MCP clients pass these as _filter, _top, ... because $ is not a legal tool-input key).

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "List succession candidates",
  "description": "A successor is one named candidate on a succession plan: candidate_employee_id, top_candidate flag, readiness (ready now / 3 / 6 / 12 months), potential, current rating, matching score and development areas. Filter by succession_plan_id to see a role's bench; filter by candidate_employee_id to see which roles a person is slated for. Server-side query: $filter/$select/$orderby/$search/$top/$skip/$count (MCP clients pass these as _filter, _top, ... because $ is not a legal tool-input key).",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "query",
      "name": "limit",
      "schema": {
        "type": "integer",
        "default": 50
      },
      "description": "Legacy page size (default 50). Prefer $top. Ignored when $top/$skip are used."
    },
    {
      "in": "query",
      "name": "cursor",
      "schema": {
        "type": "string"
      },
      "description": "Legacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top."
    },
    {
      "in": "query",
      "name": "$filter",
      "schema": {
        "type": "string"
      },
      "description": "OData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: \"status eq 'active'\"; \"salary gt 50000 and department eq 'Engineering'\"; \"contains(tolower(name),'acme')\"; \"closeDate gt 2026-01-01\"."
    },
    {
      "in": "query",
      "name": "$select",
      "schema": {
        "type": "string"
      },
      "description": "Comma-separated list of fields to return, e.g. \"id,firstName,email\". Nested fields via slash (\"pto_balance/vacation_days\"). The id field is always included."
    },
    {
      "in": "query",
      "name": "$orderby",
      "schema": {
        "type": "string"
      },
      "description": "Sort clause(s), comma-separated, each \"field [asc|desc]\" (asc is the default). Example: \"createdAt desc, lastName asc\". Null values sort last."
    },
    {
      "in": "query",
      "name": "$search",
      "schema": {
        "type": "string"
      },
      "description": "Free-text, case-insensitive substring match across the resource's searchable fields."
    },
    {
      "in": "query",
      "name": "$top",
      "schema": {
        "type": "integer"
      },
      "description": "Maximum number of items to return (page size)."
    },
    {
      "in": "query",
      "name": "$skip",
      "schema": {
        "type": "integer"
      },
      "description": "Number of matching items to skip before returning results (offset paging). Combine with $top."
    },
    {
      "in": "query",
      "name": "$count",
      "schema": {
        "type": "boolean"
      },
      "description": "When true, include @odata.count (total matches after $filter/$search, before paging) in the response."
    }
  ],
  "responses": {
    "200": {
      "description": "Paginated list",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Successor"
                }
              },
              "nextCursor": {
                "type": "string",
                "nullable": true,
                "description": "Cursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor."
              },
              "total": {
                "type": "integer",
                "description": "Total documents in the collection."
              },
              "@odata.count": {
                "type": "integer",
                "description": "Present only when $count=true: total matches after $filter/$search."
              },
              "@odata.truncated": {
                "type": "boolean",
                "description": "Present and true only when the collection exceeded the in-memory query cap and results may be incomplete."
              }
            }
          }
        }
      }
    },
    "400": {
      "description": "Invalid OData query (e.g. malformed $filter)"
    }
  }
}

POST /successors

Add a candidate to a succession plan

Names an employee as a successor for the plan given by succession_plan_id, with their readiness and potential. The plan's successor_count is updated by the server.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Add a candidate to a succession plan",
  "description": "Names an employee as a successor for the plan given by succession_plan_id, with their readiness and potential. The plan's successor_count is updated by the server.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/Successor"
        }
      }
    }
  },
  "responses": {
    "201": {
      "description": "Created",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Successor"
          }
        }
      }
    }
  }
}

GET /successors/{id}

Get a succession candidate by id

Returns one candidate's bench entry: readiness, potential, achievable level, match score and development areas.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Get a succession candidate by id",
  "description": "Returns one candidate's bench entry: readiness, potential, achievable level, match score and development areas.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Found",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Successor"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

PATCH /successors/{id}

Edit a succession candidate

Partial update of a candidate's readiness, potential, top_candidate flag or development areas - the usual way to re-rank a bench after calibration.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Edit a succession candidate",
  "description": "Partial update of a candidate's readiness, potential, top_candidate flag or development areas - the usual way to re-rank a bench after calibration.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "description": "Fields to update (partial)",
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/Successor"
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Updated",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Successor"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

DELETE /successors/{id}

Remove a candidate from a succession plan

DESTRUCTIVE and irreversible: deletes the bench entry and lowers the plan's coverage. The employee record itself is untouched.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Remove a candidate from a succession plan",
  "description": "DESTRUCTIVE and irreversible: deletes the bench entry and lowers the plan's coverage. The employee record itself is untouched.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Deleted",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "success": {
                "type": "boolean"
              }
            }
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

GET /snapshots

List captured metric snapshots

A snapshot is one metric value frozen at a point in time: metric_id, the computed value JSON (per group), a source and a timestamp, batched under a group_id. Snapshots are the history that makes trend questions answerable; to compute a metric live use tp_execute_metric or tp_query_metric instead. Server-side query: $filter/$select/$orderby/$search/$top/$skip/$count (MCP clients pass these as _filter, _top, ... because $ is not a legal tool-input key).

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "List captured metric snapshots",
  "description": "A snapshot is one metric value frozen at a point in time: metric_id, the computed value JSON (per group), a source and a timestamp, batched under a group_id. Snapshots are the history that makes trend questions answerable; to compute a metric live use tp_execute_metric or tp_query_metric instead. Server-side query: $filter/$select/$orderby/$search/$top/$skip/$count (MCP clients pass these as _filter, _top, ... because $ is not a legal tool-input key).",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "query",
      "name": "limit",
      "schema": {
        "type": "integer",
        "default": 50
      },
      "description": "Legacy page size (default 50). Prefer $top. Ignored when $top/$skip are used."
    },
    {
      "in": "query",
      "name": "cursor",
      "schema": {
        "type": "string"
      },
      "description": "Legacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top."
    },
    {
      "in": "query",
      "name": "$filter",
      "schema": {
        "type": "string"
      },
      "description": "OData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: \"status eq 'active'\"; \"salary gt 50000 and department eq 'Engineering'\"; \"contains(tolower(name),'acme')\"; \"closeDate gt 2026-01-01\"."
    },
    {
      "in": "query",
      "name": "$select",
      "schema": {
        "type": "string"
      },
      "description": "Comma-separated list of fields to return, e.g. \"id,firstName,email\". Nested fields via slash (\"pto_balance/vacation_days\"). The id field is always included."
    },
    {
      "in": "query",
      "name": "$orderby",
      "schema": {
        "type": "string"
      },
      "description": "Sort clause(s), comma-separated, each \"field [asc|desc]\" (asc is the default). Example: \"createdAt desc, lastName asc\". Null values sort last."
    },
    {
      "in": "query",
      "name": "$search",
      "schema": {
        "type": "string"
      },
      "description": "Free-text, case-insensitive substring match across the resource's searchable fields."
    },
    {
      "in": "query",
      "name": "$top",
      "schema": {
        "type": "integer"
      },
      "description": "Maximum number of items to return (page size)."
    },
    {
      "in": "query",
      "name": "$skip",
      "schema": {
        "type": "integer"
      },
      "description": "Number of matching items to skip before returning results (offset paging). Combine with $top."
    },
    {
      "in": "query",
      "name": "$count",
      "schema": {
        "type": "boolean"
      },
      "description": "When true, include @odata.count (total matches after $filter/$search, before paging) in the response."
    }
  ],
  "responses": {
    "200": {
      "description": "Paginated list",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Snapshot"
                }
              },
              "nextCursor": {
                "type": "string",
                "nullable": true,
                "description": "Cursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor."
              },
              "total": {
                "type": "integer",
                "description": "Total documents in the collection."
              },
              "@odata.count": {
                "type": "integer",
                "description": "Present only when $count=true: total matches after $filter/$search."
              },
              "@odata.truncated": {
                "type": "boolean",
                "description": "Present and true only when the collection exceeded the in-memory query cap and results may be incomplete."
              }
            }
          }
        }
      }
    },
    "400": {
      "description": "Invalid OData query (e.g. malformed $filter)"
    }
  }
}

POST /snapshots

Capture a metric snapshot

Stores a computed metric value against a metric_id and group_id. Normally written by the snapshot pipeline - creating one by hand inserts a datapoint into the trend history.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Capture a metric snapshot",
  "description": "Stores a computed metric value against a metric_id and group_id. Normally written by the snapshot pipeline - creating one by hand inserts a datapoint into the trend history.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/Snapshot"
        }
      }
    }
  },
  "responses": {
    "201": {
      "description": "Created",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Snapshot"
          }
        }
      }
    }
  }
}

GET /snapshots/{id}

Get a metric snapshot by id

Returns one frozen metric value with its timestamp, source and per-group breakdown.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Get a metric snapshot by id",
  "description": "Returns one frozen metric value with its timestamp, source and per-group breakdown.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Found",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Snapshot"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

PATCH /snapshots/{id}

Edit a metric snapshot

Partial update of a stored datapoint. Editing history rewrites what trend queries will report - prefer capturing a new snapshot.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Edit a metric snapshot",
  "description": "Partial update of a stored datapoint. Editing history rewrites what trend queries will report - prefer capturing a new snapshot.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "description": "Fields to update (partial)",
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/Snapshot"
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Updated",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Snapshot"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

DELETE /snapshots/{id}

Delete a metric snapshot

DESTRUCTIVE and irreversible: removes a datapoint from the trend history, which changes previously reported trends.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Delete a metric snapshot",
  "description": "DESTRUCTIVE and irreversible: removes a datapoint from the trend history, which changes previously reported trends.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Deleted",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "success": {
                "type": "boolean"
              }
            }
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

GET /metric_goals

List metric goals (targets and thresholds)

A metric goal is a target set on a metric for a period: metric_id, period_start/end, threshold_value and a comparison_type saying whether being above or below the threshold is good. Optionally scoped to a talent review. Read these to judge whether a computed metric is on or off target. Server-side query: $filter/$select/$orderby/$search/$top/$skip/$count (MCP clients pass these as _filter, _top, ... because $ is not a legal tool-input key).

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "List metric goals (targets and thresholds)",
  "description": "A metric goal is a target set on a metric for a period: metric_id, period_start/end, threshold_value and a comparison_type saying whether being above or below the threshold is good. Optionally scoped to a talent review. Read these to judge whether a computed metric is on or off target. Server-side query: $filter/$select/$orderby/$search/$top/$skip/$count (MCP clients pass these as _filter, _top, ... because $ is not a legal tool-input key).",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "query",
      "name": "limit",
      "schema": {
        "type": "integer",
        "default": 50
      },
      "description": "Legacy page size (default 50). Prefer $top. Ignored when $top/$skip are used."
    },
    {
      "in": "query",
      "name": "cursor",
      "schema": {
        "type": "string"
      },
      "description": "Legacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top."
    },
    {
      "in": "query",
      "name": "$filter",
      "schema": {
        "type": "string"
      },
      "description": "OData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: \"status eq 'active'\"; \"salary gt 50000 and department eq 'Engineering'\"; \"contains(tolower(name),'acme')\"; \"closeDate gt 2026-01-01\"."
    },
    {
      "in": "query",
      "name": "$select",
      "schema": {
        "type": "string"
      },
      "description": "Comma-separated list of fields to return, e.g. \"id,firstName,email\". Nested fields via slash (\"pto_balance/vacation_days\"). The id field is always included."
    },
    {
      "in": "query",
      "name": "$orderby",
      "schema": {
        "type": "string"
      },
      "description": "Sort clause(s), comma-separated, each \"field [asc|desc]\" (asc is the default). Example: \"createdAt desc, lastName asc\". Null values sort last."
    },
    {
      "in": "query",
      "name": "$search",
      "schema": {
        "type": "string"
      },
      "description": "Free-text, case-insensitive substring match across the resource's searchable fields."
    },
    {
      "in": "query",
      "name": "$top",
      "schema": {
        "type": "integer"
      },
      "description": "Maximum number of items to return (page size)."
    },
    {
      "in": "query",
      "name": "$skip",
      "schema": {
        "type": "integer"
      },
      "description": "Number of matching items to skip before returning results (offset paging). Combine with $top."
    },
    {
      "in": "query",
      "name": "$count",
      "schema": {
        "type": "boolean"
      },
      "description": "When true, include @odata.count (total matches after $filter/$search, before paging) in the response."
    }
  ],
  "responses": {
    "200": {
      "description": "Paginated list",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/MetricGoal"
                }
              },
              "nextCursor": {
                "type": "string",
                "nullable": true,
                "description": "Cursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor."
              },
              "total": {
                "type": "integer",
                "description": "Total documents in the collection."
              },
              "@odata.count": {
                "type": "integer",
                "description": "Present only when $count=true: total matches after $filter/$search."
              },
              "@odata.truncated": {
                "type": "boolean",
                "description": "Present and true only when the collection exceeded the in-memory query cap and results may be incomplete."
              }
            }
          }
        }
      }
    },
    "400": {
      "description": "Invalid OData query (e.g. malformed $filter)"
    }
  }
}

POST /metric_goals

Create a metric goal

Sets a target threshold for a metric over a period (e.g. attrition_rate below 3% for FY26), optionally tied to a talent review. Defines the bar; it does not compute anything.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Create a metric goal",
  "description": "Sets a target threshold for a metric over a period (e.g. attrition_rate below 3% for FY26), optionally tied to a talent review. Defines the bar; it does not compute anything.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/MetricGoal"
        }
      }
    }
  },
  "responses": {
    "201": {
      "description": "Created",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/MetricGoal"
          }
        }
      }
    }
  }
}

GET /metric_goals/{id}

Get a metric goal by id

Returns one target: its metric, period, threshold value and comparison direction.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Get a metric goal by id",
  "description": "Returns one target: its metric, period, threshold value and comparison direction.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Found",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/MetricGoal"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

PATCH /metric_goals/{id}

Edit a metric goal

Partial update of a target's threshold, period or comparison direction - i.e. moving the bar.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Edit a metric goal",
  "description": "Partial update of a target's threshold, period or comparison direction - i.e. moving the bar.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "description": "Fields to update (partial)",
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/MetricGoal"
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Updated",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/MetricGoal"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

DELETE /metric_goals/{id}

Delete a metric goal

DESTRUCTIVE and irreversible: removes the target, after which the metric has no threshold to be judged against. Prefer setting `active` to false.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Delete a metric goal",
  "description": "DESTRUCTIVE and irreversible: removes the target, after which the metric has no threshold to be judged against. Prefer setting `active` to false.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Deleted",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "success": {
                "type": "boolean"
              }
            }
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

GET /hrbp_scope_assignments

List HRBP scope assignments (who can see what)

A scope assignment grants ONE HRBP user access to one scope - by scope_type/scope_id, or all_access for an unrestricted HR leader. This is the access-control table that tp_resolve_scope checks before any metric or review runs, and it is why a query can come back access_denied. Server-side query: $filter/$select/$orderby/$search/$top/$skip/$count (MCP clients pass these as _filter, _top, ... because $ is not a legal tool-input key).

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "List HRBP scope assignments (who can see what)",
  "description": "A scope assignment grants ONE HRBP user access to one scope - by scope_type/scope_id, or all_access for an unrestricted HR leader. This is the access-control table that tp_resolve_scope checks before any metric or review runs, and it is why a query can come back access_denied. Server-side query: $filter/$select/$orderby/$search/$top/$skip/$count (MCP clients pass these as _filter, _top, ... because $ is not a legal tool-input key).",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "query",
      "name": "limit",
      "schema": {
        "type": "integer",
        "default": 50
      },
      "description": "Legacy page size (default 50). Prefer $top. Ignored when $top/$skip are used."
    },
    {
      "in": "query",
      "name": "cursor",
      "schema": {
        "type": "string"
      },
      "description": "Legacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top."
    },
    {
      "in": "query",
      "name": "$filter",
      "schema": {
        "type": "string"
      },
      "description": "OData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: \"status eq 'active'\"; \"salary gt 50000 and department eq 'Engineering'\"; \"contains(tolower(name),'acme')\"; \"closeDate gt 2026-01-01\"."
    },
    {
      "in": "query",
      "name": "$select",
      "schema": {
        "type": "string"
      },
      "description": "Comma-separated list of fields to return, e.g. \"id,firstName,email\". Nested fields via slash (\"pto_balance/vacation_days\"). The id field is always included."
    },
    {
      "in": "query",
      "name": "$orderby",
      "schema": {
        "type": "string"
      },
      "description": "Sort clause(s), comma-separated, each \"field [asc|desc]\" (asc is the default). Example: \"createdAt desc, lastName asc\". Null values sort last."
    },
    {
      "in": "query",
      "name": "$search",
      "schema": {
        "type": "string"
      },
      "description": "Free-text, case-insensitive substring match across the resource's searchable fields."
    },
    {
      "in": "query",
      "name": "$top",
      "schema": {
        "type": "integer"
      },
      "description": "Maximum number of items to return (page size)."
    },
    {
      "in": "query",
      "name": "$skip",
      "schema": {
        "type": "integer"
      },
      "description": "Number of matching items to skip before returning results (offset paging). Combine with $top."
    },
    {
      "in": "query",
      "name": "$count",
      "schema": {
        "type": "boolean"
      },
      "description": "When true, include @odata.count (total matches after $filter/$search, before paging) in the response."
    }
  ],
  "responses": {
    "200": {
      "description": "Paginated list",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/HrbpScopeAssignment"
                }
              },
              "nextCursor": {
                "type": "string",
                "nullable": true,
                "description": "Cursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor."
              },
              "total": {
                "type": "integer",
                "description": "Total documents in the collection."
              },
              "@odata.count": {
                "type": "integer",
                "description": "Present only when $count=true: total matches after $filter/$search."
              },
              "@odata.truncated": {
                "type": "boolean",
                "description": "Present and true only when the collection exceeded the in-memory query cap and results may be incomplete."
              }
            }
          }
        }
      }
    },
    "400": {
      "description": "Invalid OData query (e.g. malformed $filter)"
    }
  }
}

POST /hrbp_scope_assignments

Grant an HRBP access to a scope

Assigns a user a scope (or all_access). SECURITY-SENSITIVE: this widens who can see employee talent data. Confirm with the user before calling.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Grant an HRBP access to a scope",
  "description": "Assigns a user a scope (or all_access). SECURITY-SENSITIVE: this widens who can see employee talent data. Confirm with the user before calling.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/HrbpScopeAssignment"
        }
      }
    }
  },
  "responses": {
    "201": {
      "description": "Created",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/HrbpScopeAssignment"
          }
        }
      }
    }
  }
}

GET /hrbp_scope_assignments/{id}

Get an HRBP scope assignment by id

Returns one grant: the user, the scope type/id it covers, whether it is all_access, and whether it is active.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Get an HRBP scope assignment by id",
  "description": "Returns one grant: the user, the scope type/id it covers, whether it is all_access, and whether it is active.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Found",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/HrbpScopeAssignment"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

PATCH /hrbp_scope_assignments/{id}

Edit an HRBP scope assignment

Partial update of a grant (repoint the scope, toggle all_access or active). SECURITY-SENSITIVE - it changes what employee data that HRBP can see.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Edit an HRBP scope assignment",
  "description": "Partial update of a grant (repoint the scope, toggle all_access or active). SECURITY-SENSITIVE - it changes what employee data that HRBP can see.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "description": "Fields to update (partial)",
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/HrbpScopeAssignment"
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Updated",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/HrbpScopeAssignment"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

DELETE /hrbp_scope_assignments/{id}

Revoke an HRBP scope assignment

DESTRUCTIVE and irreversible: removes the grant, so that HRBP loses access to the scope and their queries may start returning access_denied.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Revoke an HRBP scope assignment",
  "description": "DESTRUCTIVE and irreversible: removes the grant, so that HRBP loses access to the scope and their queries may start returning access_denied.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Deleted",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "success": {
                "type": "boolean"
              }
            }
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

GET /hrbp_scopes

List HRBP scopes (named population definitions)

An HRBP scope is a NAMED population of employees (e.g. 'R&D - AMS') whose membership is defined by its hrbp_scope_rules. Scopes are what scope assignments hand out to HRBP users. Use this to see which populations exist before assigning one. Server-side query: $filter/$select/$orderby/$search/$top/$skip/$count (MCP clients pass these as _filter, _top, ... because $ is not a legal tool-input key).

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "List HRBP scopes (named population definitions)",
  "description": "An HRBP scope is a NAMED population of employees (e.g. 'R&D - AMS') whose membership is defined by its hrbp_scope_rules. Scopes are what scope assignments hand out to HRBP users. Use this to see which populations exist before assigning one. Server-side query: $filter/$select/$orderby/$search/$top/$skip/$count (MCP clients pass these as _filter, _top, ... because $ is not a legal tool-input key).",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "query",
      "name": "limit",
      "schema": {
        "type": "integer",
        "default": 50
      },
      "description": "Legacy page size (default 50). Prefer $top. Ignored when $top/$skip are used."
    },
    {
      "in": "query",
      "name": "cursor",
      "schema": {
        "type": "string"
      },
      "description": "Legacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top."
    },
    {
      "in": "query",
      "name": "$filter",
      "schema": {
        "type": "string"
      },
      "description": "OData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: \"status eq 'active'\"; \"salary gt 50000 and department eq 'Engineering'\"; \"contains(tolower(name),'acme')\"; \"closeDate gt 2026-01-01\"."
    },
    {
      "in": "query",
      "name": "$select",
      "schema": {
        "type": "string"
      },
      "description": "Comma-separated list of fields to return, e.g. \"id,firstName,email\". Nested fields via slash (\"pto_balance/vacation_days\"). The id field is always included."
    },
    {
      "in": "query",
      "name": "$orderby",
      "schema": {
        "type": "string"
      },
      "description": "Sort clause(s), comma-separated, each \"field [asc|desc]\" (asc is the default). Example: \"createdAt desc, lastName asc\". Null values sort last."
    },
    {
      "in": "query",
      "name": "$search",
      "schema": {
        "type": "string"
      },
      "description": "Free-text, case-insensitive substring match across the resource's searchable fields."
    },
    {
      "in": "query",
      "name": "$top",
      "schema": {
        "type": "integer"
      },
      "description": "Maximum number of items to return (page size)."
    },
    {
      "in": "query",
      "name": "$skip",
      "schema": {
        "type": "integer"
      },
      "description": "Number of matching items to skip before returning results (offset paging). Combine with $top."
    },
    {
      "in": "query",
      "name": "$count",
      "schema": {
        "type": "boolean"
      },
      "description": "When true, include @odata.count (total matches after $filter/$search, before paging) in the response."
    }
  ],
  "responses": {
    "200": {
      "description": "Paginated list",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/HrbpScope"
                }
              },
              "nextCursor": {
                "type": "string",
                "nullable": true,
                "description": "Cursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor."
              },
              "total": {
                "type": "integer",
                "description": "Total documents in the collection."
              },
              "@odata.count": {
                "type": "integer",
                "description": "Present only when $count=true: total matches after $filter/$search."
              },
              "@odata.truncated": {
                "type": "boolean",
                "description": "Present and true only when the collection exceeded the in-memory query cap and results may be incomplete."
              }
            }
          }
        }
      }
    },
    "400": {
      "description": "Invalid OData query (e.g. malformed $filter)"
    }
  }
}

POST /hrbp_scopes

Create an HRBP scope

Defines a new named population. It matches nobody until you add hrbp_scope_rules to it.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Create an HRBP scope",
  "description": "Defines a new named population. It matches nobody until you add hrbp_scope_rules to it.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/HrbpScope"
        }
      }
    }
  },
  "responses": {
    "201": {
      "description": "Created",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/HrbpScope"
          }
        }
      }
    }
  }
}

GET /hrbp_scopes/{id}

Get an HRBP scope by id

Returns one scope's name, description and active flag. Its membership criteria are the hrbp_scope_rules with this scope_id.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Get an HRBP scope by id",
  "description": "Returns one scope's name, description and active flag. Its membership criteria are the hrbp_scope_rules with this scope_id.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Found",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/HrbpScope"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

PATCH /hrbp_scopes/{id}

Edit an HRBP scope

Partial update of a scope's name, description or active flag. Membership is changed by editing its rules, not here.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Edit an HRBP scope",
  "description": "Partial update of a scope's name, description or active flag. Membership is changed by editing its rules, not here.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "description": "Fields to update (partial)",
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/HrbpScope"
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Updated",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/HrbpScope"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

DELETE /hrbp_scopes/{id}

Delete an HRBP scope

DESTRUCTIVE and irreversible: removes the population definition. Its rules and any assignments pointing at it are left dangling, so HRBPs may lose access. Confirm with the user before calling.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Delete an HRBP scope",
  "description": "DESTRUCTIVE and irreversible: removes the population definition. Its rules and any assignments pointing at it are left dangling, so HRBPs may lose access. Confirm with the user before calling.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Deleted",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "success": {
                "type": "boolean"
              }
            }
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

GET /hrbp_scope_rules

List HRBP scope membership rules

A scope rule is one membership clause of an HRBP scope: a dimension (department, location, leader, ...) and the value that must match. Rules combine to define who the parent scope covers. Filter by scope_id to read one population's definition. Server-side query: $filter/$select/$orderby/$search/$top/$skip/$count (MCP clients pass these as _filter, _top, ... because $ is not a legal tool-input key).

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "List HRBP scope membership rules",
  "description": "A scope rule is one membership clause of an HRBP scope: a dimension (department, location, leader, ...) and the value that must match. Rules combine to define who the parent scope covers. Filter by scope_id to read one population's definition. Server-side query: $filter/$select/$orderby/$search/$top/$skip/$count (MCP clients pass these as _filter, _top, ... because $ is not a legal tool-input key).",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "query",
      "name": "limit",
      "schema": {
        "type": "integer",
        "default": 50
      },
      "description": "Legacy page size (default 50). Prefer $top. Ignored when $top/$skip are used."
    },
    {
      "in": "query",
      "name": "cursor",
      "schema": {
        "type": "string"
      },
      "description": "Legacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top."
    },
    {
      "in": "query",
      "name": "$filter",
      "schema": {
        "type": "string"
      },
      "description": "OData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: \"status eq 'active'\"; \"salary gt 50000 and department eq 'Engineering'\"; \"contains(tolower(name),'acme')\"; \"closeDate gt 2026-01-01\"."
    },
    {
      "in": "query",
      "name": "$select",
      "schema": {
        "type": "string"
      },
      "description": "Comma-separated list of fields to return, e.g. \"id,firstName,email\". Nested fields via slash (\"pto_balance/vacation_days\"). The id field is always included."
    },
    {
      "in": "query",
      "name": "$orderby",
      "schema": {
        "type": "string"
      },
      "description": "Sort clause(s), comma-separated, each \"field [asc|desc]\" (asc is the default). Example: \"createdAt desc, lastName asc\". Null values sort last."
    },
    {
      "in": "query",
      "name": "$search",
      "schema": {
        "type": "string"
      },
      "description": "Free-text, case-insensitive substring match across the resource's searchable fields."
    },
    {
      "in": "query",
      "name": "$top",
      "schema": {
        "type": "integer"
      },
      "description": "Maximum number of items to return (page size)."
    },
    {
      "in": "query",
      "name": "$skip",
      "schema": {
        "type": "integer"
      },
      "description": "Number of matching items to skip before returning results (offset paging). Combine with $top."
    },
    {
      "in": "query",
      "name": "$count",
      "schema": {
        "type": "boolean"
      },
      "description": "When true, include @odata.count (total matches after $filter/$search, before paging) in the response."
    }
  ],
  "responses": {
    "200": {
      "description": "Paginated list",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/HrbpScopeRule"
                }
              },
              "nextCursor": {
                "type": "string",
                "nullable": true,
                "description": "Cursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor."
              },
              "total": {
                "type": "integer",
                "description": "Total documents in the collection."
              },
              "@odata.count": {
                "type": "integer",
                "description": "Present only when $count=true: total matches after $filter/$search."
              },
              "@odata.truncated": {
                "type": "boolean",
                "description": "Present and true only when the collection exceeded the in-memory query cap and results may be incomplete."
              }
            }
          }
        }
      }
    },
    "400": {
      "description": "Invalid OData query (e.g. malformed $filter)"
    }
  }
}

POST /hrbp_scope_rules

Add a membership rule to an HRBP scope

Adds a dimension/value clause to the scope given by scope_id, widening or narrowing who that population covers. SECURITY-SENSITIVE: it changes what data the scope's HRBPs can reach.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Add a membership rule to an HRBP scope",
  "description": "Adds a dimension/value clause to the scope given by scope_id, widening or narrowing who that population covers. SECURITY-SENSITIVE: it changes what data the scope's HRBPs can reach.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/HrbpScopeRule"
        }
      }
    }
  },
  "responses": {
    "201": {
      "description": "Created",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/HrbpScopeRule"
          }
        }
      }
    }
  }
}

GET /hrbp_scope_rules/{id}

Get an HRBP scope rule by id

Returns one membership clause: its parent scope, the dimension it matches on, and the value.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Get an HRBP scope rule by id",
  "description": "Returns one membership clause: its parent scope, the dimension it matches on, and the value.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Found",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/HrbpScopeRule"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

PATCH /hrbp_scope_rules/{id}

Edit an HRBP scope rule

Partial update of a clause's dimension, value or active flag. SECURITY-SENSITIVE - it silently changes the population an HRBP can see.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Edit an HRBP scope rule",
  "description": "Partial update of a clause's dimension, value or active flag. SECURITY-SENSITIVE - it silently changes the population an HRBP can see.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "description": "Fields to update (partial)",
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/HrbpScopeRule"
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Updated",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/HrbpScopeRule"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

DELETE /hrbp_scope_rules/{id}

Delete an HRBP scope rule

DESTRUCTIVE and irreversible: removes a membership clause, shrinking (or, if it was the last exclusion, widening) the parent scope.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Delete an HRBP scope rule",
  "description": "DESTRUCTIVE and irreversible: removes a membership clause, shrinking (or, if it was the last exclusion, widening) the parent scope.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Deleted",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "success": {
                "type": "boolean"
              }
            }
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

GET /snapshot_groups

List snapshot capture batches

A snapshot group is one capture run - a named, timestamped batch (e.g. 'March 2026 workforce snapshot') that the individual snapshot records hang off via group_id. Use this to find which capture runs exist, then read snapshots for the values. Server-side query: $filter/$select/$orderby/$search/$top/$skip/$count (MCP clients pass these as _filter, _top, ... because $ is not a legal tool-input key).

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "List snapshot capture batches",
  "description": "A snapshot group is one capture run - a named, timestamped batch (e.g. 'March 2026 workforce snapshot') that the individual snapshot records hang off via group_id. Use this to find which capture runs exist, then read snapshots for the values. Server-side query: $filter/$select/$orderby/$search/$top/$skip/$count (MCP clients pass these as _filter, _top, ... because $ is not a legal tool-input key).",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "query",
      "name": "limit",
      "schema": {
        "type": "integer",
        "default": 50
      },
      "description": "Legacy page size (default 50). Prefer $top. Ignored when $top/$skip are used."
    },
    {
      "in": "query",
      "name": "cursor",
      "schema": {
        "type": "string"
      },
      "description": "Legacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top."
    },
    {
      "in": "query",
      "name": "$filter",
      "schema": {
        "type": "string"
      },
      "description": "OData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: \"status eq 'active'\"; \"salary gt 50000 and department eq 'Engineering'\"; \"contains(tolower(name),'acme')\"; \"closeDate gt 2026-01-01\"."
    },
    {
      "in": "query",
      "name": "$select",
      "schema": {
        "type": "string"
      },
      "description": "Comma-separated list of fields to return, e.g. \"id,firstName,email\". Nested fields via slash (\"pto_balance/vacation_days\"). The id field is always included."
    },
    {
      "in": "query",
      "name": "$orderby",
      "schema": {
        "type": "string"
      },
      "description": "Sort clause(s), comma-separated, each \"field [asc|desc]\" (asc is the default). Example: \"createdAt desc, lastName asc\". Null values sort last."
    },
    {
      "in": "query",
      "name": "$search",
      "schema": {
        "type": "string"
      },
      "description": "Free-text, case-insensitive substring match across the resource's searchable fields."
    },
    {
      "in": "query",
      "name": "$top",
      "schema": {
        "type": "integer"
      },
      "description": "Maximum number of items to return (page size)."
    },
    {
      "in": "query",
      "name": "$skip",
      "schema": {
        "type": "integer"
      },
      "description": "Number of matching items to skip before returning results (offset paging). Combine with $top."
    },
    {
      "in": "query",
      "name": "$count",
      "schema": {
        "type": "boolean"
      },
      "description": "When true, include @odata.count (total matches after $filter/$search, before paging) in the response."
    }
  ],
  "responses": {
    "200": {
      "description": "Paginated list",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/SnapshotGroup"
                }
              },
              "nextCursor": {
                "type": "string",
                "nullable": true,
                "description": "Cursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor."
              },
              "total": {
                "type": "integer",
                "description": "Total documents in the collection."
              },
              "@odata.count": {
                "type": "integer",
                "description": "Present only when $count=true: total matches after $filter/$search."
              },
              "@odata.truncated": {
                "type": "boolean",
                "description": "Present and true only when the collection exceeded the in-memory query cap and results may be incomplete."
              }
            }
          }
        }
      }
    },
    "400": {
      "description": "Invalid OData query (e.g. malformed $filter)"
    }
  }
}

POST /snapshot_groups

Create a snapshot capture batch

Opens a named, timestamped batch that snapshot records can be filed under. It captures no metrics by itself.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Create a snapshot capture batch",
  "description": "Opens a named, timestamped batch that snapshot records can be filed under. It captures no metrics by itself.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/SnapshotGroup"
        }
      }
    }
  },
  "responses": {
    "201": {
      "description": "Created",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/SnapshotGroup"
          }
        }
      }
    }
  }
}

GET /snapshot_groups/{id}

Get a snapshot capture batch by id

Returns one batch's name, capture timestamp, source and note. The metric values are the snapshots carrying this group_id.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Get a snapshot capture batch by id",
  "description": "Returns one batch's name, capture timestamp, source and note. The metric values are the snapshots carrying this group_id.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Found",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/SnapshotGroup"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

PATCH /snapshot_groups/{id}

Edit a snapshot capture batch

Partial update of a batch's name, note or source. Does not change the snapshot values inside it.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Edit a snapshot capture batch",
  "description": "Partial update of a batch's name, note or source. Does not change the snapshot values inside it.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "description": "Fields to update (partial)",
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/SnapshotGroup"
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Updated",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/SnapshotGroup"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

DELETE /snapshot_groups/{id}

Delete a snapshot capture batch

DESTRUCTIVE and irreversible: removes the batch header. Its snapshots survive but lose their grouping.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Delete a snapshot capture batch",
  "description": "DESTRUCTIVE and irreversible: removes the batch header. Its snapshots survive but lose their grouping.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Deleted",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "success": {
                "type": "boolean"
              }
            }
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

GET /metric_sources

List metric data sources

A metric source is a registered system that talent metrics can be computed from (e.g. 'local' = Purple HRIS). Small reference table: it records where numbers come from, not the numbers themselves. Server-side query: $filter/$select/$orderby/$search/$top/$skip/$count (MCP clients pass these as _filter, _top, ... because $ is not a legal tool-input key).

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "List metric data sources",
  "description": "A metric source is a registered system that talent metrics can be computed from (e.g. 'local' = Purple HRIS). Small reference table: it records where numbers come from, not the numbers themselves. Server-side query: $filter/$select/$orderby/$search/$top/$skip/$count (MCP clients pass these as _filter, _top, ... because $ is not a legal tool-input key).",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "query",
      "name": "limit",
      "schema": {
        "type": "integer",
        "default": 50
      },
      "description": "Legacy page size (default 50). Prefer $top. Ignored when $top/$skip are used."
    },
    {
      "in": "query",
      "name": "cursor",
      "schema": {
        "type": "string"
      },
      "description": "Legacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top."
    },
    {
      "in": "query",
      "name": "$filter",
      "schema": {
        "type": "string"
      },
      "description": "OData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: \"status eq 'active'\"; \"salary gt 50000 and department eq 'Engineering'\"; \"contains(tolower(name),'acme')\"; \"closeDate gt 2026-01-01\"."
    },
    {
      "in": "query",
      "name": "$select",
      "schema": {
        "type": "string"
      },
      "description": "Comma-separated list of fields to return, e.g. \"id,firstName,email\". Nested fields via slash (\"pto_balance/vacation_days\"). The id field is always included."
    },
    {
      "in": "query",
      "name": "$orderby",
      "schema": {
        "type": "string"
      },
      "description": "Sort clause(s), comma-separated, each \"field [asc|desc]\" (asc is the default). Example: \"createdAt desc, lastName asc\". Null values sort last."
    },
    {
      "in": "query",
      "name": "$search",
      "schema": {
        "type": "string"
      },
      "description": "Free-text, case-insensitive substring match across the resource's searchable fields."
    },
    {
      "in": "query",
      "name": "$top",
      "schema": {
        "type": "integer"
      },
      "description": "Maximum number of items to return (page size)."
    },
    {
      "in": "query",
      "name": "$skip",
      "schema": {
        "type": "integer"
      },
      "description": "Number of matching items to skip before returning results (offset paging). Combine with $top."
    },
    {
      "in": "query",
      "name": "$count",
      "schema": {
        "type": "boolean"
      },
      "description": "When true, include @odata.count (total matches after $filter/$search, before paging) in the response."
    }
  ],
  "responses": {
    "200": {
      "description": "Paginated list",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/MetricSource"
                }
              },
              "nextCursor": {
                "type": "string",
                "nullable": true,
                "description": "Cursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor."
              },
              "total": {
                "type": "integer",
                "description": "Total documents in the collection."
              },
              "@odata.count": {
                "type": "integer",
                "description": "Present only when $count=true: total matches after $filter/$search."
              },
              "@odata.truncated": {
                "type": "boolean",
                "description": "Present and true only when the collection exceeded the in-memory query cap and results may be incomplete."
              }
            }
          }
        }
      }
    },
    "400": {
      "description": "Invalid OData query (e.g. malformed $filter)"
    }
  }
}

POST /metric_sources

Register a metric data source

Adds a source system that snapshots and metric computations can attribute to. Administrative configuration.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Register a metric data source",
  "description": "Adds a source system that snapshots and metric computations can attribute to. Administrative configuration.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/MetricSource"
        }
      }
    }
  },
  "responses": {
    "201": {
      "description": "Created",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/MetricSource"
          }
        }
      }
    }
  }
}

GET /metric_sources/{id}

Get a metric data source by id

Returns one registered source: its key, display name and active flag.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Get a metric data source by id",
  "description": "Returns one registered source: its key, display name and active flag.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Found",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/MetricSource"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

PATCH /metric_sources/{id}

Edit a metric data source

Partial update of a source's name, description or active flag.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Edit a metric data source",
  "description": "Partial update of a source's name, description or active flag.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "description": "Fields to update (partial)",
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/MetricSource"
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Updated",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/MetricSource"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

DELETE /metric_sources/{id}

Delete a metric data source

DESTRUCTIVE and irreversible: removes the source registration. Snapshots that referenced it keep the key but it no longer resolves.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Delete a metric data source",
  "description": "DESTRUCTIVE and irreversible: removes the source registration. Snapshots that referenced it keep the key but it no longer resolves.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Deleted",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "success": {
                "type": "boolean"
              }
            }
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

GET /employee_relations

List employee relations (ER) cases

An ER case is an HR investigation or performance-management record about one subject_person: short description, state, priority, the HR rep who opened it and the investigator assigned, due/closed dates, plus PIP fields (start/end, improvement areas, outcome). SENSITIVE HR data, and separate from the talent-review side of this app. Allegations and involved parties are child records keyed by employee_relation_id. Server-side query: $filter/$select/$orderby/$search/$top/$skip/$count (MCP clients pass these as _filter, _top, ... because $ is not a legal tool-input key).

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "List employee relations (ER) cases",
  "description": "An ER case is an HR investigation or performance-management record about one subject_person: short description, state, priority, the HR rep who opened it and the investigator assigned, due/closed dates, plus PIP fields (start/end, improvement areas, outcome). SENSITIVE HR data, and separate from the talent-review side of this app. Allegations and involved parties are child records keyed by employee_relation_id. Server-side query: $filter/$select/$orderby/$search/$top/$skip/$count (MCP clients pass these as _filter, _top, ... because $ is not a legal tool-input key).",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "query",
      "name": "limit",
      "schema": {
        "type": "integer",
        "default": 50
      },
      "description": "Legacy page size (default 50). Prefer $top. Ignored when $top/$skip are used."
    },
    {
      "in": "query",
      "name": "cursor",
      "schema": {
        "type": "string"
      },
      "description": "Legacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top."
    },
    {
      "in": "query",
      "name": "$filter",
      "schema": {
        "type": "string"
      },
      "description": "OData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: \"status eq 'active'\"; \"salary gt 50000 and department eq 'Engineering'\"; \"contains(tolower(name),'acme')\"; \"closeDate gt 2026-01-01\"."
    },
    {
      "in": "query",
      "name": "$select",
      "schema": {
        "type": "string"
      },
      "description": "Comma-separated list of fields to return, e.g. \"id,firstName,email\". Nested fields via slash (\"pto_balance/vacation_days\"). The id field is always included."
    },
    {
      "in": "query",
      "name": "$orderby",
      "schema": {
        "type": "string"
      },
      "description": "Sort clause(s), comma-separated, each \"field [asc|desc]\" (asc is the default). Example: \"createdAt desc, lastName asc\". Null values sort last."
    },
    {
      "in": "query",
      "name": "$search",
      "schema": {
        "type": "string"
      },
      "description": "Free-text, case-insensitive substring match across the resource's searchable fields."
    },
    {
      "in": "query",
      "name": "$top",
      "schema": {
        "type": "integer"
      },
      "description": "Maximum number of items to return (page size)."
    },
    {
      "in": "query",
      "name": "$skip",
      "schema": {
        "type": "integer"
      },
      "description": "Number of matching items to skip before returning results (offset paging). Combine with $top."
    },
    {
      "in": "query",
      "name": "$count",
      "schema": {
        "type": "boolean"
      },
      "description": "When true, include @odata.count (total matches after $filter/$search, before paging) in the response."
    }
  ],
  "responses": {
    "200": {
      "description": "Paginated list",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/EmployeeRelation"
                }
              },
              "nextCursor": {
                "type": "string",
                "nullable": true,
                "description": "Cursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor."
              },
              "total": {
                "type": "integer",
                "description": "Total documents in the collection."
              },
              "@odata.count": {
                "type": "integer",
                "description": "Present only when $count=true: total matches after $filter/$search."
              },
              "@odata.truncated": {
                "type": "boolean",
                "description": "Present and true only when the collection exceeded the in-memory query cap and results may be incomplete."
              }
            }
          }
        }
      }
    },
    "400": {
      "description": "Invalid OData query (e.g. malformed $filter)"
    }
  }
}

POST /employee_relations

Open an employee relations (ER) case

Creates an investigation / performance-management case about an employee. SENSITIVE: it starts a formal HR record about a named person - confirm with the user before calling.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Open an employee relations (ER) case",
  "description": "Creates an investigation / performance-management case about an employee. SENSITIVE: it starts a formal HR record about a named person - confirm with the user before calling.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/EmployeeRelation"
        }
      }
    }
  },
  "responses": {
    "201": {
      "description": "Created",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/EmployeeRelation"
          }
        }
      }
    }
  }
}

GET /employee_relations/{id}

Get an employee relations (ER) case by id

Returns one case with its state, priority, assignment, dates and PIP details. SENSITIVE HR content; a locked case restricts who may read it.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Get an employee relations (ER) case by id",
  "description": "Returns one case with its state, priority, assignment, dates and PIP details. SENSITIVE HR content; a locked case restricts who may read it.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Found",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/EmployeeRelation"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

PATCH /employee_relations/{id}

Edit an employee relations (ER) case

Partial update of a case - reassign the investigator, change state or priority, close it, or record PIP progress and outcome. SENSITIVE HR record.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Edit an employee relations (ER) case",
  "description": "Partial update of a case - reassign the investigator, change state or priority, close it, or record PIP progress and outcome. SENSITIVE HR record.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "description": "Fields to update (partial)",
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/EmployeeRelation"
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Updated",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/EmployeeRelation"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

DELETE /employee_relations/{id}

Delete an employee relations (ER) case

DESTRUCTIVE and irreversible: erases the investigation record and its audit trail, and orphans its allegations and involved parties. Prefer closing the case (state) over deleting it.

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Delete an employee relations (ER) case",
  "description": "DESTRUCTIVE and irreversible: erases the investigation record and its audit trail, and orphans its allegations and involved parties. Prefer closing the case (state) over deleting it.",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Deleted",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "success": {
                "type": "boolean"
              }
            }
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

GET /allegation_types

List allegation types

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "List allegation types",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "query",
      "name": "limit",
      "schema": {
        "type": "integer",
        "default": 50
      },
      "description": "Legacy page size (default 50). Prefer $top. Ignored when $top/$skip are used."
    },
    {
      "in": "query",
      "name": "cursor",
      "schema": {
        "type": "string"
      },
      "description": "Legacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top."
    },
    {
      "in": "query",
      "name": "$filter",
      "schema": {
        "type": "string"
      },
      "description": "OData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: \"status eq 'active'\"; \"salary gt 50000 and department eq 'Engineering'\"; \"contains(tolower(name),'acme')\"; \"closeDate gt 2026-01-01\"."
    },
    {
      "in": "query",
      "name": "$select",
      "schema": {
        "type": "string"
      },
      "description": "Comma-separated list of fields to return, e.g. \"id,firstName,email\". Nested fields via slash (\"pto_balance/vacation_days\"). The id field is always included."
    },
    {
      "in": "query",
      "name": "$orderby",
      "schema": {
        "type": "string"
      },
      "description": "Sort clause(s), comma-separated, each \"field [asc|desc]\" (asc is the default). Example: \"createdAt desc, lastName asc\". Null values sort last."
    },
    {
      "in": "query",
      "name": "$search",
      "schema": {
        "type": "string"
      },
      "description": "Free-text, case-insensitive substring match across the resource's searchable fields."
    },
    {
      "in": "query",
      "name": "$top",
      "schema": {
        "type": "integer"
      },
      "description": "Maximum number of items to return (page size)."
    },
    {
      "in": "query",
      "name": "$skip",
      "schema": {
        "type": "integer"
      },
      "description": "Number of matching items to skip before returning results (offset paging). Combine with $top."
    },
    {
      "in": "query",
      "name": "$count",
      "schema": {
        "type": "boolean"
      },
      "description": "When true, include @odata.count (total matches after $filter/$search, before paging) in the response."
    }
  ],
  "responses": {
    "200": {
      "description": "Paginated list",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/AllegationType"
                }
              },
              "nextCursor": {
                "type": "string",
                "nullable": true,
                "description": "Cursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor."
              },
              "total": {
                "type": "integer",
                "description": "Total documents in the collection."
              },
              "@odata.count": {
                "type": "integer",
                "description": "Present only when $count=true: total matches after $filter/$search."
              },
              "@odata.truncated": {
                "type": "boolean",
                "description": "Present and true only when the collection exceeded the in-memory query cap and results may be incomplete."
              }
            }
          }
        }
      }
    },
    "400": {
      "description": "Invalid OData query (e.g. malformed $filter)"
    }
  }
}

POST /allegation_types

Create allegation type

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Create allegation type",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/AllegationType"
        }
      }
    }
  },
  "responses": {
    "201": {
      "description": "Created",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/AllegationType"
          }
        }
      }
    }
  }
}

GET /allegation_types/{id}

Get allegation type

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Get allegation type",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Found",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/AllegationType"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

PATCH /allegation_types/{id}

Update allegation type

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Update allegation type",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "description": "Fields to update (partial)",
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/AllegationType"
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Updated",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/AllegationType"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

DELETE /allegation_types/{id}

Delete allegation type

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Delete allegation type",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Deleted",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "success": {
                "type": "boolean"
              }
            }
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

GET /allegation_subtypes

List allegation subtypes

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "List allegation subtypes",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "query",
      "name": "limit",
      "schema": {
        "type": "integer",
        "default": 50
      },
      "description": "Legacy page size (default 50). Prefer $top. Ignored when $top/$skip are used."
    },
    {
      "in": "query",
      "name": "cursor",
      "schema": {
        "type": "string"
      },
      "description": "Legacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top."
    },
    {
      "in": "query",
      "name": "$filter",
      "schema": {
        "type": "string"
      },
      "description": "OData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: \"status eq 'active'\"; \"salary gt 50000 and department eq 'Engineering'\"; \"contains(tolower(name),'acme')\"; \"closeDate gt 2026-01-01\"."
    },
    {
      "in": "query",
      "name": "$select",
      "schema": {
        "type": "string"
      },
      "description": "Comma-separated list of fields to return, e.g. \"id,firstName,email\". Nested fields via slash (\"pto_balance/vacation_days\"). The id field is always included."
    },
    {
      "in": "query",
      "name": "$orderby",
      "schema": {
        "type": "string"
      },
      "description": "Sort clause(s), comma-separated, each \"field [asc|desc]\" (asc is the default). Example: \"createdAt desc, lastName asc\". Null values sort last."
    },
    {
      "in": "query",
      "name": "$search",
      "schema": {
        "type": "string"
      },
      "description": "Free-text, case-insensitive substring match across the resource's searchable fields."
    },
    {
      "in": "query",
      "name": "$top",
      "schema": {
        "type": "integer"
      },
      "description": "Maximum number of items to return (page size)."
    },
    {
      "in": "query",
      "name": "$skip",
      "schema": {
        "type": "integer"
      },
      "description": "Number of matching items to skip before returning results (offset paging). Combine with $top."
    },
    {
      "in": "query",
      "name": "$count",
      "schema": {
        "type": "boolean"
      },
      "description": "When true, include @odata.count (total matches after $filter/$search, before paging) in the response."
    }
  ],
  "responses": {
    "200": {
      "description": "Paginated list",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/AllegationSubtype"
                }
              },
              "nextCursor": {
                "type": "string",
                "nullable": true,
                "description": "Cursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor."
              },
              "total": {
                "type": "integer",
                "description": "Total documents in the collection."
              },
              "@odata.count": {
                "type": "integer",
                "description": "Present only when $count=true: total matches after $filter/$search."
              },
              "@odata.truncated": {
                "type": "boolean",
                "description": "Present and true only when the collection exceeded the in-memory query cap and results may be incomplete."
              }
            }
          }
        }
      }
    },
    "400": {
      "description": "Invalid OData query (e.g. malformed $filter)"
    }
  }
}

POST /allegation_subtypes

Create allegation subtype

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Create allegation subtype",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/AllegationSubtype"
        }
      }
    }
  },
  "responses": {
    "201": {
      "description": "Created",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/AllegationSubtype"
          }
        }
      }
    }
  }
}

GET /allegation_subtypes/{id}

Get allegation subtype

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Get allegation subtype",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Found",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/AllegationSubtype"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

PATCH /allegation_subtypes/{id}

Update allegation subtype

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Update allegation subtype",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "description": "Fields to update (partial)",
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/AllegationSubtype"
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Updated",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/AllegationSubtype"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

DELETE /allegation_subtypes/{id}

Delete allegation subtype

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Delete allegation subtype",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Deleted",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "success": {
                "type": "boolean"
              }
            }
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

GET /allegations

List allegations

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "List allegations",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "query",
      "name": "limit",
      "schema": {
        "type": "integer",
        "default": 50
      },
      "description": "Legacy page size (default 50). Prefer $top. Ignored when $top/$skip are used."
    },
    {
      "in": "query",
      "name": "cursor",
      "schema": {
        "type": "string"
      },
      "description": "Legacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top."
    },
    {
      "in": "query",
      "name": "$filter",
      "schema": {
        "type": "string"
      },
      "description": "OData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: \"status eq 'active'\"; \"salary gt 50000 and department eq 'Engineering'\"; \"contains(tolower(name),'acme')\"; \"closeDate gt 2026-01-01\"."
    },
    {
      "in": "query",
      "name": "$select",
      "schema": {
        "type": "string"
      },
      "description": "Comma-separated list of fields to return, e.g. \"id,firstName,email\". Nested fields via slash (\"pto_balance/vacation_days\"). The id field is always included."
    },
    {
      "in": "query",
      "name": "$orderby",
      "schema": {
        "type": "string"
      },
      "description": "Sort clause(s), comma-separated, each \"field [asc|desc]\" (asc is the default). Example: \"createdAt desc, lastName asc\". Null values sort last."
    },
    {
      "in": "query",
      "name": "$search",
      "schema": {
        "type": "string"
      },
      "description": "Free-text, case-insensitive substring match across the resource's searchable fields."
    },
    {
      "in": "query",
      "name": "$top",
      "schema": {
        "type": "integer"
      },
      "description": "Maximum number of items to return (page size)."
    },
    {
      "in": "query",
      "name": "$skip",
      "schema": {
        "type": "integer"
      },
      "description": "Number of matching items to skip before returning results (offset paging). Combine with $top."
    },
    {
      "in": "query",
      "name": "$count",
      "schema": {
        "type": "boolean"
      },
      "description": "When true, include @odata.count (total matches after $filter/$search, before paging) in the response."
    }
  ],
  "responses": {
    "200": {
      "description": "Paginated list",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Allegation"
                }
              },
              "nextCursor": {
                "type": "string",
                "nullable": true,
                "description": "Cursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor."
              },
              "total": {
                "type": "integer",
                "description": "Total documents in the collection."
              },
              "@odata.count": {
                "type": "integer",
                "description": "Present only when $count=true: total matches after $filter/$search."
              },
              "@odata.truncated": {
                "type": "boolean",
                "description": "Present and true only when the collection exceeded the in-memory query cap and results may be incomplete."
              }
            }
          }
        }
      }
    },
    "400": {
      "description": "Invalid OData query (e.g. malformed $filter)"
    }
  }
}

POST /allegations

Create allegation

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Create allegation",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/Allegation"
        }
      }
    }
  },
  "responses": {
    "201": {
      "description": "Created",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Allegation"
          }
        }
      }
    }
  }
}

GET /allegations/{id}

Get allegation

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Get allegation",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Found",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Allegation"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

PATCH /allegations/{id}

Update allegation

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Update allegation",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "description": "Fields to update (partial)",
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/Allegation"
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Updated",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Allegation"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

DELETE /allegations/{id}

Delete allegation

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Delete allegation",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Deleted",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "success": {
                "type": "boolean"
              }
            }
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

GET /involved_parties

List involved parties

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "List involved parties",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "query",
      "name": "limit",
      "schema": {
        "type": "integer",
        "default": 50
      },
      "description": "Legacy page size (default 50). Prefer $top. Ignored when $top/$skip are used."
    },
    {
      "in": "query",
      "name": "cursor",
      "schema": {
        "type": "string"
      },
      "description": "Legacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top."
    },
    {
      "in": "query",
      "name": "$filter",
      "schema": {
        "type": "string"
      },
      "description": "OData filter expression. Comparison operators: eq, ne, gt, ge, lt, le. Logical: and, or, not, with parentheses for grouping. String functions: contains(field,'x'), startswith(field,'x'), endswith(field,'x'). Membership: field in ('a','b'). Case-insensitive matching via tolower(field) / toupper(field). Nested fields use a slash, e.g. pto_balance/vacation_days. String literals use single quotes; dates are ISO-8601. Examples: \"status eq 'active'\"; \"salary gt 50000 and department eq 'Engineering'\"; \"contains(tolower(name),'acme')\"; \"closeDate gt 2026-01-01\"."
    },
    {
      "in": "query",
      "name": "$select",
      "schema": {
        "type": "string"
      },
      "description": "Comma-separated list of fields to return, e.g. \"id,firstName,email\". Nested fields via slash (\"pto_balance/vacation_days\"). The id field is always included."
    },
    {
      "in": "query",
      "name": "$orderby",
      "schema": {
        "type": "string"
      },
      "description": "Sort clause(s), comma-separated, each \"field [asc|desc]\" (asc is the default). Example: \"createdAt desc, lastName asc\". Null values sort last."
    },
    {
      "in": "query",
      "name": "$search",
      "schema": {
        "type": "string"
      },
      "description": "Free-text, case-insensitive substring match across the resource's searchable fields."
    },
    {
      "in": "query",
      "name": "$top",
      "schema": {
        "type": "integer"
      },
      "description": "Maximum number of items to return (page size)."
    },
    {
      "in": "query",
      "name": "$skip",
      "schema": {
        "type": "integer"
      },
      "description": "Number of matching items to skip before returning results (offset paging). Combine with $top."
    },
    {
      "in": "query",
      "name": "$count",
      "schema": {
        "type": "boolean"
      },
      "description": "When true, include @odata.count (total matches after $filter/$search, before paging) in the response."
    }
  ],
  "responses": {
    "200": {
      "description": "Paginated list",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/InvolvedParty"
                }
              },
              "nextCursor": {
                "type": "string",
                "nullable": true,
                "description": "Cursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor."
              },
              "total": {
                "type": "integer",
                "description": "Total documents in the collection."
              },
              "@odata.count": {
                "type": "integer",
                "description": "Present only when $count=true: total matches after $filter/$search."
              },
              "@odata.truncated": {
                "type": "boolean",
                "description": "Present and true only when the collection exceeded the in-memory query cap and results may be incomplete."
              }
            }
          }
        }
      }
    },
    "400": {
      "description": "Invalid OData query (e.g. malformed $filter)"
    }
  }
}

POST /involved_parties

Create involved party

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Create involved party",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/InvolvedParty"
        }
      }
    }
  },
  "responses": {
    "201": {
      "description": "Created",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/InvolvedParty"
          }
        }
      }
    }
  }
}

GET /involved_parties/{id}

Get involved party

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Get involved party",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Found",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/InvolvedParty"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

PATCH /involved_parties/{id}

Update involved party

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Update involved party",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "requestBody": {
    "description": "Fields to update (partial)",
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/InvolvedParty"
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Updated",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/InvolvedParty"
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

DELETE /involved_parties/{id}

Delete involved party

Authentication

[
  {
    "patAuth": []
  }
]

Request, responses and operation details

{
  "summary": "Delete involved party",
  "parameters": [
    {
      "$ref": "#/components/parameters/InstanceId"
    },
    {
      "in": "path",
      "name": "id",
      "required": true,
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "Deleted",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "success": {
                "type": "boolean"
              }
            }
          }
        }
      }
    },
    "404": {
      "description": "Not found"
    }
  }
}

Schemas and reusable components

securitySchemes

patAuth

{
  "type": "http",
  "scheme": "bearer"
}

parameters

InstanceId

{
  "in": "header",
  "name": "X-Instance-ID",
  "required": true,
  "schema": {
    "type": "string"
  }
}

ImpersonateUser

{
  "in": "header",
  "name": "X-PS-Impersonate-User",
  "required": false,
  "schema": {
    "type": "string",
    "format": "email"
  },
  "description": "Optional. Act as a specific user in the target instance — the value is that user's email (must exist in the instance). Resolution order for the effective user: (1) this header, if set; (2) the instance's configured default MCP user; (3) otherwise no user is bound. User-scoped paths (e.g. /users/{email}/…) also accept the literal \"me\", and Graph-style apps serve /me/… twins of those paths (Graph: /me ≡ /users/{signed-in-user}) — both resolve to whatever this header (or the default MCP user) points at. An explicit path email always wins over the header. The unified MCP server does not send this header — it relies on the per-instance default — so it is primarily for direct REST/HTTP callers."
}

schemas

TalentReview

{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "readOnly": true,
      "example": "TR-0001"
    },
    "number": {
      "type": "string",
      "readOnly": true,
      "example": "TR-0000001"
    },
    "name": {
      "type": "string",
      "example": "Q2 Regional Talent Review"
    },
    "state": {
      "type": "string",
      "enum": [
        "in_preparation",
        "scheduled",
        "in_progress",
        "action_plan",
        "closed"
      ],
      "description": "Lifecycle (forward-only; SN label 'In Progress' → 'in_progress').",
      "example": "in_progress"
    },
    "period_start": {
      "type": "string",
      "format": "date",
      "example": "2025-04-01"
    },
    "period_end": {
      "type": "string",
      "format": "date",
      "example": "2025-06-30"
    },
    "leaders": {
      "type": "array",
      "description": "Employee IDs leading this review (SN leaders→sys_user).",
      "items": {
        "type": "string"
      }
    },
    "departments": {
      "type": "array",
      "description": "Department names in scope.",
      "items": {
        "type": "string"
      }
    },
    "locations": {
      "type": "array",
      "description": "Locations in scope.",
      "items": {
        "type": "string"
      }
    },
    "template_id": {
      "type": "string",
      "nullable": true
    },
    "objectives": {
      "type": "string",
      "description": "Review objective(s) (e.g. 'Identify retention risks in high-growth hubs')."
    },
    "metrics": {
      "type": "array",
      "description": "Metrics attached to the review.",
      "items": {
        "type": "object",
        "properties": {
          "metric_id": {
            "type": "string",
            "example": "voluntary_attrition_rate"
          },
          "group_by": {
            "type": "string",
            "nullable": true,
            "example": "department"
          },
          "aggregation": {
            "type": "string",
            "nullable": true,
            "enum": [
              "count",
              "sum",
              "avg"
            ]
          },
          "order": {
            "type": "integer"
          },
          "insights": {
            "type": "string",
            "nullable": true
          }
        }
      }
    },
    "active": {
      "type": "boolean",
      "default": true
    },
    "createdAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    },
    "updatedAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    }
  },
  "required": [
    "name"
  ]
}

EmployeeAssessment

{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "readOnly": true,
      "example": "ASSESS-0001"
    },
    "employee_id": {
      "type": "string",
      "example": "EMP-0001"
    },
    "talent_review_id": {
      "type": "string",
      "nullable": true
    },
    "assessment_date": {
      "type": "string",
      "format": "date"
    },
    "cycle": {
      "type": "string",
      "example": "CY2025"
    },
    "performance_rating": {
      "type": "integer",
      "minimum": 1,
      "maximum": 5,
      "description": "1–5 (SN current_performance_level 10–50 / current_rating 30/40/50)."
    },
    "performance_band": {
      "type": "string",
      "enum": [
        "excellent",
        "good",
        "average",
        "needs_improvement",
        "poor"
      ],
      "description": "Derived band (excellent/good/average/needs_improvement/poor)."
    },
    "potential": {
      "type": "string",
      "enum": [
        "low",
        "medium",
        "high"
      ],
      "description": "SN 10/20/30 or High/Medium/Low."
    },
    "achievable_level": {
      "type": "string",
      "enum": [
        "1",
        "2",
        "3"
      ],
      "description": "SN 10/20/30 or '1/2/3 Levels'."
    },
    "flight_risk": {
      "type": "string",
      "enum": [
        "low",
        "medium",
        "high"
      ],
      "description": "Stored (not derived) per SN assessment."
    },
    "replacement_readiness": {
      "type": "string",
      "enum": [
        "immediate",
        "3m",
        "6m",
        "12m"
      ],
      "description": "SN 0/3/6/12."
    },
    "box": {
      "type": "integer",
      "minimum": 1,
      "maximum": 9,
      "readOnly": true,
      "description": "Derived 9-box cell (potential × performance)."
    },
    "core_competencies": {
      "type": "string",
      "nullable": true
    },
    "development_needs": {
      "type": "string",
      "nullable": true
    },
    "createdAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    },
    "updatedAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    }
  },
  "required": [
    "employee_id"
  ]
}

PerformanceReview

{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "readOnly": true,
      "example": "PR-0001"
    },
    "employee_id": {
      "type": "string",
      "example": "EMP-0001"
    },
    "review_start_date": {
      "type": "string",
      "format": "date"
    },
    "review_end_date": {
      "type": "string",
      "format": "date"
    },
    "rating_manager": {
      "type": "number",
      "minimum": 1,
      "maximum": 5,
      "example": 4.2
    },
    "rating_employee": {
      "type": "number",
      "minimum": 1,
      "maximum": 5,
      "example": 4
    },
    "assessed_on": {
      "type": "string",
      "format": "date-time"
    },
    "createdAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    },
    "updatedAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    }
  },
  "required": [
    "employee_id"
  ]
}

SuccessionPlan

{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "readOnly": true,
      "example": "SP-0001"
    },
    "number": {
      "type": "string",
      "readOnly": true,
      "example": "SP-0000001"
    },
    "title": {
      "type": "string",
      "example": "Principal Product Manager"
    },
    "incumbent_employee_id": {
      "type": "string",
      "nullable": true,
      "example": "EMP-0001"
    },
    "job_title": {
      "type": "string",
      "nullable": true
    },
    "department": {
      "type": "string",
      "nullable": true
    },
    "planned_retirement_date": {
      "type": "string",
      "format": "date",
      "nullable": true
    },
    "criticality": {
      "type": "string",
      "enum": [
        "low",
        "medium",
        "high"
      ],
      "description": "SN demo low/medium/high."
    },
    "loss_impact": {
      "type": "string",
      "enum": [
        "low",
        "medium",
        "high"
      ],
      "description": "SN High/Intermediate→medium/Low."
    },
    "retention_risk": {
      "type": "string",
      "enum": [
        "low",
        "medium",
        "high"
      ]
    },
    "success_profile": {
      "type": "object",
      "nullable": true,
      "description": "Role mission/skills/qualifications (SN JSON)."
    },
    "successor_count": {
      "type": "integer",
      "readOnly": true
    },
    "external_id": {
      "type": "string",
      "nullable": true
    },
    "active": {
      "type": "boolean",
      "default": true
    },
    "createdAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    },
    "updatedAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    }
  },
  "required": [
    "title"
  ]
}

Successor

{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "readOnly": true,
      "example": "SUC-0001"
    },
    "succession_plan_id": {
      "type": "string",
      "example": "SP-0001"
    },
    "candidate_employee_id": {
      "type": "string",
      "example": "EMP-0002"
    },
    "top_candidate": {
      "type": "boolean"
    },
    "readiness": {
      "type": "string",
      "enum": [
        "immediate",
        "3m",
        "6m",
        "12m"
      ],
      "description": "SN 0/3/6/12 or 'Ready in …' (9 months→6m)."
    },
    "potential": {
      "type": "string",
      "enum": [
        "low",
        "medium",
        "high"
      ]
    },
    "achievable_level": {
      "type": "string",
      "enum": [
        "1",
        "2",
        "3"
      ]
    },
    "current_rating": {
      "type": "string",
      "enum": [
        "excellent",
        "good",
        "average",
        "needs_improvement",
        "poor"
      ],
      "description": "Banded (SN '4 - Exceeds Expectations')."
    },
    "education": {
      "type": "string",
      "nullable": true
    },
    "skills": {
      "type": "string",
      "nullable": true,
      "description": "Comma-separated."
    },
    "job_history_companies": {
      "type": "string",
      "nullable": true
    },
    "promotion_readiness": {
      "type": "string",
      "nullable": true
    },
    "development_areas": {
      "type": "string",
      "nullable": true
    },
    "matching_score": {
      "type": "integer",
      "minimum": 0,
      "maximum": 100,
      "nullable": true
    },
    "candidate_profile": {
      "type": "object",
      "nullable": true,
      "description": "Per-dimension match scores (SN JSON)."
    },
    "temporary_fill": {
      "type": "boolean",
      "nullable": true
    },
    "createdAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    },
    "updatedAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    }
  },
  "required": [
    "succession_plan_id",
    "candidate_employee_id"
  ]
}

Snapshot

{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "readOnly": true,
      "example": "SNP-0001"
    },
    "metric_id": {
      "type": "string",
      "example": "headcount"
    },
    "group_id": {
      "type": "string",
      "nullable": true,
      "description": "Batch grouping key."
    },
    "source": {
      "type": "string",
      "enum": [
        "local",
        "workday",
        "successfactors",
        "oracle"
      ],
      "default": "local"
    },
    "value": {
      "type": "object",
      "description": "Computed metric value as JSON (per group)."
    },
    "timestamp": {
      "type": "string",
      "format": "date-time"
    },
    "createdAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    },
    "updatedAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    }
  },
  "required": [
    "metric_id",
    "value"
  ]
}

MetricGoal

{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "readOnly": true,
      "example": "GOAL-0001"
    },
    "name": {
      "type": "string",
      "example": "Attrition Rate Goal 2026"
    },
    "talent_review_id": {
      "type": "string",
      "nullable": true
    },
    "metric_id": {
      "type": "string",
      "example": "attrition_rate"
    },
    "period_start": {
      "type": "string",
      "format": "date"
    },
    "period_end": {
      "type": "string",
      "format": "date"
    },
    "threshold_value": {
      "type": "number",
      "example": 3
    },
    "comparison_type": {
      "type": "string",
      "enum": [
        "gt",
        "lt",
        "eq",
        "lte",
        "gte"
      ],
      "example": "lte"
    },
    "active": {
      "type": "boolean",
      "default": true
    },
    "createdAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    },
    "updatedAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    }
  },
  "required": [
    "metric_id"
  ]
}

HrbpScopeAssignment

{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "readOnly": true,
      "example": "SCOPE-0001"
    },
    "user": {
      "type": "string",
      "description": "User (email/employee id) this scope grants visibility to.",
      "example": "sofia.rossi@acme.com"
    },
    "scope_type": {
      "type": "string",
      "enum": [
        "hrbp",
        "metric_threshold"
      ],
      "default": "hrbp"
    },
    "scope_id": {
      "type": "string",
      "nullable": true,
      "description": "Optional link to an HrbpScope (normalized scope definition).",
      "example": "HSCOPE-RND"
    },
    "all_access": {
      "type": "boolean",
      "default": false,
      "description": "Unrestricted (admin-equivalent) scope — request passes through verbatim."
    },
    "leaders": {
      "type": "array",
      "description": "Leader employee IDs in scope.",
      "items": {
        "type": "string"
      }
    },
    "departments": {
      "type": "array",
      "description": "Departments in scope.",
      "items": {
        "type": "string"
      }
    },
    "locations": {
      "type": "array",
      "description": "Hierarchical geo scope: region / country / city tokens (a region token covers all its countries & cities).",
      "items": {
        "type": "string"
      }
    },
    "active": {
      "type": "boolean",
      "default": true
    },
    "createdAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    },
    "updatedAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    }
  },
  "required": [
    "user"
  ]
}

HrbpScope

{
  "type": "object",
  "description": "Named HRBP scope (SN sn_talent_pulse_hrbp_scope). Composed of HrbpScopeRule rows; assignments reference it by scope_id.",
  "properties": {
    "id": {
      "type": "string",
      "readOnly": true,
      "example": "HSCOPE-RND"
    },
    "name": {
      "type": "string",
      "example": "R&D — AMS"
    },
    "description": {
      "type": "string",
      "nullable": true
    },
    "active": {
      "type": "boolean",
      "default": true
    },
    "createdAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    },
    "updatedAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    }
  },
  "required": [
    "name"
  ]
}

HrbpScopeRule

{
  "type": "object",
  "description": "A single dimension rule within an HrbpScope (SN sn_talent_pulse_hrbp_scope_rule).",
  "properties": {
    "id": {
      "type": "string",
      "readOnly": true,
      "example": "HRULE-0001"
    },
    "scope_id": {
      "type": "string",
      "description": "Parent HrbpScope id.",
      "example": "HSCOPE-RND"
    },
    "dimension": {
      "type": "string",
      "enum": [
        "leader",
        "department",
        "location",
        "region",
        "country",
        "city",
        "all_access"
      ],
      "description": "Geo dimensions (location/region/country/city) all feed the hierarchical location scope.",
      "example": "region"
    },
    "value": {
      "type": "string",
      "nullable": true,
      "description": "The in-scope value for the dimension (null for all_access). Geo values may be a region (AMS), country (USA), or city (New York, NY).",
      "example": "AMS"
    },
    "active": {
      "type": "boolean",
      "default": true
    },
    "createdAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    },
    "updatedAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    }
  },
  "required": [
    "scope_id",
    "dimension"
  ]
}

SnapshotGroup

{
  "type": "object",
  "description": "Groups related metric snapshots captured in one run (SN sn_talent_pulse_snapshot_group).",
  "properties": {
    "id": {
      "type": "string",
      "readOnly": true,
      "example": "SGRP-0001"
    },
    "name": {
      "type": "string",
      "example": "March 2026 workforce snapshot"
    },
    "captured_at": {
      "type": "string",
      "format": "date-time"
    },
    "source": {
      "type": "string",
      "enum": [
        "local",
        "workday",
        "successfactors",
        "oracle"
      ],
      "default": "local"
    },
    "note": {
      "type": "string",
      "nullable": true
    },
    "createdAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    },
    "updatedAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    }
  },
  "required": [
    "name"
  ]
}

MetricSource

{
  "type": "object",
  "description": "A system a metric value can originate from (SN sn_talent_pulse_metric_source).",
  "properties": {
    "id": {
      "type": "string",
      "readOnly": true,
      "example": "MSRC-local"
    },
    "key": {
      "type": "string",
      "enum": [
        "local",
        "workday",
        "successfactors",
        "oracle"
      ],
      "example": "local"
    },
    "name": {
      "type": "string",
      "example": "Purple HRIS (local)"
    },
    "description": {
      "type": "string",
      "nullable": true
    },
    "active": {
      "type": "boolean",
      "default": true
    },
    "createdAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    },
    "updatedAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    }
  },
  "required": [
    "key",
    "name"
  ]
}

EmployeeRelation

{
  "type": "object",
  "description": "Employee Relations case (SN sn_hr_er_case, extends sn_hr_core_case).",
  "properties": {
    "id": {
      "type": "string",
      "readOnly": true,
      "example": "ERC-0001"
    },
    "number": {
      "type": "string",
      "readOnly": true,
      "example": "ERC-0000001"
    },
    "subject_person": {
      "type": "string",
      "description": "Employee ID the case concerns.",
      "example": "EMP-0003"
    },
    "short_description": {
      "type": "string",
      "example": "Complaint of workplace harassment"
    },
    "description": {
      "type": "string",
      "nullable": true
    },
    "state": {
      "type": "string",
      "enum": [
        "open",
        "work_in_progress",
        "awaiting_info",
        "resolved",
        "closed",
        "cancelled"
      ],
      "default": "open"
    },
    "priority": {
      "type": "string",
      "enum": [
        "low",
        "moderate",
        "high",
        "critical"
      ],
      "description": "SN 1-Critical/2-High/3-Moderate/4-Low.",
      "default": "moderate"
    },
    "opened_by": {
      "type": "string",
      "nullable": true,
      "description": "Employee ID of the HR rep who opened the case."
    },
    "assigned_to": {
      "type": "string",
      "nullable": true,
      "description": "Employee ID of the assigned HR investigator."
    },
    "hr_service": {
      "type": "string",
      "default": "Employee Relations"
    },
    "opened_at": {
      "type": "string",
      "format": "date-time"
    },
    "due_date": {
      "type": "string",
      "format": "date",
      "nullable": true
    },
    "closed_at": {
      "type": "string",
      "format": "date-time",
      "nullable": true
    },
    "active": {
      "type": "boolean",
      "default": true
    },
    "incident_date": {
      "type": "string",
      "format": "date",
      "nullable": true,
      "description": "Date of most recent incident."
    },
    "external_opened_for": {
      "type": "boolean",
      "default": false,
      "description": "Opened for is not a User."
    },
    "locked": {
      "type": "boolean",
      "default": false,
      "description": "Restricting access limits who can view/edit the case."
    },
    "preferred_contact_method": {
      "type": "string",
      "enum": [
        "not_specified",
        "personal_phone",
        "work_phone",
        "personal_email",
        "work_email"
      ],
      "default": "not_specified"
    },
    "reported_date": {
      "type": "string",
      "format": "date-time",
      "nullable": true
    },
    "pip_start_date": {
      "type": "string",
      "format": "date",
      "nullable": true
    },
    "pip_end_date": {
      "type": "string",
      "format": "date",
      "nullable": true
    },
    "pip_improvement_areas": {
      "type": "string",
      "nullable": true
    },
    "pip_rationale": {
      "type": "string",
      "nullable": true
    },
    "pip_successful": {
      "type": "string",
      "enum": [
        "y",
        "n"
      ],
      "nullable": true
    },
    "pip_extended": {
      "type": "string",
      "enum": [
        "y",
        "n"
      ],
      "nullable": true
    },
    "pip_extension_date": {
      "type": "string",
      "format": "date",
      "nullable": true
    },
    "createdAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    },
    "updatedAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    }
  },
  "required": [
    "subject_person",
    "short_description"
  ]
}

AllegationType

{
  "type": "object",
  "description": "Allegation type reference catalog (SN sn_hr_er_allegation_type).",
  "properties": {
    "id": {
      "type": "string",
      "readOnly": true,
      "example": "AT-HARASSMENT"
    },
    "name": {
      "type": "string",
      "example": "Harassment"
    },
    "description": {
      "type": "string",
      "nullable": true
    },
    "active": {
      "type": "boolean",
      "default": true
    },
    "createdAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    },
    "updatedAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    }
  },
  "required": [
    "name"
  ]
}

AllegationSubtype

{
  "type": "object",
  "description": "Allegation subtype, dependent on allegation_type (SN sn_hr_er_allegation_subtype).",
  "properties": {
    "id": {
      "type": "string",
      "readOnly": true,
      "example": "AST-VERBAL"
    },
    "allegation_type_id": {
      "type": "string",
      "example": "AT-HARASSMENT"
    },
    "name": {
      "type": "string",
      "example": "Verbal harassment"
    },
    "active": {
      "type": "boolean",
      "default": true
    },
    "createdAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    },
    "updatedAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    }
  },
  "required": [
    "allegation_type_id",
    "name"
  ]
}

Allegation

{
  "type": "object",
  "description": "One allegation filed on an ER case (SN sn_hr_er_allegation).",
  "properties": {
    "id": {
      "type": "string",
      "readOnly": true,
      "example": "ALG-0001"
    },
    "employee_relation_id": {
      "type": "string",
      "example": "ERC-0001"
    },
    "allegation_type_id": {
      "type": "string",
      "example": "AT-HARASSMENT"
    },
    "allegation_subtype_id": {
      "type": "string",
      "example": "AST-VERBAL"
    },
    "description": {
      "type": "string",
      "nullable": true
    },
    "subjects_of_allegation": {
      "type": "string",
      "readOnly": true,
      "nullable": true,
      "description": "Derived: names of the case's 'respondent' involved parties."
    },
    "createdAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    },
    "updatedAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    }
  },
  "required": [
    "employee_relation_id",
    "allegation_type_id",
    "allegation_subtype_id"
  ]
}

InvolvedParty

{
  "type": "object",
  "description": "A complainant, respondent, witness, or other party on an ER case (SN sn_hr_er_involved_party).",
  "properties": {
    "id": {
      "type": "string",
      "readOnly": true,
      "example": "IP-0001"
    },
    "employee_relation_id": {
      "type": "string",
      "example": "ERC-0001"
    },
    "employee_id": {
      "type": "string",
      "nullable": true,
      "description": "Employee ID, if the party has a User record.",
      "example": "EMP-0008"
    },
    "not_in_system": {
      "type": "boolean",
      "default": false,
      "description": "Involved party does not have a User record."
    },
    "name": {
      "type": "string",
      "nullable": true,
      "description": "Name/description, used when not_in_system (or no employee_id)."
    },
    "display_name": {
      "type": "string",
      "readOnly": true,
      "description": "Derived: the linked employee's name, else name."
    },
    "type": {
      "type": "string",
      "enum": [
        "complainant",
        "respondent",
        "witness",
        "other"
      ],
      "default": "other"
    },
    "correlation_id": {
      "type": "string",
      "nullable": true
    },
    "createdAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    },
    "updatedAt": {
      "type": "string",
      "format": "date-time",
      "readOnly": true
    }
  },
  "required": [
    "employee_relation_id",
    "type"
  ]
}

Document metadata and extensions

{
  "openapi": "3.0.0",
  "info": {
    "title": "Purple Suite HRBP API",
    "description": "HR Business Partner (HRBP) source system — Talent Insights & Talent Review, and Employee Relations case management. Data layer for talent reviews, 9-box employee assessments, performance reviews, succession planning, metric snapshots, and ER cases/allegations/involved parties (SN sn_hr_er_* parity). ServiceNow-parity contract endpoints (resolve_filters, available_metrics, preview_review/commit_review, query) and the tp_* MCP tools are served alongside these collections. References employees in the Purple HRS (HRIS) app by employee_id. Choice fields use a readable canonical value; the originating ServiceNow code is noted in each field description.\n\n---\n\n**Acting as a user (`X-PS-Impersonate-User`).** Every endpoint accepts an optional `X-PS-Impersonate-User` request header whose value is the email of the instance user to act as. The effective user resolves in this order: the header if present, else the instance's configured default MCP user, else none. User-scoped paths additionally accept the literal `me` in place of an email, and Graph-style apps also serve `/me/…` twins of their `/users/{email}/…` paths that resolve the same way. This header is honored by all operations but is intentionally omitted from each operation's parameter list so it is not surfaced as a per-tool argument by MCP clients; see the `ImpersonateUser` entry under `components.parameters`.",
    "version": "1.0.0"
  },
  "security": [
    {
      "patAuth": []
    }
  ]
}
Interactive API explorer (requires JavaScript)