{"openapi":"3.0.0","info":{"title":"Purple Suite ITSM API","version":"1.0.0","description":"\n\n---\n\n**Acting as a user (`X-PS-Impersonate-User`).** Every endpoint accepts an optional `X-PS-Impersonate-User` request header whose value is the email of the instance user to act as. The effective user resolves in this order: the header if present, else the instance's configured default MCP user, else none. User-scoped paths additionally accept the literal `me` in place of an email, and Graph-style apps also serve `/me/…` twins of their `/users/{email}/…` paths that resolve the same way. This header is honored by all operations but is intentionally omitted from each operation's parameter list so it is not surfaced as a per-tool argument by MCP clients; see the `ImpersonateUser` entry under `components.parameters`."},"servers":[{"url":"https://marketplace.moveworks.com/api/purple-suite/itsm"}],"security":[{"patAuth":[]}],"components":{"securitySchemes":{"patAuth":{"type":"http","scheme":"bearer"}},"parameters":{"InstanceId":{"in":"header","name":"X-Instance-ID","required":true,"schema":{"type":"string"}},"ImpersonateUser":{"in":"header","name":"X-PS-Impersonate-User","required":false,"schema":{"type":"string","format":"email"},"description":"Optional. Act as a specific user in the target instance — the value is that user's email (must exist in the instance). Resolution order for the effective user: (1) this header, if set; (2) the instance's configured default MCP user; (3) otherwise no user is bound. User-scoped paths (e.g. /users/{email}/…) also accept the literal \"me\", and Graph-style apps serve /me/… twins of those paths (Graph: /me ≡ /users/{signed-in-user}) — both resolve to whatever this header (or the default MCP user) points at. An explicit path email always wins over the header. The unified MCP server does not send this header — it relies on the per-instance default — so it is primarily for direct REST/HTTP callers."}},"schemas":{"Incident":{"type":"object","properties":{"id":{"type":"string","readOnly":true,"example":"INC-0001"},"title":{"type":"string","example":"VPN issue - Engineering"},"status":{"type":"string","enum":["open","in_progress","resolved","closed","cancelled"],"example":"open"},"priority":{"type":"string","enum":["P1","P2","P3","P4"],"example":"P2"},"category":{"type":"string","enum":["hardware","software","network","access","other"],"example":"network"},"assignee":{"type":"string","format":"email","example":"alice@acme.com"},"reporter":{"type":"string","format":"email","example":"user1@acme.com"},"escalation_tier":{"type":"integer","minimum":1,"maximum":3,"example":1},"escalated_at":{"type":"string","format":"date-time","readOnly":true},"escalation_notes":{"type":"string","example":"Escalated due to customer impact"},"reopen_reason":{"type":"string","example":"Issue recurred after resolution"},"createdAt":{"type":"string","format":"date-time","readOnly":true},"updatedAt":{"type":"string","format":"date-time","readOnly":true}}},"Change":{"type":"object","properties":{"id":{"type":"string","readOnly":true,"example":"CHG-0001"},"title":{"type":"string","example":"OS upgrade"},"status":{"type":"string","enum":["draft","pending_approval","approved","in_progress","implemented","completed","rejected","cancelled"],"example":"draft"},"riskLevel":{"type":"string","enum":["low","medium","high"],"example":"medium"},"scheduledDate":{"type":"string","format":"date-time","example":"2026-06-15T00:00:00.000Z"},"approver":{"type":"string","format":"email","example":"manager1@acme.com"},"cab_approval":{"type":"object","readOnly":true,"properties":{"approved_by":{"type":"string"},"approved_at":{"type":"string","format":"date-time"},"rejected_by":{"type":"string"},"reason":{"type":"string"}}},"createdAt":{"type":"string","format":"date-time","readOnly":true},"updatedAt":{"type":"string","format":"date-time","readOnly":true}}},"SlaPolicy":{"type":"object","properties":{"id":{"type":"string","readOnly":true,"example":"SLA-001"},"name":{"type":"string","example":"Critical Incident SLA"},"responseTimeHours":{"type":"number","example":1},"resolutionTimeHours":{"type":"number","example":4},"priority":{"type":"string","enum":["P1","P2","P3","P4"],"example":"P1"},"active":{"type":"boolean","example":true},"paused":{"type":"boolean","example":false},"createdAt":{"type":"string","format":"date-time","readOnly":true},"updatedAt":{"type":"string","format":"date-time","readOnly":true}}},"Problem":{"type":"object","properties":{"id":{"type":"string","readOnly":true,"example":"PRB-0001"},"title":{"type":"string","example":"Recurring login failures"},"status":{"type":"string","enum":["open","known_error","resolved"],"example":"open"},"rootCause":{"type":"string","enum":["Unknown","Configuration error","Software bug","Infrastructure issue","Third-party dependency"],"example":"Unknown"},"createdAt":{"type":"string","format":"date-time","readOnly":true},"updatedAt":{"type":"string","format":"date-time","readOnly":true}}},"ServiceRequest":{"type":"object","properties":{"id":{"type":"string","readOnly":true,"example":"SR-0001"},"title":{"type":"string","example":"New laptop request"},"status":{"type":"string","enum":["submitted","approved","in_progress","completed","cancelled"],"example":"submitted"},"requestedBy":{"type":"string","format":"email","example":"user1@acme.com"},"fulfillmentGroup":{"type":"string","enum":["IT Support","Security","Procurement","Facilities"],"example":"IT Support"},"createdAt":{"type":"string","format":"date-time","readOnly":true},"updatedAt":{"type":"string","format":"date-time","readOnly":true}}},"ConfigurationItem":{"type":"object","properties":{"id":{"type":"string","readOnly":true,"example":"CI-a1b2c3d4"},"name":{"type":"string","example":"web-server-01"},"type":{"type":"string","enum":["server","workstation","network_device","application","database","storage"],"example":"server"},"status":{"type":"string","enum":["operational","maintenance","retired","ordered"],"example":"operational"},"environment":{"type":"string","enum":["production","staging","development","dr"],"example":"production"},"owner":{"type":"string","enum":["IT Ops","Engineering","Security"],"example":"IT Ops"},"createdAt":{"type":"string","format":"date-time","readOnly":true},"updatedAt":{"type":"string","format":"date-time","readOnly":true}}},"KbArticle":{"type":"object","properties":{"id":{"type":"string","readOnly":true,"example":"KB-0001"},"title":{"type":"string","example":"How to reset your password"},"category":{"type":"string","enum":["Authentication","Network","Hardware","Software","Security","Onboarding"],"example":"Authentication"},"views":{"type":"integer","example":150},"helpful":{"type":"integer","example":42},"author":{"type":"string","format":"email","example":"alice@acme.com"},"publishedAt":{"type":"string","format":"date-time","example":"2026-01-10T00:00:00.000Z"},"createdAt":{"type":"string","format":"date-time","readOnly":true},"updatedAt":{"type":"string","format":"date-time","readOnly":true}}},"Alert":{"type":"object","properties":{"id":{"type":"string","readOnly":true,"example":"ALT-0001"},"title":{"type":"string","example":"High CPU usage detected"},"severity":{"type":"string","enum":["critical","warning","info"],"example":"warning"},"source":{"type":"string","enum":["Nagios","Datadog","PagerDuty","CloudWatch","Prometheus"],"example":"Datadog"},"status":{"type":"string","enum":["active","acknowledged","resolved"],"example":"active"},"triggeredAt":{"type":"string","format":"date-time","example":"2026-05-29T08:00:00.000Z"},"resolvedAt":{"type":"string","format":"date-time","nullable":true,"example":null},"createdAt":{"type":"string","format":"date-time","readOnly":true},"updatedAt":{"type":"string","format":"date-time","readOnly":true}}}}},"paths":{"/incidents":{"get":{"summary":"List IT incidents (unplanned break/fix tickets)","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/Incident"}},"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)"}},"description":"Incidents in Purple ITSM (a ServiceNow-style IT service desk) are unplanned disruptions someone reported — VPN down, laptop broken — with status (open | in_progress | resolved | closed | cancelled), priority P1–P4, category, assignee, reporter and escalation_tier. Distinct from service requests (asking for something), problems (root cause behind repeat incidents) and alerts (raised by monitoring). Supports server-side OData querying — $filter, $search, $orderby, $select, $top, $skip, $count (MCP clients see these as _filter, _search, _orderby, _select, _top, _skip, _count because $ is not a legal tool-input key). Example: $filter=status eq 'open' and priority eq 'P1'&$orderby=createdAt desc."},"post":{"summary":"Open a new IT incident ticket","parameters":[{"$ref":"#/components/parameters/InstanceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Incident"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Incident"}}}}},"description":"Files an incident on the IT service desk — title, priority (P1–P4), category (hardware/software/network/access/other), reporter and assignee. Use this when something is broken; if the user is asking to be GIVEN something (laptop, access, software) create a service request instead."}},"/incidents/{id}":{"get":{"summary":"Get one IT incident by ticket number","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/Incident"}}}},"404":{"description":"Not found"}},"description":"Fetches a single incident by id (e.g. INC-0001) with its current status, priority, assignee, escalation tier and timestamps. Use it to answer 'what's the status of my ticket'; search by other fields with itsm__list__incidents."},"patch":{"summary":"Update an IT incident (reassign, reprioritise, resolve)","description":"The general-purpose incident write: change assignee, priority, category, notes or status. State-machine rules are enforced — valid statuses are open | in_progress | resolved | closed | cancelled; an open incident must pass through in_progress before it can be closed; and reopening a resolved/closed incident requires reopen_reason in the body. To raise the escalation tier use itsm__escalate__incidents, which is the only way that counter moves.","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/Incident"}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Incident"}}}},"404":{"description":"Not found"}}},"delete":{"summary":"Delete an IT incident record","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"}},"description":"DESTRUCTIVE and irreversible: erases the incident and its history from the service desk entirely. This is not how tickets are normally finished — to end a ticket set its status to resolved/closed/cancelled with itsm__update__incidents; delete only for records created in error."}},"/incidents/{id}/escalate":{"post":{"summary":"Escalate an incident to the next support tier","description":"The only way the escalation counter moves: bumps the incident's escalation_tier by 1 (tier 3 is the ceiling — a further call returns 400), stamps escalated_at and stores optional escalation_notes. Use it when a ticket needs senior/urgent attention; use itsm__update__incidents to merely change priority, assignee or status. Fails with 422 on a resolved or closed incident.","parameters":[{"$ref":"#/components/parameters/InstanceId"},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"escalation_notes":{"type":"string","example":"Customer impact escalating; looping in senior support"}}}}}},"responses":{"200":{"description":"Updated incident after escalation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Incident"}}}},"400":{"description":"Incident already at maximum escalation tier (3)"},"404":{"description":"Not found"},"422":{"description":"Cannot escalate a resolved or closed incident"}}}},"/changes":{"get":{"summary":"List change requests (planned IT changes)","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/Change"}},"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)"}},"description":"A Change is a PLANNED modification to the IT estate going through change management — OS upgrade, firewall rule, release — with status (draft | pending_approval | approved | in_progress | implemented | completed | rejected | cancelled), riskLevel, scheduledDate, approver and a cab_approval record. Contrast with incidents, which are unplanned breakages. Supports server-side OData querying — $filter, $search, $orderby, $select, $top, $skip, $count (MCP clients see these as _filter, _search, _orderby, _select, _top, _skip, _count because $ is not a legal tool-input key). Example: $filter=status eq 'pending_approval' and riskLevel eq 'high'."},"post":{"summary":"Raise a change request","parameters":[{"$ref":"#/components/parameters/InstanceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Change"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Change"}}}}},"description":"Creates a change request for planned work — title, riskLevel, scheduledDate and approver — normally starting in draft or pending_approval. Approval itself is not granted here: that happens through itsm__cab_approve__changes."}},"/changes/{id}":{"get":{"summary":"Get one change request","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/Change"}}}},"404":{"description":"Not found"}},"description":"Fetches a single change by id (e.g. CHG-0001) with its status, risk, schedule and the cab_approval block recording who approved or rejected it and why."},"patch":{"summary":"Update a change request's details or status","description":"Edits change fields — title, riskLevel, scheduledDate, approver — and moves it through non-approval statuses such as in_progress, implemented, completed or cancelled. Do NOT use this to approve or reject: itsm__cab_approve__changes and itsm__cab_reject__changes are the CAB decisions and they also write the auditable cab_approval 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/Change"}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Change"}}}},"404":{"description":"Not found"}}},"delete":{"summary":"Delete a change request","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"}},"description":"DESTRUCTIVE and irreversible: removes the change request and its CAB approval trail. To call off planned work while keeping the audit history, set status to 'cancelled' with itsm__update__changes instead."}},"/changes/{id}/cab-approve":{"post":{"summary":"Approve a change at the Change Advisory Board","description":"Records the formal CAB decision to approve planned work: writes approved_by/approved_at into the change's auditable cab_approval block and sets status to 'approved'. This is the governance action — do not simulate it by patching status with itsm__update__changes, which leaves no approval record. Fails with 422 if the change is already approved, rejected or cancelled.","parameters":[{"$ref":"#/components/parameters/InstanceId"},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"approved_by":{"type":"string","example":"manager1@acme.com"}},"required":["approved_by"]}}}},"responses":{"200":{"description":"Updated change after CAB approval","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Change"}}}},"404":{"description":"Not found"},"422":{"description":"Change cannot be approved in its current state"}}}},"/changes/{id}/cab-reject":{"post":{"summary":"Reject a change at the Change Advisory Board","description":"Records the formal CAB decision to refuse planned work: requires rejected_by and a reason, writes them into the change's cab_approval block and sets status to 'rejected'. The counterpart to itsm__cab_approve__changes; prefer it over patching status directly so the refusal is auditable. Fails with 422 if the change is already rejected or implemented.","parameters":[{"$ref":"#/components/parameters/InstanceId"},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rejected_by":{"type":"string","example":"manager2@acme.com"},"reason":{"type":"string","example":"Insufficient testing evidence provided"}},"required":["rejected_by","reason"]}}}},"responses":{"200":{"description":"Updated change after CAB rejection","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Change"}}}},"404":{"description":"Not found"},"422":{"description":"Change cannot be rejected in its current state"}}}},"/sla_policies":{"get":{"summary":"List SLA policies (response/resolution targets)","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/SlaPolicy"}},"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)"}},"description":"SLA policies are the service-desk's configured time targets, not tickets: each names a priority (P1–P4) with responseTimeHours and resolutionTimeHours, plus active and paused flags. Use it to answer 'what is the SLA for a P1?' or to audit which policies are currently paused. Supports server-side OData querying — $filter, $search, $orderby, $select, $top, $skip, $count (MCP clients see these as _filter, _search, _orderby, _select, _top, _skip, _count because $ is not a legal tool-input key). Example: $filter=paused eq true."},"post":{"summary":"Create an SLA policy","parameters":[{"$ref":"#/components/parameters/InstanceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlaPolicy"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlaPolicy"}}}}},"description":"Defines a new service-level target — name, the priority it applies to, responseTimeHours and resolutionTimeHours. Configuration only; it does not alter any existing incident."}},"/sla_policies/{id}":{"get":{"summary":"Get one SLA policy","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/SlaPolicy"}}}},"404":{"description":"Not found"}},"description":"Fetches a single SLA policy by id (e.g. SLA-001) with its response/resolution targets and its active and paused flags."},"patch":{"summary":"Update an SLA policy's targets","description":"Edits a policy's name, priority, response/resolution hours or active flag. For the specific act of suspending or restarting SLA timing use itsm__pause__sla_policies / itsm__resume__sla_policies, which enforce the paused-state transition.","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/SlaPolicy"}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlaPolicy"}}}},"404":{"description":"Not found"}}},"delete":{"summary":"Delete an SLA policy","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"}},"description":"DESTRUCTIVE and irreversible: removes the SLA definition, so tickets at that priority no longer have a target. To stop the clock temporarily use itsm__pause__sla_policies instead."}},"/sla-policies/{id}/pause":{"post":{"summary":"Pause an SLA policy (stop the clock)","description":"Suspends a service-level target by setting paused=true, e.g. during a maintenance window so response/resolution clocks do not count against IT. Reverse it with itsm__resume__sla_policies; use itsm__update__sla_policies to change the target hours themselves. Fails with 422 if the policy is already paused.","parameters":[{"$ref":"#/components/parameters/InstanceId"},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Updated SLA policy after pause","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlaPolicy"}}}},"404":{"description":"Not found"},"422":{"description":"SLA policy is already paused"}}}},"/sla-policies/{id}/resume":{"post":{"summary":"Resume a paused SLA policy (restart the clock)","description":"Puts a suspended service-level target back in force by setting paused=false — the counterpart to itsm__pause__sla_policies, typically once a maintenance window ends. Fails with 422 if the policy is not currently paused.","parameters":[{"$ref":"#/components/parameters/InstanceId"},{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Updated SLA policy after resume","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlaPolicy"}}}},"404":{"description":"Not found"},"422":{"description":"SLA policy is not paused and cannot be resumed"}}}},"/problems":{"get":{"summary":"List problems (root causes behind repeat incidents)","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/Problem"}},"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)"}},"description":"ITIL problem records: the underlying cause investigated behind a pattern of incidents (e.g. 'recurring login failures'), with status open | known_error | resolved and a rootCause classification. Use this for root-cause / known-error questions; individual user-reported breakages are itsm__list__incidents. Supports server-side OData querying — $filter, $search, $orderby, $select, $top, $skip, $count (MCP clients see these as _filter, _search, _orderby, _select, _top, _skip, _count because $ is not a legal tool-input key). Example: $filter=status eq 'known_error'."},"post":{"summary":"Open a problem investigation","parameters":[{"$ref":"#/components/parameters/InstanceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"description":"Creates a problem record to investigate the root cause behind repeating incidents. Use it when the same failure keeps recurring; log the individual user-facing outages as incidents."}},"/problems/{id}":{"get":{"summary":"Get one problem record","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/Problem"}}}},"404":{"description":"Not found"}},"description":"Fetches a single problem by id (e.g. PRB-0001) with its status and rootCause classification — useful for checking whether a recurring failure is already a known error."},"patch":{"summary":"Update a problem investigation","description":"Edits the problem's title, status (open | known_error | resolved) or rootCause as the investigation progresses — for example marking it a known error once the cause is identified.","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/Problem"}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found"}}},"delete":{"summary":"Delete a problem record","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"}},"description":"DESTRUCTIVE and irreversible: erases the problem record and its root-cause findings. Normally close an investigation by setting status to 'resolved' with itsm__update__problems instead."}},"/service_requests":{"get":{"summary":"List service requests (asks from the service catalog)","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/ServiceRequest"}},"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)"}},"description":"Service requests are people ASKING for something standard — a new laptop, software, access — with status submitted | approved | in_progress | completed | cancelled, requestedBy and a fulfillmentGroup (IT Support, Security, Procurement, Facilities). Use itsm__list__incidents instead when something is broken. Supports server-side OData querying — $filter, $search, $orderby, $select, $top, $skip, $count (MCP clients see these as _filter, _search, _orderby, _select, _top, _skip, _count because $ is not a legal tool-input key). Example: $filter=status eq 'submitted' and fulfillmentGroup eq 'Procurement'."},"post":{"summary":"Submit a service request","parameters":[{"$ref":"#/components/parameters/InstanceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceRequest"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceRequest"}}}}},"description":"Raises a catalog request on behalf of someone — title, requestedBy and the fulfillmentGroup that will handle it — normally starting in 'submitted'. For a fault or outage file an incident instead."}},"/service_requests/{id}":{"get":{"summary":"Get one service request","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/ServiceRequest"}}}},"404":{"description":"Not found"}},"description":"Fetches a single service request by id (e.g. SR-0001) with its status, requester and fulfillment group — the tool for 'where is my laptop request?'."},"patch":{"summary":"Update or progress a service request","description":"Edits the request or moves it along its lifecycle by setting status to approved, in_progress, completed or cancelled, and can reroute it to a different fulfillmentGroup.","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/ServiceRequest"}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceRequest"}}}},"404":{"description":"Not found"}}},"delete":{"summary":"Delete a service request","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"}},"description":"DESTRUCTIVE and irreversible: removes the request and its history. To withdraw a request while keeping the record, set status to 'cancelled' with itsm__update__service_requests instead."}},"/cis":{"get":{"summary":"List CMDB configuration items (IT assets)","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/ConfigurationItem"}},"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)"}},"description":"The CMDB inventory of managed IT assets — servers, workstations, network devices, applications, databases, storage — each with name, type, status (operational | maintenance | retired | ordered), environment (production/staging/development/dr) and owning team. Use it to find the asset behind a ticket or audit what is in production. Supports server-side OData querying — $filter, $search, $orderby, $select, $top, $skip, $count (MCP clients see these as _filter, _search, _orderby, _select, _top, _skip, _count because $ is not a legal tool-input key). Example: $filter=type eq 'server' and environment eq 'production'."},"post":{"summary":"Add a configuration item to the CMDB","parameters":[{"$ref":"#/components/parameters/InstanceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigurationItem"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigurationItem"}}}}},"description":"Registers a new managed asset in the CMDB — name, type, environment, owning team and lifecycle status. Inventory only; it does not create any ticket."}},"/cis/{id}":{"get":{"summary":"Get one CMDB configuration item","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/ConfigurationItem"}}}},"404":{"description":"Not found"}},"description":"Fetches a single configuration item by id (e.g. CI-a1b2c3d4) with its type, environment, owner and operational status."},"patch":{"summary":"Update a CMDB configuration item","description":"Edits an asset record — status (e.g. move it to maintenance or retired), environment, owner or name. Updates inventory metadata only; it does not schedule the work, which belongs in a change request.","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/ConfigurationItem"}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfigurationItem"}}}},"404":{"description":"Not found"}}},"delete":{"summary":"Delete a CMDB configuration item","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"}},"description":"DESTRUCTIVE and irreversible: removes the asset from the CMDB, breaking references from tickets and changes. For decommissioned kit set status to 'retired' with itsm__update__cis instead."}},"/kb_articles":{"get":{"summary":"Search the IT knowledge base","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/KbArticle"}},"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)"}},"description":"Self-service how-to and troubleshooting articles published by IT (title, category, author, publishedAt, views, helpful counts). Reach for this FIRST when a user asks how to do something, before opening a ticket. Supports server-side OData querying — $filter, $search, $orderby, $select, $top, $skip, $count (MCP clients see these as _filter, _search, _orderby, _select, _top, _skip, _count because $ is not a legal tool-input key). Example: $search=password reset, or $filter=category eq 'Authentication'&$orderby=helpful desc."},"post":{"summary":"Publish a knowledge base article","parameters":[{"$ref":"#/components/parameters/InstanceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KbArticle"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KbArticle"}}}}},"description":"Creates a new KB article — title, category (Authentication, Network, Hardware, Software, Security, Onboarding), author and publish date — so users can self-serve instead of raising incidents."}},"/kb_articles/{id}":{"get":{"summary":"Get one knowledge base article","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/KbArticle"}}}},"404":{"description":"Not found"}},"description":"Fetches a single KB article by id (e.g. KB-0001) with its category, author and usefulness stats — use it to cite specific guidance once you have found it via itsm__list__kb_articles."},"patch":{"summary":"Update a knowledge base article","description":"Edits an existing article's title, category, author or publication date — for example to correct out-of-date guidance rather than publishing a duplicate.","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/KbArticle"}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KbArticle"}}}},"404":{"description":"Not found"}}},"delete":{"summary":"Delete a knowledge base article","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"}},"description":"DESTRUCTIVE and irreversible: unpublishes and erases the article, so users searching the knowledge base will no longer find that guidance."}},"/alerts":{"get":{"summary":"List monitoring alerts from observability tools","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/Alert"}},"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)"}},"description":"Machine-generated alerts fired by monitoring systems (Datadog, PagerDuty, Nagios, CloudWatch, Prometheus) with severity critical | warning | info, status active | acknowledged | resolved and trigger/resolve times. These are detections, not human-reported tickets — use itsm__list__incidents for those. Supports server-side OData querying — $filter, $search, $orderby, $select, $top, $skip, $count (MCP clients see these as _filter, _search, _orderby, _select, _top, _skip, _count because $ is not a legal tool-input key). Example: $filter=status eq 'active' and severity eq 'critical'."},"post":{"summary":"Record a monitoring alert","parameters":[{"$ref":"#/components/parameters/InstanceId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Alert"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Alert"}}}}},"description":"Creates an alert record as if a monitoring tool had fired it — title, severity, source system and triggeredAt. Mostly for simulating observability signals; a person reporting an issue should be filed as an incident."}},"/alerts/{id}":{"get":{"summary":"Get one monitoring alert","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/Alert"}}}},"404":{"description":"Not found"}},"description":"Fetches a single alert by id (e.g. ALT-0001) with its severity, source, trigger time and whether it has been acknowledged or resolved."},"patch":{"summary":"Acknowledge or resolve a monitoring alert","description":"Updates an alert — most often setting status to 'acknowledged' when someone picks it up or 'resolved' once the condition clears, and stamping resolvedAt.","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/Alert"}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Alert"}}}},"404":{"description":"Not found"}}},"delete":{"summary":"Delete a monitoring alert","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"}},"description":"DESTRUCTIVE and irreversible: erases the alert record and its detection history. To clear noise while keeping the trail, set its status to 'resolved' with itsm__update__alerts instead."}}}}