Authentication, scope levels, regions, permissions, pagination, and errors. These apply to every API behind the Platform API Gateway.
Overview
One integration, one token, one permission model, and one set of request conventions cover every API behind the Platform API Gateway.
This page covers the shared mechanics. Individual API pages cover what is specific to them, such as resource paths and required permissions.
| Topic | What it covers |
|---|---|
| Authentication | Getting and using an access token |
| Scope levels | Organization, platform environment, and tenant |
| Regions and data residency | Which host to call, and where your data lives |
| Request context | The headers that identify your tenant or environment |
| Capability permissions | How permissions are named and granted |
| Pagination, sorting, and filtering | Working through collections |
| Errors | Status codes and what they mean |
| Versioning | How API versions appear in paths |
To create an integration and make a first call, see Getting started.
Authentication
The gateway uses OAuth 2.0 client credentials across its entire surface. You create an integration in Jamf Account, exchange its client ID and secret for a short-lived access token, and send that token with every request.
Client credentials
Every integration you create in Jamf Account holds a client_id and a client_secret. Treat the secret like a password:
- It appears once, at creation. Store it in a secrets manager immediately.
- Regenerating the secret is the only way to replace a lost one.
- Integrations are valid for six months. Build rotation into your deployment process.
Use the client_secret_post client authentication method, sending credentials in the request body as form fields.
Request an access token
Send a POST to the token endpoint with Content-Type: application/x-www-form-urlencoded:
curl --request POST \
--url https://us.api.jamfcloud.com/auth/token \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_id=<your_client_ID>' \
--data-urlencode 'client_secret=<your_client_secret>'| Parameter | Value |
|---|---|
grant_type | client_credentials |
client_id | Your integration's client ID |
client_secret | Your integration's client secret |
A successful request returns:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_in": 900,
"refresh_expires_in": 0,
"token_type": "Bearer",
"not-before-policy": 0
}Token lifetime
Access tokens are valid for 900 seconds (15 minutes). refresh_expires_in is 0, so when a token expires you request a new one with the same client credentials.
For anything long-running, refresh on a timer based on expires_in. A 15-minute token expires partway through a large pagination loop.
Use the token
Pass the token as a Bearer token in the Authorization header:
Authorization: Bearer <your_access_token>
Scope levels
Every integration is scoped to one level, chosen when you create it. That level applies to every token the integration issues, and it decides which APIs you can reach and which permissions are available to grant.
| Scope level | What it reaches |
|---|---|
| Organization management | Jamf Account APIs: audit events, licensing, partner operations such as deal registration and distributor actions, and SSO configuration |
| Platform environment | Platform APIs, plus the product APIs of the tenants inside that environment |
| Tenant | Product APIs for the specific instances you select |
Platform APIs available at environment scope: blueprints, compliance benchmarks, devices, device groups, device actions, declaration reporting, audit events, and AI policies.
Product APIs available at tenant scope: Jamf Pro, including the Classic API, along with Jamf Protect and Jamf Security Cloud.
A platform environment is a defined group of tenants that your organization has across the Jamf platform. It links resources and capabilities across products, which is why platform APIs work at that level.
Jamf groups most organizations' tenants into an environment automatically, based on how your organization is set up, so no action is needed. Some organizations include tenants purchased or set up in a way that doesn't map cleanly to one environment; those organizations can group tenants manually in the platform environments UI in Jamf Account. If a tenant doesn't appear in your environments at all, contact Jamf Support.
Choosing a level
Pick platform environment for cross-product workflows. The platform APIs and the shared capability model are available at this level.
Pick tenant to confine an integration to one product's data. Capability permissions span products, so tenant scope is what draws that boundary.
Pick organization management for account administration across your whole organization.
An environment-scoped token carries no tenant ID claim, so product APIs that resolve their context from that claim require a tenant-scoped integration. If a product endpoint returns
403under an environment-scoped token, create one scoped to the tenant.
Regions and data residency
The gateway is deployed in three regions. Which host you call depends on your scope level and the region your product instances are hosted in.
| Scope level | Base URL |
|---|---|
| Organization management | https://api.jamfcloud.com |
| Platform environment | https://{region}.api.jamfcloud.com |
| Tenant | https://{region}.api.jamfcloud.com |
{region} is one of:
| Region | Covers |
|---|---|
us | United States |
eu | Europe |
apac | Asia Pacific |
Organization management uses the bare host, which always routes to the US region.
Tokens are region-locked
Request your token from the same host you send API requests to. A token issued by the US endpoint returns 401 at the EU endpoint, and the same applies in reverse.
| Scope level | Token endpoint |
|---|---|
| Organization management | https://api.jamfcloud.com/auth/token |
| Platform environment | https://{region}.api.jamfcloud.com/auth/token |
| Tenant | https://{region}.api.jamfcloud.com/auth/token |
Product availability by region
Most APIs are available in all three regions. One exception applies:
| Product | Regional availability |
|---|---|
| Jamf Security Cloud | Commercial customers in us, eu, and apac. Education customers in eu and apac. |
US-hosted Jamf Safe Internet tenants, which some education customers use for data residency, are outside the supported set for gateway integrations.
Request context
Your token identifies your organization. For environment-scoped and tenant-scoped requests, name the context explicitly in a header:
| Header | Send it for | Value |
|---|---|---|
X-Tenant-Id | Tenant-scoped requests | The UUID of the product instance |
X-Environment-Id | Platform environment-scoped requests | The UUID of the platform environment |
| None | Organization management requests | The organization comes from the token |
Copy either ID from the Integration details panel in Jamf Account by clicking the relevant pill.
This changed at GA. During the public beta, tenant and environment IDs were path segments (
/tenant/{tenantId}/). Production accepts the header form only. If you built against the beta, see Updating your Jamf Pro integrations.
Capability permissions
Permissions are organized by capability, meaning what you are trying to do. devices is one capability spanning the whole platform, so it covers device inventory in every product at once. The full permission surface appears in one list.
Format
{capability}:{action}
The capability comes first in kebab-case, followed by the action in lowercase.
| Permission | Grants |
|---|---|
devices:read | Read device inventory |
devices:update | Modify device records |
blueprints:deploy | Deploy a blueprint |
device-groups:read | Read device groups |
destructive-device-actions:execute | Erase a device, unmanage it, or remove its MDM profile |
audit:read | Read audit events |
Actions
The gateway supports six actions. Actions are lowercase and case-sensitive.
| Action | Meaning |
|---|---|
create | Create a new resource |
read | Retrieve a resource |
update | Modify an existing resource |
delete | Remove a resource |
deploy | Push a configuration to devices |
execute | Run an action or command |
Grant every action your integration uses.
devices:updatecovers writes only. Adddevices:readif your integration reads a record before modifying it. Some endpoints require two capabilities together.
Each API's reference pages list the permissions their operations require. For the full capability list and the old-to-new privilege mapping, see the Jamf Pro permissions map.
Pagination, sorting, and filtering
Collection endpoints are paginated and accept the same query parameters.
| Parameter | Default | Notes |
|---|---|---|
page | 0 | Zero-based |
page-size | 100 | Minimum 1. Some APIs declare a maximum, so check the endpoint's reference page |
sort | Varies by API | Comma-separated, with :desc for descending, e.g. model:desc,name |
filter | Empty, meaning all results | RSQL expression |
Filtering with RSQL
The filter parameter takes an RSQL expression. Each endpoint's reference page lists the fields it allows in a query, and dates use ISO 8601 format.
filter=name=="*iPhone*" and lastInventoryUpdateTime>="2026-01-31T18:09:00.000Z"
Comparison operators:
| Operator | Meaning |
|---|---|
== | Equals. An asterisk acts as a wildcard, as in name=="*iPhone*" |
!= | Not equals, and it also accepts wildcards |
=lt= or < | Less than |
=le= or <= | Less than or equal to |
=gt= or > | Greater than |
=ge= or >= | Greater than or equal to |
=in= | Matches any value in a list, as in model=in=(ValueA,ValueB) |
=out= | Excludes every value in a list |
String comparisons are case-insensitive. Arguments containing spaces need quoting, single and double quotes work interchangeably as long as you stay consistent, and a backslash escapes special characters. Null values fall outside every comparison, while empty strings are included.
Combine clauses with and:
filter=deviceType=="MOBILE" and name=="*Managed*"
Response envelopes
Paginated responses on the platform APIs carry full metadata:
{
"page": 0,
"pageSize": 100,
"totalCount": 4213,
"totalPages": 43,
"hasNext": true,
"hasPrevious": false,
"results": []
}Some product APIs return a smaller envelope, such as totalCount and results only. Check the reference page for the endpoint you are calling to confirm its shape.
A 15-minute token expires partway through a large pagination loop. Refresh on a timer based on
expires_in.
Errors
Two responses have gateway-specific behavior.
| Status | What it means |
|---|---|
401 Unauthorized | The token expired, is malformed, or came from a different region than the endpoint you called |
403 Forbidden | The integration lacks a capability permission, the API requires a different scope level, or the version segment is unrecognized |
Reading a 403
The gateway returns 403 for three separate conditions. Check them in this order:
- Check your permissions. Compare the capability the endpoint requires against what your integration was granted in Jamf Account.
- Check your scope level. Platform APIs need environment scope, and some product APIs need tenant scope.
- Check the version segment in your path. Unrecognized versions return
403by design, to avoid confirming which paths exist.
A typo in a version segment therefore returns 403 rather than 404.
Versioning
Every endpoint path carries a version segment:
/{api}/v{n}/{resource-path}
The version is required. Each API versions independently, and the move to general availability left every existing version in place, so beta integrations keep the version numbers they already use.
Related articles
- Getting started: create an integration and make your first call
- Updating your Jamf Pro integrations: moving existing Jamf Pro and Classic API code onto the gateway
- Jamf Pro permissions map: privilege names to capability equivalents