Purple DEX API Documentation
Machine-readable OpenAPI 3.0 specification: https://marketplace.moveworks.com/api/purple-suite/dex/openapi.json
The consolidated all-apps document at https://marketplace.moveworks.com/api/purple-suite/openapi.json can be narrowed to this app with ?apps=dex, or combined with other apps comma-separated (e.g. ?apps=dex,itsm).
Overview
Endpoints
GET /api/purple-suite/dex/devices
List DEX-monitored endpoint devices with health telemetry
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
limit | query | integer | no | Legacy page size (default 50). Prefer $top. Ignored when $top/$skip are used. |
cursor | query | string | no | Legacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top. |
$filter | query | string | no | 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". |
$select | query | string | no | 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. |
$orderby | query | string | no | Sort clause(s), comma-separated, each "field [asc|desc]" (asc is the default). Example: "createdAt desc, lastName asc". Null values sort last. |
$search | query | string | no | Free-text, case-insensitive substring match across the resource's searchable fields. |
$top | query | integer | no | Maximum number of items to return (page size). |
$skip | query | integer | no | Number of matching items to skip before returning results (offset paging). Combine with $top. |
$count | query | boolean | no | When true, include @odata.count (total matches after $filter/$search, before paging) in the response. |
Responses
200- Paginated list
application/jsondataarrayarray of:
Deviceidstringhostnamestringdevice_typestringosstringos_versionstringmanufacturerstringmodelstringserial_numberstringassigned_tostring — Email of the assigned userdepartmentstringlocationstringip_addressstringlast_seenstringhealth_scorenumbercpu_usage_pctnumbermemory_usage_pctnumberdisk_usage_pctnumberbattery_health_pctnumberuptime_hoursnumbercompliance_statusstringencryption_enabledbooleanantivirus_statusstringcreatedAtstringupdatedAtstring
nextCursorstring — Cursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor.totalinteger — Total documents in the collection.@odata.countinteger — Present only when $count=true: total matches after $filter/$search.@odata.truncatedboolean — Present and true only when the collection exceeded the in-memory query cap and results may be incomplete.
400- Invalid OData query (e.g. malformed $filter)
POST /api/purple-suite/dex/devices
Create device
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes |
Request body
application/json — required
Device
idstringhostnamestringdevice_typestringosstringos_versionstringmanufacturerstringmodelstringserial_numberstringassigned_tostring — Email of the assigned userdepartmentstringlocationstringip_addressstringlast_seenstringhealth_scorenumbercpu_usage_pctnumbermemory_usage_pctnumberdisk_usage_pctnumberbattery_health_pctnumberuptime_hoursnumbercompliance_statusstringencryption_enabledbooleanantivirus_statusstringcreatedAtstringupdatedAtstring
Responses
201- Created
application/jsonDeviceidstringhostnamestringdevice_typestringosstringos_versionstringmanufacturerstringmodelstringserial_numberstringassigned_tostring — Email of the assigned userdepartmentstringlocationstringip_addressstringlast_seenstringhealth_scorenumbercpu_usage_pctnumbermemory_usage_pctnumberdisk_usage_pctnumberbattery_health_pctnumberuptime_hoursnumbercompliance_statusstringencryption_enabledbooleanantivirus_statusstringcreatedAtstringupdatedAtstring
GET /api/purple-suite/dex/devices/{id}
Get device
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Responses
200- Found
application/jsonDeviceidstringhostnamestringdevice_typestringosstringos_versionstringmanufacturerstringmodelstringserial_numberstringassigned_tostring — Email of the assigned userdepartmentstringlocationstringip_addressstringlast_seenstringhealth_scorenumbercpu_usage_pctnumbermemory_usage_pctnumberdisk_usage_pctnumberbattery_health_pctnumberuptime_hoursnumbercompliance_statusstringencryption_enabledbooleanantivirus_statusstringcreatedAtstringupdatedAtstring
404- Not found
DELETE /api/purple-suite/dex/devices/{id}
Delete device
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Responses
200- Deleted
application/jsonsuccessboolean
404- Not found
PATCH /api/purple-suite/dex/devices/{id}
Update device
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Request body
application/json
Device
idstringhostnamestringdevice_typestringosstringos_versionstringmanufacturerstringmodelstringserial_numberstringassigned_tostring — Email of the assigned userdepartmentstringlocationstringip_addressstringlast_seenstringhealth_scorenumbercpu_usage_pctnumbermemory_usage_pctnumberdisk_usage_pctnumberbattery_health_pctnumberuptime_hoursnumbercompliance_statusstringencryption_enabledbooleanantivirus_statusstringcreatedAtstringupdatedAtstring
Responses
200- Updated
application/jsonDeviceidstringhostnamestringdevice_typestringosstringos_versionstringmanufacturerstringmodelstringserial_numberstringassigned_tostring — Email of the assigned userdepartmentstringlocationstringip_addressstringlast_seenstringhealth_scorenumbercpu_usage_pctnumbermemory_usage_pctnumberdisk_usage_pctnumberbattery_health_pctnumberuptime_hoursnumbercompliance_statusstringencryption_enabledbooleanantivirus_statusstringcreatedAtstringupdatedAtstring
404- Not found
GET /api/purple-suite/dex/software_inventory
List software installed on DEX-monitored devices
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
limit | query | integer | no | Legacy page size (default 50). Prefer $top. Ignored when $top/$skip are used. |
cursor | query | string | no | Legacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top. |
$filter | query | string | no | 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". |
$select | query | string | no | 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. |
$orderby | query | string | no | Sort clause(s), comma-separated, each "field [asc|desc]" (asc is the default). Example: "createdAt desc, lastName asc". Null values sort last. |
$search | query | string | no | Free-text, case-insensitive substring match across the resource's searchable fields. |
$top | query | integer | no | Maximum number of items to return (page size). |
$skip | query | integer | no | Number of matching items to skip before returning results (offset paging). Combine with $top. |
$count | query | boolean | no | When true, include @odata.count (total matches after $filter/$search, before paging) in the response. |
Responses
200- Paginated list
application/jsondataarrayarray of:
SoftwareInventoryidstringdevice_idstringsoftware_namestringversionstringpublisherstringinstall_datestringlast_usedstringlicense_typestringis_managedbooleanis_approvedbooleancreatedAtstringupdatedAtstring
nextCursorstring — Cursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor.totalinteger — Total documents in the collection.@odata.countinteger — Present only when $count=true: total matches after $filter/$search.@odata.truncatedboolean — Present and true only when the collection exceeded the in-memory query cap and results may be incomplete.
400- Invalid OData query (e.g. malformed $filter)
POST /api/purple-suite/dex/software_inventory
Create software inventory entry
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes |
Request body
application/json — required
SoftwareInventory
idstringdevice_idstringsoftware_namestringversionstringpublisherstringinstall_datestringlast_usedstringlicense_typestringis_managedbooleanis_approvedbooleancreatedAtstringupdatedAtstring
Responses
201- Created
application/jsonSoftwareInventoryidstringdevice_idstringsoftware_namestringversionstringpublisherstringinstall_datestringlast_usedstringlicense_typestringis_managedbooleanis_approvedbooleancreatedAtstringupdatedAtstring
GET /api/purple-suite/dex/software_inventory/{id}
Get software inventory entry
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Responses
200- Found
application/jsonSoftwareInventoryidstringdevice_idstringsoftware_namestringversionstringpublisherstringinstall_datestringlast_usedstringlicense_typestringis_managedbooleanis_approvedbooleancreatedAtstringupdatedAtstring
404- Not found
DELETE /api/purple-suite/dex/software_inventory/{id}
Delete software inventory entry
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Responses
200- Deleted
application/jsonsuccessboolean
404- Not found
PATCH /api/purple-suite/dex/software_inventory/{id}
Update software inventory entry
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Request body
application/json
SoftwareInventory
idstringdevice_idstringsoftware_namestringversionstringpublisherstringinstall_datestringlast_usedstringlicense_typestringis_managedbooleanis_approvedbooleancreatedAtstringupdatedAtstring
Responses
200- Updated
application/jsonSoftwareInventoryidstringdevice_idstringsoftware_namestringversionstringpublisherstringinstall_datestringlast_usedstringlicense_typestringis_managedbooleanis_approvedbooleancreatedAtstringupdatedAtstring
404- Not found
GET /api/purple-suite/dex/dex_alerts
List DEX device-health alerts (machine-generated telemetry alerts)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
limit | query | integer | no | Legacy page size (default 50). Prefer $top. Ignored when $top/$skip are used. |
cursor | query | string | no | Legacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top. |
$filter | query | string | no | 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". |
$select | query | string | no | 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. |
$orderby | query | string | no | Sort clause(s), comma-separated, each "field [asc|desc]" (asc is the default). Example: "createdAt desc, lastName asc". Null values sort last. |
$search | query | string | no | Free-text, case-insensitive substring match across the resource's searchable fields. |
$top | query | integer | no | Maximum number of items to return (page size). |
$skip | query | integer | no | Number of matching items to skip before returning results (offset paging). Combine with $top. |
$count | query | boolean | no | When true, include @odata.count (total matches after $filter/$search, before paging) in the response. |
Responses
200- Paginated list
application/jsondataarrayarray of:
DexAlertidstringdevice_idstringalert_typestringseveritystringstatusstringtitlestringdescriptionstringmetric_valuenumber — The metric reading that triggered the alertthresholdnumber — The threshold that was exceededacknowledgedbooleanacknowledged_bystringacknowledged_atstringresolved_atstringresolved_bystringresolution_notesstring — Notes recorded when the alert was resolvedcreatedAtstringupdatedAtstring
nextCursorstring — Cursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor.totalinteger — Total documents in the collection.@odata.countinteger — Present only when $count=true: total matches after $filter/$search.@odata.truncatedboolean — Present and true only when the collection exceeded the in-memory query cap and results may be incomplete.
400- Invalid OData query (e.g. malformed $filter)
POST /api/purple-suite/dex/dex_alerts
Create DEX alert
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes |
Request body
application/json — required
DexAlert
idstringdevice_idstringalert_typestringseveritystringstatusstringtitlestringdescriptionstringmetric_valuenumber — The metric reading that triggered the alertthresholdnumber — The threshold that was exceededacknowledgedbooleanacknowledged_bystringacknowledged_atstringresolved_atstringresolved_bystringresolution_notesstring — Notes recorded when the alert was resolvedcreatedAtstringupdatedAtstring
Responses
201- Created
application/jsonDexAlertidstringdevice_idstringalert_typestringseveritystringstatusstringtitlestringdescriptionstringmetric_valuenumber — The metric reading that triggered the alertthresholdnumber — The threshold that was exceededacknowledgedbooleanacknowledged_bystringacknowledged_atstringresolved_atstringresolved_bystringresolution_notesstring — Notes recorded when the alert was resolvedcreatedAtstringupdatedAtstring
GET /api/purple-suite/dex/dex_alerts/{id}
Get DEX alert
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Responses
200- Found
application/jsonDexAlertidstringdevice_idstringalert_typestringseveritystringstatusstringtitlestringdescriptionstringmetric_valuenumber — The metric reading that triggered the alertthresholdnumber — The threshold that was exceededacknowledgedbooleanacknowledged_bystringacknowledged_atstringresolved_atstringresolved_bystringresolution_notesstring — Notes recorded when the alert was resolvedcreatedAtstringupdatedAtstring
404- Not found
DELETE /api/purple-suite/dex/dex_alerts/{id}
Delete DEX alert
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Responses
200- Deleted
application/jsonsuccessboolean
404- Not found
PATCH /api/purple-suite/dex/dex_alerts/{id}
Update DEX alert
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Request body
application/json
DexAlert
idstringdevice_idstringalert_typestringseveritystringstatusstringtitlestringdescriptionstringmetric_valuenumber — The metric reading that triggered the alertthresholdnumber — The threshold that was exceededacknowledgedbooleanacknowledged_bystringacknowledged_atstringresolved_atstringresolved_bystringresolution_notesstring — Notes recorded when the alert was resolvedcreatedAtstringupdatedAtstring
Responses
200- Updated
application/jsonDexAlertidstringdevice_idstringalert_typestringseveritystringstatusstringtitlestringdescriptionstringmetric_valuenumber — The metric reading that triggered the alertthresholdnumber — The threshold that was exceededacknowledgedbooleanacknowledged_bystringacknowledged_atstringresolved_atstringresolved_bystringresolution_notesstring — Notes recorded when the alert was resolvedcreatedAtstringupdatedAtstring
404- Not found
POST /api/purple-suite/dex/dex_alerts/{id}/acknowledge
Acknowledge a DEX alert
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Request body
application/json — required
acknowledged_bystring required — Email of the person acknowledging the alert
Responses
200- Alert acknowledged
application/jsonDexAlertidstringdevice_idstringalert_typestringseveritystringstatusstringtitlestringdescriptionstringmetric_valuenumber — The metric reading that triggered the alertthresholdnumber — The threshold that was exceededacknowledgedbooleanacknowledged_bystringacknowledged_atstringresolved_atstringresolved_bystringresolution_notesstring — Notes recorded when the alert was resolvedcreatedAtstringupdatedAtstring
404- Alert not found
422- Alert already resolved or already acknowledged
POST /api/purple-suite/dex/dex_alerts/{id}/resolve
Resolve a DEX alert
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Request body
application/json — required
resolved_bystring required — Email of the person resolving the alertresolution_notesstring — Optional notes about the resolution
Responses
200- Alert resolved
application/jsonDexAlertidstringdevice_idstringalert_typestringseveritystringstatusstringtitlestringdescriptionstringmetric_valuenumber — The metric reading that triggered the alertthresholdnumber — The threshold that was exceededacknowledgedbooleanacknowledged_bystringacknowledged_atstringresolved_atstringresolved_bystringresolution_notesstring — Notes recorded when the alert was resolvedcreatedAtstringupdatedAtstring
404- Alert not found
422- Alert already resolved
GET /api/purple-suite/dex/remediations
List DEX remediation actions run against devices
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
limit | query | integer | no | Legacy page size (default 50). Prefer $top. Ignored when $top/$skip are used. |
cursor | query | string | no | Legacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top. |
$filter | query | string | no | 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". |
$select | query | string | no | 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. |
$orderby | query | string | no | Sort clause(s), comma-separated, each "field [asc|desc]" (asc is the default). Example: "createdAt desc, lastName asc". Null values sort last. |
$search | query | string | no | Free-text, case-insensitive substring match across the resource's searchable fields. |
$top | query | integer | no | Maximum number of items to return (page size). |
$skip | query | integer | no | Number of matching items to skip before returning results (offset paging). Combine with $top. |
$count | query | boolean | no | When true, include @odata.count (total matches after $filter/$search, before paging) in the response. |
Responses
200- Paginated list
application/jsondataarrayarray of:
Remediationidstringdevice_idstringaction_typestringstatusstringtarget_softwarestring — Optional: specific software targetedexecuted_bystringexecuted_atstringcompleted_atstringresultstringnotesstringcreatedAtstringupdatedAtstring
nextCursorstring — Cursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor.totalinteger — Total documents in the collection.@odata.countinteger — Present only when $count=true: total matches after $filter/$search.@odata.truncatedboolean — Present and true only when the collection exceeded the in-memory query cap and results may be incomplete.
400- Invalid OData query (e.g. malformed $filter)
POST /api/purple-suite/dex/remediations
Create remediation
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes |
Request body
application/json — required
Remediation
idstringdevice_idstringaction_typestringstatusstringtarget_softwarestring — Optional: specific software targetedexecuted_bystringexecuted_atstringcompleted_atstringresultstringnotesstringcreatedAtstringupdatedAtstring
Responses
201- Created
application/jsonRemediationidstringdevice_idstringaction_typestringstatusstringtarget_softwarestring — Optional: specific software targetedexecuted_bystringexecuted_atstringcompleted_atstringresultstringnotesstringcreatedAtstringupdatedAtstring
GET /api/purple-suite/dex/remediations/{id}
Get remediation
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Responses
200- Found
application/jsonRemediationidstringdevice_idstringaction_typestringstatusstringtarget_softwarestring — Optional: specific software targetedexecuted_bystringexecuted_atstringcompleted_atstringresultstringnotesstringcreatedAtstringupdatedAtstring
404- Not found
DELETE /api/purple-suite/dex/remediations/{id}
Delete remediation
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Responses
200- Deleted
application/jsonsuccessboolean
404- Not found
PATCH /api/purple-suite/dex/remediations/{id}
Update remediation
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Request body
application/json
Remediation
idstringdevice_idstringaction_typestringstatusstringtarget_softwarestring — Optional: specific software targetedexecuted_bystringexecuted_atstringcompleted_atstringresultstringnotesstringcreatedAtstringupdatedAtstring
Responses
200- Updated
application/jsonRemediationidstringdevice_idstringaction_typestringstatusstringtarget_softwarestring — Optional: specific software targetedexecuted_bystringexecuted_atstringcompleted_atstringresultstringnotesstringcreatedAtstringupdatedAtstring
404- Not found
POST /api/purple-suite/dex/remediations/{id}/execute
Execute a remediation
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Request body
application/json — required
executed_bystring — Email or identifier of the executor (defaults to 'system')
Responses
200- Remediation started (status = in_progress)
application/jsonRemediationidstringdevice_idstringaction_typestringstatusstringtarget_softwarestring — Optional: specific software targetedexecuted_bystringexecuted_atstringcompleted_atstringresultstringnotesstringcreatedAtstringupdatedAtstring
404- Remediation not found
422- Remediation already completed or already in_progress
POST /api/purple-suite/dex/remediations/{id}/complete
Mark a remediation as complete
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Request body
application/json — required
resultstring — Outcome description (defaults to 'success')
Responses
200- Remediation completed
application/jsonRemediationidstringdevice_idstringaction_typestringstatusstringtarget_softwarestring — Optional: specific software targetedexecuted_bystringexecuted_atstringcompleted_atstringresultstringnotesstringcreatedAtstringupdatedAtstring
404- Remediation not found
422- Remediation is not in_progress (must execute first)
GET /api/purple-suite/dex/experience_scores
List DEX digital-experience scores (0–10) per device and user
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
limit | query | integer | no | Legacy page size (default 50). Prefer $top. Ignored when $top/$skip are used. |
cursor | query | string | no | Legacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top. |
$filter | query | string | no | 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". |
$select | query | string | no | 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. |
$orderby | query | string | no | Sort clause(s), comma-separated, each "field [asc|desc]" (asc is the default). Example: "createdAt desc, lastName asc". Null values sort last. |
$search | query | string | no | Free-text, case-insensitive substring match across the resource's searchable fields. |
$top | query | integer | no | Maximum number of items to return (page size). |
$skip | query | integer | no | Number of matching items to skip before returning results (offset paging). Combine with $top. |
$count | query | boolean | no | When true, include @odata.count (total matches after $filter/$search, before paging) in the response. |
Responses
200- Paginated list
application/jsondataarrayarray of:
ExperienceScoreidstringdevice_idstringuser_emailstringoverall_scorenumberboot_time_scorenumberresponsiveness_scorenumbernetwork_scorenumberstability_scorenumberbattery_scorenumbermeasured_atstringboot_time_secondsnumberavg_app_crash_countnumberavg_response_time_msnumbercreatedAtstringupdatedAtstring
nextCursorstring — Cursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor.totalinteger — Total documents in the collection.@odata.countinteger — Present only when $count=true: total matches after $filter/$search.@odata.truncatedboolean — Present and true only when the collection exceeded the in-memory query cap and results may be incomplete.
400- Invalid OData query (e.g. malformed $filter)
POST /api/purple-suite/dex/experience_scores
Create experience score
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes |
Request body
application/json — required
ExperienceScore
idstringdevice_idstringuser_emailstringoverall_scorenumberboot_time_scorenumberresponsiveness_scorenumbernetwork_scorenumberstability_scorenumberbattery_scorenumbermeasured_atstringboot_time_secondsnumberavg_app_crash_countnumberavg_response_time_msnumbercreatedAtstringupdatedAtstring
Responses
201- Created
application/jsonExperienceScoreidstringdevice_idstringuser_emailstringoverall_scorenumberboot_time_scorenumberresponsiveness_scorenumbernetwork_scorenumberstability_scorenumberbattery_scorenumbermeasured_atstringboot_time_secondsnumberavg_app_crash_countnumberavg_response_time_msnumbercreatedAtstringupdatedAtstring
GET /api/purple-suite/dex/experience_scores/{id}
Get experience score
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Responses
200- Found
application/jsonExperienceScoreidstringdevice_idstringuser_emailstringoverall_scorenumberboot_time_scorenumberresponsiveness_scorenumbernetwork_scorenumberstability_scorenumberbattery_scorenumbermeasured_atstringboot_time_secondsnumberavg_app_crash_countnumberavg_response_time_msnumbercreatedAtstringupdatedAtstring
404- Not found
DELETE /api/purple-suite/dex/experience_scores/{id}
Delete experience score
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Responses
200- Deleted
application/jsonsuccessboolean
404- Not found
PATCH /api/purple-suite/dex/experience_scores/{id}
Update experience score
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Request body
application/json
ExperienceScore
idstringdevice_idstringuser_emailstringoverall_scorenumberboot_time_scorenumberresponsiveness_scorenumbernetwork_scorenumberstability_scorenumberbattery_scorenumbermeasured_atstringboot_time_secondsnumberavg_app_crash_countnumberavg_response_time_msnumbercreatedAtstringupdatedAtstring
Responses
200- Updated
application/jsonExperienceScoreidstringdevice_idstringuser_emailstringoverall_scorenumberboot_time_scorenumberresponsiveness_scorenumbernetwork_scorenumberstability_scorenumberbattery_scorenumbermeasured_atstringboot_time_secondsnumberavg_app_crash_countnumberavg_response_time_msnumbercreatedAtstringupdatedAtstring
404- Not found
GET /api/purple-suite/dex/dex_campaigns
List DEX IT campaigns (fleet patch, rollout and compliance sweeps)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
limit | query | integer | no | Legacy page size (default 50). Prefer $top. Ignored when $top/$skip are used. |
cursor | query | string | no | Legacy keyset cursor — pass the previous response's nextCursor. Prefer $skip/$top. |
$filter | query | string | no | 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". |
$select | query | string | no | 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. |
$orderby | query | string | no | Sort clause(s), comma-separated, each "field [asc|desc]" (asc is the default). Example: "createdAt desc, lastName asc". Null values sort last. |
$search | query | string | no | Free-text, case-insensitive substring match across the resource's searchable fields. |
$top | query | integer | no | Maximum number of items to return (page size). |
$skip | query | integer | no | Number of matching items to skip before returning results (offset paging). Combine with $top. |
$count | query | boolean | no | When true, include @odata.count (total matches after $filter/$search, before paging) in the response. |
Responses
200- Paginated list
application/jsondataarrayarray of:
Campaignidstringnamestringdescriptionstringcampaign_typestringstatusstringtarget_criteriaobject — Filter criteria for targeted devices (e.g. OS, department)total_devicesintegercompleted_devicesintegerfailed_devicesintegerlaunched_atstringlaunched_bystringcreated_bystringcreatedAtstringupdatedAtstring
nextCursorstring — Cursor for the next page, or null on the last page. With $top/$skip this is the next $skip value; otherwise a keyset cursor.totalinteger — Total documents in the collection.@odata.countinteger — Present only when $count=true: total matches after $filter/$search.@odata.truncatedboolean — Present and true only when the collection exceeded the in-memory query cap and results may be incomplete.
400- Invalid OData query (e.g. malformed $filter)
POST /api/purple-suite/dex/dex_campaigns
Create DEX campaign
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes |
Request body
application/json — required
Campaign
idstringnamestringdescriptionstringcampaign_typestringstatusstringtarget_criteriaobject — Filter criteria for targeted devices (e.g. OS, department)total_devicesintegercompleted_devicesintegerfailed_devicesintegerlaunched_atstringlaunched_bystringcreated_bystringcreatedAtstringupdatedAtstring
Responses
201- Created
application/jsonCampaignidstringnamestringdescriptionstringcampaign_typestringstatusstringtarget_criteriaobject — Filter criteria for targeted devices (e.g. OS, department)total_devicesintegercompleted_devicesintegerfailed_devicesintegerlaunched_atstringlaunched_bystringcreated_bystringcreatedAtstringupdatedAtstring
GET /api/purple-suite/dex/dex_campaigns/{id}
Get DEX campaign
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Responses
200- Found
application/jsonCampaignidstringnamestringdescriptionstringcampaign_typestringstatusstringtarget_criteriaobject — Filter criteria for targeted devices (e.g. OS, department)total_devicesintegercompleted_devicesintegerfailed_devicesintegerlaunched_atstringlaunched_bystringcreated_bystringcreatedAtstringupdatedAtstring
404- Not found
DELETE /api/purple-suite/dex/dex_campaigns/{id}
Delete DEX campaign
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Responses
200- Deleted
application/jsonsuccessboolean
404- Not found
PATCH /api/purple-suite/dex/dex_campaigns/{id}
Update DEX campaign
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Request body
application/json
Campaign
idstringnamestringdescriptionstringcampaign_typestringstatusstringtarget_criteriaobject — Filter criteria for targeted devices (e.g. OS, department)total_devicesintegercompleted_devicesintegerfailed_devicesintegerlaunched_atstringlaunched_bystringcreated_bystringcreatedAtstringupdatedAtstring
Responses
200- Updated
application/jsonCampaignidstringnamestringdescriptionstringcampaign_typestringstatusstringtarget_criteriaobject — Filter criteria for targeted devices (e.g. OS, department)total_devicesintegercompleted_devicesintegerfailed_devicesintegerlaunched_atstringlaunched_bystringcreated_bystringcreatedAtstringupdatedAtstring
404- Not found
POST /api/purple-suite/dex/dex_campaigns/{id}/launch
Launch a DEX campaign
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
X-Instance-ID | header | string | yes | |
id | path | string | yes |
Request body
application/json — required
launched_bystring — Email or identifier of the person launching the campaign (defaults to 'system')
Responses
200- Campaign launched (status = active)
application/jsonCampaignidstringnamestringdescriptionstringcampaign_typestringstatusstringtarget_criteriaobject — Filter criteria for targeted devices (e.g. OS, department)total_devicesintegercompleted_devicesintegerfailed_devicesintegerlaunched_atstringlaunched_bystringcreated_bystringcreatedAtstringupdatedAtstring
404- Campaign not found
422- Campaign already active or already completed