Practical, copy-paste GraphQL recipes for common Jamf Protect tasks.
This page shows what you can do with the Jamf Protect API through practical, copy-paste examples. Every query and mutation below is valid against the current schema.
All requests are a single POST to the Protect GraphQL endpoint through the Platform API Gateway, with a Bearer token in the Authorization header and your scope context in a header: your tenant ID in X-Tenant-Id for a tenant-scoped integration, or your environment ID in X-Environment-Id for a platform environment-scoped one. See the overview for how to create an integration and obtain a token.
{region} is us, eu, or apac, matching the region your Protect tenant is hosted in.
How to send a query
Wrap any GraphQL query in a JSON body under the query key and POST it:
curl --header "Content-Type: application/json" \
--header "Authorization: Bearer <ACCESS-TOKEN>" \
--header "X-Tenant-Id: <YOUR-TENANT-ID>" \
--request POST \
--url "https://{region}.api.jamfcloud.com/protect" \
--data '{"query": "query { listComputers(input: { pageSize: 5 }) { items { hostName uuid } } }"}'Each operation also requires a capability permission on your integration. For example, listComputers requires devices:read. The overview has the full operation-to-permission table.
Each example below comes in two parts:
- A GraphQL block, which is the query or mutation itself. This is the actual operation in GraphQL's query language: it describes exactly the data you're asking for (and the fields you want back). Paste it into a GraphQL client such as Altair or Apollo Sandbox, or into the
queryfield of the request above. - A cURL / Python block, with runnable examples that take that same query and send it to the endpoint over HTTP. Switch tabs to see each language.
So: the GraphQL block is what you're requesting; the cURL and Python tabs are how to send it.
Reading data
List enrolled computers
Return a page of computers with basic hardware and OS details.
query ListComputers {
listComputers(input: { pageSize: 25 }) {
items {
uuid
hostName
serial
osString
modelName
checkin
connectionStatus
}
pageInfo {
next
total
}
}
}Send that query over HTTP. Switch tabs for cURL or Python:
curl --request POST \
--url "https://{region}.api.jamfcloud.com/protect" \
--header "Authorization: Bearer <ACCESS-TOKEN>" \
--header "X-Tenant-Id: <YOUR-TENANT-ID>" \
--header "Content-Type: application/json" \
--data '{"query":"query ListComputers { listComputers(input: { pageSize: 25 }) { items { uuid hostName serial osString modelName checkin connectionStatus } pageInfo { next total } } }"}'import requests
resp = requests.post(
"https://{region}.api.jamfcloud.com/protect",
headers={
"Authorization": "Bearer <ACCESS-TOKEN>",
"X-Tenant-Id": "<YOUR-TENANT-ID>",
"Content-Type": "application/json",
},
json={"query": """
query ListComputers {
listComputers(input: { pageSize: 25 }) {
items {
uuid
hostName
serial
osString
modelName
checkin
connectionStatus
}
pageInfo {
next
total
}
}
}
"""},
)
resp.raise_for_status()
print(resp.json())Paginate through results
Every list returns a pageInfo.next cursor. Pass it back as next to fetch the following page; when next is null, you've reached the end.
query NextPageOfComputers {
listComputers(input: { pageSize: 50, next: "PASTE_PAGEINFO_NEXT_CURSOR" }) {
items {
uuid
hostName
}
pageInfo {
next
total
}
}
}Send that query over HTTP. Switch tabs for cURL or Python:
curl --request POST \
--url "https://{region}.api.jamfcloud.com/protect" \
--header "Authorization: Bearer <ACCESS-TOKEN>" \
--header "X-Tenant-Id: <YOUR-TENANT-ID>" \
--header "Content-Type: application/json" \
--data '{"query":"query NextPageOfComputers { listComputers(input: { pageSize: 50, next: \"PASTE_PAGEINFO_NEXT_CURSOR\" }) { items { uuid hostName } pageInfo { next total } } }"}'import requests
resp = requests.post(
"https://{region}.api.jamfcloud.com/protect",
headers={
"Authorization": "Bearer <ACCESS-TOKEN>",
"X-Tenant-Id": "<YOUR-TENANT-ID>",
"Content-Type": "application/json",
},
json={"query": """
query NextPageOfComputers {
listComputers(input: { pageSize: 50, next: "PASTE_PAGEINFO_NEXT_CURSOR" }) {
items {
uuid
hostName
}
pageInfo {
next
total
}
}
}
"""},
)
resp.raise_for_status()
print(resp.json())Find high-severity, unresolved alerts
Filter and sort server-side. This returns new (unresolved) High-severity alerts, newest first, with the affected computer inlined.
query HighSeverityOpenAlerts {
listAlerts(input: {
pageSize: 25
filter: {
severity: { equals: High }
status: { equals: "New" }
}
order: { field: created, direction: DESC }
}) {
items {
uuid
created
severity
status
eventType
computer {
hostName
serial
}
}
pageInfo {
next
total
}
}
}Send that query over HTTP. Switch tabs for cURL or Python:
curl --request POST \
--url "https://{region}.api.jamfcloud.com/protect" \
--header "Authorization: Bearer <ACCESS-TOKEN>" \
--header "X-Tenant-Id: <YOUR-TENANT-ID>" \
--header "Content-Type: application/json" \
--data '{"query":"query HighSeverityOpenAlerts { listAlerts(input: { pageSize: 25 filter: { severity: { equals: High } status: { equals: \"New\" } } order: { field: created, direction: DESC } }) { items { uuid created severity status eventType computer { hostName serial } } pageInfo { next total } } }"}'import requests
resp = requests.post(
"https://{region}.api.jamfcloud.com/protect",
headers={
"Authorization": "Bearer <ACCESS-TOKEN>",
"X-Tenant-Id": "<YOUR-TENANT-ID>",
"Content-Type": "application/json",
},
json={"query": """
query HighSeverityOpenAlerts {
listAlerts(input: {
pageSize: 25
filter: {
severity: { equals: High }
status: { equals: "New" }
}
order: { field: created, direction: DESC }
}) {
items {
uuid
created
severity
status
eventType
computer {
hostName
serial
}
}
pageInfo {
next
total
}
}
}
"""},
)
resp.raise_for_status()
print(resp.json())Filters compose with and / or / not, and support operators like equals, contains, in, greaterThan, and beforeInterval / afterInterval for dates. For example, alerts from the last 24 hours on a specific plan:
query RecentAlertsForPlan {
listAlerts(input: {
pageSize: 50
filter: {
and: [
{ created: { afterInterval: "PT24H" } },
{ plan: { equals: "PLAN-ID" } }
]
}
}) {
items {
uuid
created
severity
eventType
}
}
}Send that query over HTTP. Switch tabs for cURL or Python:
curl --request POST \
--url "https://{region}.api.jamfcloud.com/protect" \
--header "Authorization: Bearer <ACCESS-TOKEN>" \
--header "X-Tenant-Id: <YOUR-TENANT-ID>" \
--header "Content-Type: application/json" \
--data '{"query":"query RecentAlertsForPlan { listAlerts(input: { pageSize: 50 filter: { and: [ { created: { afterInterval: \"PT24H\" } }, { plan: { equals: \"PLAN-ID\" } } ] } }) { items { uuid created severity eventType } } }"}'import requests
resp = requests.post(
"https://{region}.api.jamfcloud.com/protect",
headers={
"Authorization": "Bearer <ACCESS-TOKEN>",
"X-Tenant-Id": "<YOUR-TENANT-ID>",
"Content-Type": "application/json",
},
json={"query": """
query RecentAlertsForPlan {
listAlerts(input: {
pageSize: 50
filter: {
and: [
{ created: { afterInterval: "PT24H" } },
{ plan: { equals: "PLAN-ID" } }
]
}
}) {
items {
uuid
created
severity
eventType
}
}
}
"""},
)
resp.raise_for_status()
print(resp.json())Get a single alert with full detail
Look up one alert by UUID, including the raw event payload (json).
query GetAlert {
getAlert(uuid: "6f250316-2cfb-4521-8cb7-bfaf46497bc5") {
uuid
severity
status
eventType
created
tags
computer {
hostName
serial
osString
}
json
}
}Send that query over HTTP. Switch tabs for cURL or Python:
curl --request POST \
--url "https://{region}.api.jamfcloud.com/protect" \
--header "Authorization: Bearer <ACCESS-TOKEN>" \
--header "X-Tenant-Id: <YOUR-TENANT-ID>" \
--header "Content-Type: application/json" \
--data '{"query":"query GetAlert { getAlert(uuid: \"6f250316-2cfb-4521-8cb7-bfaf46497bc5\") { uuid severity status eventType created tags computer { hostName serial osString } json } }"}'import requests
resp = requests.post(
"https://{region}.api.jamfcloud.com/protect",
headers={
"Authorization": "Bearer <ACCESS-TOKEN>",
"X-Tenant-Id": "<YOUR-TENANT-ID>",
"Content-Type": "application/json",
},
json={"query": """
query GetAlert {
getAlert(uuid: "6f250316-2cfb-4521-8cb7-bfaf46497bc5") {
uuid
severity
status
eventType
created
tags
computer {
hostName
serial
osString
}
json
}
}
"""},
)
resp.raise_for_status()
print(resp.json())Pull a compliance / insights scorecard
Each computer carries insight (compliance) pass/fail counts and posture fields, which are useful for a fleet compliance overview.
query ComplianceOverview {
listComputers(input: { pageSize: 100 }) {
items {
hostName
serial
insightsStatsPass
insightsStatsFail
insightsStatsUnknown
fullDiskAccess
webProtectionActive
insightsUpdated
}
pageInfo {
total
}
}
}Send that query over HTTP. Switch tabs for cURL or Python:
curl --request POST \
--url "https://{region}.api.jamfcloud.com/protect" \
--header "Authorization: Bearer <ACCESS-TOKEN>" \
--header "X-Tenant-Id: <YOUR-TENANT-ID>" \
--header "Content-Type: application/json" \
--data '{"query":"query ComplianceOverview { listComputers(input: { pageSize: 100 }) { items { hostName serial insightsStatsPass insightsStatsFail insightsStatsUnknown fullDiskAccess webProtectionActive insightsUpdated } pageInfo { total } } }"}'import requests
resp = requests.post(
"https://{region}.api.jamfcloud.com/protect",
headers={
"Authorization": "Bearer <ACCESS-TOKEN>",
"X-Tenant-Id": "<YOUR-TENANT-ID>",
"Content-Type": "application/json",
},
json={"query": """
query ComplianceOverview {
listComputers(input: { pageSize: 100 }) {
items {
hostName
serial
insightsStatsPass
insightsStatsFail
insightsStatsUnknown
fullDiskAccess
webProtectionActive
insightsUpdated
}
pageInfo {
total
}
}
}
"""},
)
resp.raise_for_status()
print(resp.json())Browse the analytics (detection) catalog
List the analytics available in your tenant, including severity and category.
query DetectionCatalog {
listAnalytics {
items {
uuid
name
severity
categories
description
}
}
}Send that query over HTTP. Switch tabs for cURL or Python:
curl --request POST \
--url "https://{region}.api.jamfcloud.com/protect" \
--header "Authorization: Bearer <ACCESS-TOKEN>" \
--header "X-Tenant-Id: <YOUR-TENANT-ID>" \
--header "Content-Type: application/json" \
--data '{"query":"query DetectionCatalog { listAnalytics { items { uuid name severity categories description } } }"}'import requests
resp = requests.post(
"https://{region}.api.jamfcloud.com/protect",
headers={
"Authorization": "Bearer <ACCESS-TOKEN>",
"X-Tenant-Id": "<YOUR-TENANT-ID>",
"Content-Type": "application/json",
},
json={"query": """
query DetectionCatalog {
listAnalytics {
items {
uuid
name
severity
categories
description
}
}
}
"""},
)
resp.raise_for_status()
print(resp.json())Inspect a plan and its analytics
query PlanDetail {
getPlan(id: "1") {
id
name
description
logLevel
analytics {
name
severity
}
}
}Send that query over HTTP. Switch tabs for cURL or Python:
curl --request POST \
--url "https://{region}.api.jamfcloud.com/protect" \
--header "Authorization: Bearer <ACCESS-TOKEN>" \
--header "X-Tenant-Id: <YOUR-TENANT-ID>" \
--header "Content-Type: application/json" \
--data '{"query":"query PlanDetail { getPlan(id: \"1\") { id name description logLevel analytics { name severity } } }"}'import requests
resp = requests.post(
"https://{region}.api.jamfcloud.com/protect",
headers={
"Authorization": "Bearer <ACCESS-TOKEN>",
"X-Tenant-Id": "<YOUR-TENANT-ID>",
"Content-Type": "application/json",
},
json={"query": """
query PlanDetail {
getPlan(id: "1") {
id
name
description
logLevel
analytics {
name
severity
}
}
}
"""},
)
resp.raise_for_status()
print(resp.json())Review audit logs by user
See recent administrative actions, most recent first.
query RecentUserActivity {
listAuditLogsByUser(input: { pageSize: 25 }) {
items {
date
user
op
resourceId
ips
}
pageInfo {
next
}
}
}Send that query over HTTP. Switch tabs for cURL or Python:
curl --request POST \
--url "https://{region}.api.jamfcloud.com/protect" \
--header "Authorization: Bearer <ACCESS-TOKEN>" \
--header "X-Tenant-Id: <YOUR-TENANT-ID>" \
--header "Content-Type: application/json" \
--data '{"query":"query RecentUserActivity { listAuditLogsByUser(input: { pageSize: 25 }) { items { date user op resourceId ips } pageInfo { next } } }"}'import requests
resp = requests.post(
"https://{region}.api.jamfcloud.com/protect",
headers={
"Authorization": "Bearer <ACCESS-TOKEN>",
"X-Tenant-Id": "<YOUR-TENANT-ID>",
"Content-Type": "application/json",
},
json={"query": """
query RecentUserActivity {
listAuditLogsByUser(input: { pageSize: 25 }) {
items {
date
user
op
resourceId
ips
}
pageInfo {
next
}
}
}
"""},
)
resp.raise_for_status()
print(resp.json())Making changes (mutations)
Resolve one or more alerts
Update the status of a batch of alerts by UUID.
mutation ResolveAlerts {
updateAlerts(input: {
uuids: ["6f250316-2cfb-4521-8cb7-bfaf46497bc5"]
status: Resolved
}) {
items {
uuid
status
updated
}
}
}Send that query over HTTP. Switch tabs for cURL or Python:
curl --request POST \
--url "https://{region}.api.jamfcloud.com/protect" \
--header "Authorization: Bearer <ACCESS-TOKEN>" \
--header "X-Tenant-Id: <YOUR-TENANT-ID>" \
--header "Content-Type: application/json" \
--data '{"query":"mutation ResolveAlerts { updateAlerts(input: { uuids: [\"6f250316-2cfb-4521-8cb7-bfaf46497bc5\"] status: Resolved }) { items { uuid status updated } } }"}'import requests
resp = requests.post(
"https://{region}.api.jamfcloud.com/protect",
headers={
"Authorization": "Bearer <ACCESS-TOKEN>",
"X-Tenant-Id": "<YOUR-TENANT-ID>",
"Content-Type": "application/json",
},
json={"query": """
mutation ResolveAlerts {
updateAlerts(input: {
uuids: ["6f250316-2cfb-4521-8cb7-bfaf46497bc5"]
status: Resolved
}) {
items {
uuid
status
updated
}
}
}
"""},
)
resp.raise_for_status()
print(resp.json())Valid status values are New, InProgress, Resolved, and AutoResolved.
Assign a computer to a plan
mutation AssignComputerToPlan {
setComputerPlan(uuid: "COMPUTER-UUID", input: { plan: "PLAN-ID" }) {
uuid
hostName
plan {
id
name
}
}
}Send that query over HTTP. Switch tabs for cURL or Python:
curl --request POST \
--url "https://{region}.api.jamfcloud.com/protect" \
--header "Authorization: Bearer <ACCESS-TOKEN>" \
--header "X-Tenant-Id: <YOUR-TENANT-ID>" \
--header "Content-Type: application/json" \
--data '{"query":"mutation AssignComputerToPlan { setComputerPlan(uuid: \"COMPUTER-UUID\", input: { plan: \"PLAN-ID\" }) { uuid hostName plan { id name } } }"}'import requests
resp = requests.post(
"https://{region}.api.jamfcloud.com/protect",
headers={
"Authorization": "Bearer <ACCESS-TOKEN>",
"X-Tenant-Id": "<YOUR-TENANT-ID>",
"Content-Type": "application/json",
},
json={"query": """
mutation AssignComputerToPlan {
setComputerPlan(uuid: "COMPUTER-UUID", input: { plan: "PLAN-ID" }) {
uuid
hostName
plan {
id
name
}
}
}
"""},
)
resp.raise_for_status()
print(resp.json())Create a prevent list (block execution)
Block by Team ID, file hash, CDHash, or signing ID. This example blocks a specific developer Team ID.
mutation BlockByTeamId {
createPreventList(input: {
name: "Blocked developers"
type: TEAMID
list: ["ABCDE12345"]
tags: []
description: "Team IDs blocked from execution"
}) {
id
name
type
list
count
}
}Send that query over HTTP. Switch tabs for cURL or Python:
curl --request POST \
--url "https://{region}.api.jamfcloud.com/protect" \
--header "Authorization: Bearer <ACCESS-TOKEN>" \
--header "X-Tenant-Id: <YOUR-TENANT-ID>" \
--header "Content-Type: application/json" \
--data '{"query":"mutation BlockByTeamId { createPreventList(input: { name: \"Blocked developers\" type: TEAMID list: [\"ABCDE12345\"] tags: [] description: \"Team IDs blocked from execution\" }) { id name type list count } }"}'import requests
resp = requests.post(
"https://{region}.api.jamfcloud.com/protect",
headers={
"Authorization": "Bearer <ACCESS-TOKEN>",
"X-Tenant-Id": "<YOUR-TENANT-ID>",
"Content-Type": "application/json",
},
json={"query": """
mutation BlockByTeamId {
createPreventList(input: {
name: "Blocked developers"
type: TEAMID
list: ["ABCDE12345"]
tags: []
description: "Team IDs blocked from execution"
}) {
id
name
type
list
count
}
}
"""},
)
resp.raise_for_status()
print(resp.json())Supported type values: TEAMID, FILEHASH, CDHASH, SIGNINGID.
Using variables
For production code, prefer GraphQL variables over string interpolation. Send query and variables in the request body:
{
"query": "query Alerts($input: AlertQueryInput!) { listAlerts(input: $input) { items { uuid severity } pageInfo { next } } }",
"variables": {
"input": {
"pageSize": 25,
"filter": { "severity": { "equals": "High" } }
}
}
}
These examples are grounded in the live Jamf Protect schema. See the Queries, Mutations, and Types pages for the complete field reference.
Jamf Protect API: Overview · Queries · Mutations · Types · Example Calls