---
**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`.
---
**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
GET /accounts
List CRM accounts (customer companies)
Sales-relationship records for companies this org sells to — customers, prospects and partners — with owner, territory, industry, ARR/MRR and renewal dates. These are not bank deposit accounts (see the retail-banking app) and not user/login accounts (see the identity app). Supports server-side OData querying — _filter, _orderby, _select, _search, _top, _skip, _count (the spec names these $filter etc.; MCP clients see the _ form because $ is not a legal tool-input key).
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "List CRM accounts (customer companies)",
"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/Account"
}
},
"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": "Sales-relationship records for companies this org sells to — customers, prospects and partners — with owner, territory, industry, ARR/MRR and renewal dates. These are not bank deposit accounts (see the retail-banking app) and not user/login accounts (see the identity app). Supports server-side OData querying — _filter, _orderby, _select, _search, _top, _skip, _count (the spec names these $filter etc.; MCP clients see the _ form because $ is not a legal tool-input key)."
}
POST /accounts
Create CRM account (customer company)
Adds a new company record to the CRM. Use this for an organisation you sell to; an individual person at a known company belongs in contacts, and an unqualified inbound person belongs in leads.
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "Create CRM account (customer company)",
"parameters": [
{
"$ref": "#/components/parameters/InstanceId"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Account"
}
}
}
},
"responses": {
"201": {
"description": "Created",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Account"
}
}
}
}
},
"description": "Adds a new company record to the CRM. Use this for an organisation you sell to; an individual person at a known company belongs in contacts, and an unqualified inbound person belongs in leads."
}
GET /accounts/{id}
Get CRM account by id
Fetches one customer company (e.g. ACC-0001) with its firmographics and revenue rollups. Use this when you already have the account id; to find an account by name or attribute, use the list tool with _search or _filter.
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "Get CRM account by 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/Account"
}
}
}
},
"404": {
"description": "Not found"
}
},
"description": "Fetches one customer company (e.g. ACC-0001) with its firmographics and revenue rollups. Use this when you already have the account id; to find an account by name or attribute, use the list tool with _search or _filter."
}
PATCH /accounts/{id}
Update CRM account
Partial update of a customer company — e.g. reassign owner, change status (customer/prospect/partner/inactive), territory, or revenue fields. Send only the fields you want to change.
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "Update CRM account",
"description": "Partial update of a customer company — e.g. reassign owner, change status (customer/prospect/partner/inactive), territory, or revenue fields. Send only the fields you want to change.",
"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/Account"
}
}
}
},
"responses": {
"200": {
"description": "Updated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Account"
}
}
}
},
"404": {
"description": "Not found"
}
}
}
DELETE /accounts/{id}
Delete CRM account (destructive)
Permanently removes the company record; this cannot be undone and related contacts, opportunities and cases are not cascaded or cleaned up. Prefer updating status to 'inactive' unless the record genuinely must be purged.
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "Delete CRM account (destructive)",
"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": "Permanently removes the company record; this cannot be undone and related contacts, opportunities and cases are not cascaded or cleaned up. Prefer updating status to 'inactive' unless the record genuinely must be purged."
}
GET /contacts
List CRM contacts (named people at customer accounts)
External customer-side individuals — buyers, champions, admins — each linked to an account via accountId, with title, email, phone and active/inactive status. Not employees (see the hris and identity apps) and not unqualified prospects (see leads). Supports server-side OData querying — _filter, _orderby, _select, _search, _top, _skip, _count (the spec names these $filter etc.; MCP clients see the _ form because $ is not a legal tool-input key).
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "List CRM contacts (named people at customer accounts)",
"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/Contact"
}
},
"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": "External customer-side individuals — buyers, champions, admins — each linked to an account via accountId, with title, email, phone and active/inactive status. Not employees (see the hris and identity apps) and not unqualified prospects (see leads). Supports server-side OData querying — _filter, _orderby, _select, _search, _top, _skip, _count (the spec names these $filter etc.; MCP clients see the _ form because $ is not a legal tool-input key)."
}
POST /contacts
Create CRM contact (person at a customer account)
Adds a person who already belongs to a known account. For an unqualified inbound prospect create a lead instead, and to promote an existing lead use the lead convert tool rather than creating a contact by hand.
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "Create CRM contact (person at a customer account)",
"parameters": [
{
"$ref": "#/components/parameters/InstanceId"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Contact"
}
}
}
},
"responses": {
"201": {
"description": "Created",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Contact"
}
}
}
}
},
"description": "Adds a person who already belongs to a known account. For an unqualified inbound prospect create a lead instead, and to promote an existing lead use the lead convert tool rather than creating a contact by hand."
}
GET /contacts/{id}
Get CRM contact by id
Fetches one customer-side person record by id, including their accountId, title and contact details.
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "Get CRM contact by 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/Contact"
}
}
}
},
"404": {
"description": "Not found"
}
},
"description": "Fetches one customer-side person record by id, including their accountId, title and contact details."
}
PATCH /contacts/{id}
Update CRM contact
Partial update of a customer-side person — e.g. new title, email, phone, owning account, or flipping status to inactive.
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "Update CRM contact",
"description": "Partial update of a customer-side person — e.g. new title, email, phone, owning account, or flipping status to inactive.",
"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/Contact"
}
}
}
},
"responses": {
"200": {
"description": "Updated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Contact"
}
}
}
},
"404": {
"description": "Not found"
}
}
}
DELETE /contacts/{id}
Delete CRM contact (destructive)
Permanently removes the person record; this cannot be undone. Prefer setting status to 'inactive' so engagement history stays attributable.
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "Delete CRM contact (destructive)",
"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": "Permanently removes the person record; this cannot be undone. Prefer setting status to 'inactive' so engagement history stays attributable."
}
GET /opportunities
List CRM opportunities (sales deals in the pipeline)
Revenue deals tied to an account, with stage, amount, probability, closeDate, owner and a server-maintained stageHistory. This is the sales pipeline — customer support tickets are cases and logged touchpoints are activities. Supports server-side OData querying — _filter, _orderby, _select, _search, _top, _skip, _count (the spec names these $filter etc.; MCP clients see the _ form because $ is not a legal tool-input key). Example: _filter="stage ne 'closed_lost' and amount gt 50000".
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "List CRM opportunities (sales deals in the pipeline)",
"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/Opportunity"
}
},
"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": "Revenue deals tied to an account, with stage, amount, probability, closeDate, owner and a server-maintained stageHistory. This is the sales pipeline — customer support tickets are cases and logged touchpoints are activities. Supports server-side OData querying — _filter, _orderby, _select, _search, _top, _skip, _count (the spec names these $filter etc.; MCP clients see the _ form because $ is not a legal tool-input key). Example: _filter=\"stage ne 'closed_lost' and amount gt 50000\"."
}
POST /opportunities
Create CRM opportunity (new sales deal)
Opens a new pipeline deal against an account with a stage, amount and close date. To move an existing deal forward use the advance-stage tool rather than creating a second opportunity.
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "Create CRM opportunity (new sales deal)",
"parameters": [
{
"$ref": "#/components/parameters/InstanceId"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Opportunity"
}
}
}
},
"responses": {
"201": {
"description": "Created",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Opportunity"
}
}
}
}
},
"description": "Opens a new pipeline deal against an account with a stage, amount and close date. To move an existing deal forward use the advance-stage tool rather than creating a second opportunity."
}
GET /opportunities/{id}
Get CRM opportunity by id
Fetches one pipeline deal including its stageHistory (the audit trail of stage moves recorded by the advance-stage tool).
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "Get CRM opportunity by 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/Opportunity"
}
}
}
},
"404": {
"description": "Not found"
}
},
"description": "Fetches one pipeline deal including its stageHistory (the audit trail of stage moves recorded by the advance-stage tool)."
}
PATCH /opportunities/{id}
Update CRM opportunity (non-stage fields)
Partial update of deal attributes — amount, probability, closeDate, owner, name. To change the pipeline stage prefer the advance-stage tool, which enforces the stage order and appends to stageHistory; this tool does neither.
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "Update CRM opportunity (non-stage fields)",
"description": "Partial update of deal attributes — amount, probability, closeDate, owner, name. To change the pipeline stage prefer the advance-stage tool, which enforces the stage order and appends to stageHistory; this tool does neither.",
"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/Opportunity"
}
}
}
},
"responses": {
"200": {
"description": "Updated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Opportunity"
}
}
}
},
"404": {
"description": "Not found"
}
}
}
DELETE /opportunities/{id}
Delete CRM opportunity (destructive)
Permanently removes the deal and its stage history; this cannot be undone. To record a deal that did not land, advance its stage to closed_lost instead.
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "Delete CRM opportunity (destructive)",
"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": "Permanently removes the deal and its stage history; this cannot be undone. To record a deal that did not land, advance its stage to closed_lost instead."
}
POST /opportunities/{id}/advance-stage
Advance a CRM opportunity to a new pipeline stage
The preferred way to move a deal: sets the stage, appends a timestamped stageHistory entry with optional notes, and enforces pipeline order. Forward-only and terminal — moving backwards is rejected, and a closed_won/closed_lost deal cannot be advanced at all. Use PATCH /opportunities/{id} for non-stage edits.
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "Advance a CRM opportunity to a new pipeline stage",
"description": "The preferred way to move a deal: sets the stage, appends a timestamped stageHistory entry with optional notes, and enforces pipeline order. Forward-only and terminal — moving backwards is rejected, and a closed_won/closed_lost deal cannot be advanced at all. Use PATCH /opportunities/{id} for non-stage edits.",
"parameters": [
{
"$ref": "#/components/parameters/InstanceId"
},
{
"in": "path",
"name": "id",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"stage": {
"type": "string",
"enum": [
"prospecting",
"qualification",
"proposal",
"negotiation",
"closed_won",
"closed_lost"
],
"example": "proposal"
},
"notes": {
"type": "string",
"example": "Customer responded positively to initial pitch"
}
},
"required": [
"stage"
]
}
}
}
},
"responses": {
"200": {
"description": "Updated opportunity with new stage and stageHistory entry",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Opportunity"
}
}
}
},
"400": {
"description": "Invalid stage value"
},
"404": {
"description": "Not found"
},
"422": {
"description": "Stage transition not allowed (opportunity is closed or move is backwards)"
}
}
}
GET /leads
List CRM leads (unqualified inbound prospects)
Top-of-funnel people not yet tied to an account, with source (web form, trade show, referral…), score and status new → contacted → qualified → converted/disqualified/dead. Once qualified, a lead becomes a contact (and optionally an opportunity) via the convert tool. Supports server-side OData querying — _filter, _orderby, _select, _search, _top, _skip, _count (the spec names these $filter etc.; MCP clients see the _ form because $ is not a legal tool-input key).
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "List CRM leads (unqualified inbound prospects)",
"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/Lead"
}
},
"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": "Top-of-funnel people not yet tied to an account, with source (web form, trade show, referral…), score and status new → contacted → qualified → converted/disqualified/dead. Once qualified, a lead becomes a contact (and optionally an opportunity) via the convert tool. Supports server-side OData querying — _filter, _orderby, _select, _search, _top, _skip, _count (the spec names these $filter etc.; MCP clients see the _ form because $ is not a legal tool-input key)."
}
POST /leads
Create CRM lead (raw inbound prospect)
Captures a new unqualified prospect with their company, source and score. Use contacts instead when the person already belongs to a known customer account.
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "Create CRM lead (raw inbound prospect)",
"parameters": [
{
"$ref": "#/components/parameters/InstanceId"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Lead"
}
}
}
},
"responses": {
"201": {
"description": "Created",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Lead"
}
}
}
}
},
"description": "Captures a new unqualified prospect with their company, source and score. Use contacts instead when the person already belongs to a known customer account."
}
GET /leads/{id}
Get CRM lead by id
Fetches one prospect record, including convertedTo once the lead has been run through the convert tool.
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "Get CRM lead by 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/Lead"
}
}
}
},
"404": {
"description": "Not found"
}
},
"description": "Fetches one prospect record, including convertedTo once the lead has been run through the convert tool."
}
PATCH /leads/{id}
Update CRM lead
Partial update — e.g. move status from new to contacted or qualified, adjust score, or fill in phone/title/accountId. Do not set status to 'converted' here; use the convert tool so the contact (and optional opportunity) are actually created.
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "Update CRM lead",
"description": "Partial update — e.g. move status from new to contacted or qualified, adjust score, or fill in phone/title/accountId. Do not set status to 'converted' here; use the convert tool so the contact (and optional opportunity) are actually created.",
"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/Lead"
}
}
}
},
"responses": {
"200": {
"description": "Updated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Lead"
}
}
}
},
"404": {
"description": "Not found"
}
}
}
DELETE /leads/{id}
Delete CRM lead (destructive)
Permanently removes the prospect record; this cannot be undone. Prefer status 'disqualified' or 'dead' so funnel conversion rates stay accurate.
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "Delete CRM lead (destructive)",
"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": "Permanently removes the prospect record; this cannot be undone. Prefer status 'disqualified' or 'dead' so funnel conversion rates stay accurate."
}
POST /leads/{id}/convert
Convert a CRM lead into a contact (and optionally an opportunity)
The one-way qualification step: creates a Contact from the lead's fields, additionally creates an Opportunity when opportunity_data is supplied, and stamps the lead as 'converted'. Not repeatable and not reversible — a lead that is already converted or disqualified is rejected.
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "Convert a CRM lead into a contact (and optionally an opportunity)",
"description": "The one-way qualification step: creates a Contact from the lead's fields, additionally creates an Opportunity when opportunity_data is supplied, and stamps the lead as 'converted'. Not repeatable and not reversible — a lead that is already converted or disqualified is rejected.",
"parameters": [
{
"$ref": "#/components/parameters/InstanceId"
},
{
"in": "path",
"name": "id",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"opportunity_data": {
"type": "object",
"description": "Optional. If provided, an Opportunity is created by spreading these fields.",
"properties": {
"name": {
"type": "string",
"example": "Enterprise New Business - Q3 2026"
},
"accountId": {
"type": "string",
"example": "ACC-0001"
},
"stage": {
"type": "string",
"enum": [
"prospecting",
"qualification",
"proposal",
"negotiation",
"closed_won",
"closed_lost"
],
"example": "prospecting"
},
"amount": {
"type": "number",
"example": 50000
},
"probability": {
"type": "integer",
"example": 10
},
"closeDate": {
"type": "string",
"format": "date-time",
"example": "2026-09-30T00:00:00.000Z"
},
"owner": {
"type": "string",
"example": "alice@example.com"
}
}
}
}
}
}
}
},
"responses": {
"200": {
"description": "Converted lead with the created contact and optional opportunity",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"contact": {
"$ref": "#/components/schemas/Contact"
},
"opportunity": {
"$ref": "#/components/schemas/Opportunity",
"nullable": true
},
"lead": {
"$ref": "#/components/schemas/Lead"
}
}
}
}
}
},
"404": {
"description": "Not found"
},
"422": {
"description": "Lead cannot be converted (already converted or disqualified)"
}
}
}
GET /cases
List CRM cases (customer support tickets)
Issues reported by a customer against an account, with subject, priority, assignee and status open → in_progress → resolved → closed. These are customer-facing support cases; internal employee IT tickets live in the itsm app. Supports server-side OData querying — _filter, _orderby, _select, _search, _top, _skip, _count (the spec names these $filter etc.; MCP clients see the _ form because $ is not a legal tool-input key).
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "List CRM cases (customer support 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/Case"
}
},
"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": "Issues reported by a customer against an account, with subject, priority, assignee and status open → in_progress → resolved → closed. These are customer-facing support cases; internal employee IT tickets live in the itsm app. Supports server-side OData querying — _filter, _orderby, _select, _search, _top, _skip, _count (the spec names these $filter etc.; MCP clients see the _ form because $ is not a legal tool-input key)."
}
POST /cases
Create CRM case (customer support ticket)
Logs a new customer-reported issue against an account with a subject and priority. For an internal employee IT problem create an itsm incident instead.
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "Create CRM case (customer support ticket)",
"parameters": [
{
"$ref": "#/components/parameters/InstanceId"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Case"
}
}
}
},
"responses": {
"201": {
"description": "Created",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Case"
}
}
}
}
},
"description": "Logs a new customer-reported issue against an account with a subject and priority. For an internal employee IT problem create an itsm incident instead."
}
GET /cases/{id}
Get CRM case by id
Fetches one customer support case with its status, priority, assignee and resolution timestamps.
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "Get CRM case by 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/Case"
}
}
}
},
"404": {
"description": "Not found"
}
},
"description": "Fetches one customer support case with its status, priority, assignee and resolution timestamps."
}
PATCH /cases/{id}
Update or transition a CRM case
Partial update, and the only way to move a case through its lifecycle. State-machine rules are enforced: an 'open' case cannot jump straight to 'closed' (route it via in_progress or resolved), and reopening a 'closed' case requires reopenReason (alias reopen_reason).
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "Update or transition a CRM case",
"description": "Partial update, and the only way to move a case through its lifecycle. State-machine rules are enforced: an 'open' case cannot jump straight to 'closed' (route it via in_progress or resolved), and reopening a 'closed' case requires reopenReason (alias reopen_reason).",
"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/Case"
}
}
}
},
"responses": {
"200": {
"description": "Updated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Case"
}
}
}
},
"404": {
"description": "Not found"
},
"422": {
"description": "State-machine violation — e.g. closing an open case directly, or reopening without reopenReason"
}
}
}
DELETE /cases/{id}
Delete CRM case (destructive)
Permanently removes the support case and its history; this cannot be undone. Resolving or closing the case is almost always the right action instead.
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "Delete CRM case (destructive)",
"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": "Permanently removes the support case and its history; this cannot be undone. Resolving or closing the case is almost always the right action instead."
}
GET /activities
List CRM activities (logged calls, emails, meetings, tasks, notes)
The touchpoint timeline attached to an account: type, subject, owner, dueDate and a completed flag. Use it for engagement history or to find open follow-ups; real calendar invites live in the calendar app. Supports server-side OData querying — _filter, _orderby, _select, _search, _top, _skip, _count (the spec names these $filter etc.; MCP clients see the _ form because $ is not a legal tool-input key).
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "List CRM activities (logged calls, emails, meetings, tasks, notes)",
"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/Activity"
}
},
"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 touchpoint timeline attached to an account: type, subject, owner, dueDate and a completed flag. Use it for engagement history or to find open follow-ups; real calendar invites live in the calendar app. Supports server-side OData querying — _filter, _orderby, _select, _search, _top, _skip, _count (the spec names these $filter etc.; MCP clients see the _ form because $ is not a legal tool-input key)."
}
POST /activities
Log a CRM activity (call, email, meeting, task or note)
Records a touchpoint that happened, or schedules a follow-up task, against an account. This only writes a CRM record — it does not send an email or book a meeting.
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "Log a CRM activity (call, email, meeting, task or note)",
"parameters": [
{
"$ref": "#/components/parameters/InstanceId"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Activity"
}
}
}
},
"responses": {
"201": {
"description": "Created",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Activity"
}
}
}
}
},
"description": "Records a touchpoint that happened, or schedules a follow-up task, against an account. This only writes a CRM record — it does not send an email or book a meeting."
}
GET /activities/{id}
Get CRM activity by id
Fetches one logged touchpoint or follow-up task from an account's timeline.
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "Get CRM activity by 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/Activity"
}
}
}
},
"404": {
"description": "Not found"
}
},
"description": "Fetches one logged touchpoint or follow-up task from an account's timeline."
}
PATCH /activities/{id}
Update CRM activity
Partial update of a logged touchpoint — most often flipping completed to true when a follow-up is done, or changing dueDate, owner or subject.
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "Update CRM activity",
"description": "Partial update of a logged touchpoint — most often flipping completed to true when a follow-up is done, or changing dueDate, owner or subject.",
"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/Activity"
}
}
}
},
"responses": {
"200": {
"description": "Updated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Activity"
}
}
}
},
"404": {
"description": "Not found"
}
}
}
DELETE /activities/{id}
Delete CRM activity (destructive)
Permanently removes the touchpoint from the account timeline; this cannot be undone. Mark a task completed instead of deleting it when the work simply finished.
Authentication
[
{
"patAuth": []
}
]
Request, responses and operation details
{
"summary": "Delete CRM activity (destructive)",
"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": "Permanently removes the touchpoint from the account timeline; this cannot be undone. Mark a task completed instead of deleting it when the work simply finished."
}
GET /recent-campaign
Get most recent campaign (legacy stub)
Legacy compatibility endpoint. Returns a static most-recent campaign record. No authentication required.
Authentication
[]
Request, responses and operation details
{
"summary": "Get most recent campaign (legacy stub)",
"description": "Legacy compatibility endpoint. Returns a static most-recent campaign record. No authentication required.",
"parameters": [],
"responses": {
"200": {
"description": "Most recent campaign",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"campaign": {
"type": "object",
"properties": {
"id": {
"type": "string",
"example": "campaign-2025-q1"
},
"name": {
"type": "string",
"example": "Q1 2025 Referral Campaign"
},
"status": {
"type": "string",
"example": "active"
}
}
}
}
}
}
}
}
},
"security": []
}
GET /engagement
Get customer engagement data (legacy stub)
Legacy compatibility endpoint. Returns static engagement metrics. No authentication required.
Authentication
[]
Request, responses and operation details
{
"summary": "Get customer engagement data (legacy stub)",
"description": "Legacy compatibility endpoint. Returns static engagement metrics. No authentication required.",
"parameters": [],
"responses": {
"200": {
"description": "Engagement metrics",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"engagement": {
"type": "object",
"properties": {
"totalUsers": {
"type": "integer",
"example": 1250
},
"activeUsers": {
"type": "integer",
"example": 890
},
"engagementRate": {
"type": "number",
"example": 71.2
}
}
}
}
}
}
}
}
},
"security": []
}