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`.
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`.
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"
}
}
}