Skip to main content

Public APIs - Device and evidence retrieval

Overview

On the settings page, you can retrieve your organization API token to pull Swif data into 3rd party platform.

For general patterns and examples of using Swif APIs, see:
​APIs – Manage Employees

For retrieving device applications, see:
​APIs – Device Application Retrieval

For retrieving device browser extensions, see:
​APIs – Device Extensions

For APIs – Team Installer Retrieval, see:
​APIs – Team Installer Retrieval.

Migration and Performance Optimization

As of August 2026, the applicationInfo and extension field has been removed from the main Device Inventory API (GET /restful/organization/devices) to significantly improve performance and reduce payload sizes.

If your existing integration relies on application data, you will need to update your workflow as follows:

  1. Retrieve Device IDs: Continue using the /devices endpoint to get your list of managed devices.

  2. Fetch Applications Individually: Use the id from the device record to call the new dedicated endpoint:

    1. Device Application Retrieval
      ​/restful/organization/devices/:deviceId/applications.

    2. Device Extension Retrieval
      ​/restful/organization/devices/:deviceId/extensions

  3. Implement Pagination: The new endpoint supports limit and offset parameters, allowing you to efficiently handle devices with a large number of installed applications.

This change ensures faster response times and prevents "Repository Entity Not Found" errors that could previously occur when processing massive data payloads.

Regional Endpoints

Ensure you are using the correct base URL for your organization's data residency:

  • US / Global: https://api.swifteam.com

  • EU Tenant: https://api.eu.swifteam.com


Team filtering and team details

You can get your organization's teams and use a team ID to see only the devices or employees in that team. Requests that don't include teamId work exactly as before, so you don't need to change existing integrations.

How it works:

  1. Call GET /restful/organization/teams to get your team IDs.

  2. Add teamId=<id> to /devices or /employees.

List teams

GET /restful/organization/teams returns your organization's active teams, sorted by name and then by ID. It doesn't take any parameters.

CURL request

curl --location 'https://api.swifteam.com/restful/organization/teams' \
--header 'Authorization: Bearer {TOKEN}'

Sample JSON response

{
"records": [
{ "teamId": "6667d7c93300001200972f03", "teamName": "Engineering" },
{ "teamId": "68a71f053000001f00873d00", "teamName": "QA" }
],
"meta": {
"totalCount": 2,
"resultCount": 2,
"haveMore": false
}
}

Field

Type

Description

teamId

string

The team's ID (24 hexadecimal characters)

teamName

string (optional)

The team's name

Filter devices by team

Add the optional teamId parameter to GET /restful/organization/devices. You can still use q, offset (default 0) and limit (default 10) with it.

CURL request

curl --location 'https://api.swifteam.com/restful/organization/devices?teamId=6667d7c93300001200972f03&offset=0&limit=10' \
--header 'Authorization: Bearer {TOKEN}'

When you filter by team, you only get that team's devices. The meta counts include only the matching devices.

Filter employees by team

GET /restful/organization/employees also takes the optional teamId parameter, and works with q, offset and limit the same way. The filter only looks at each employee's primary team.

curl --location 'https://api.swifteam.com/restful/organization/employees?teamId=6667d7c93300001200972f03&offset=0&limit=10' \
--header 'Authorization: Bearer {TOKEN}'

Team fields in device and employee records

Each device and employee record now has two top-level fields, whether or not you filter by team:

"teamId": "6667d7c93300001200972f03",
"teamName": "Engineering"

teamName can be missing for older records whose team is no longer active.

Errors

HTTP status

Code

When it happens

400

PUBLIC_API_INVALID_TEAM_ID

teamId is empty or isn't 24 hexadecimal characters

404

PUBLIC_API_TEAM_NOT_FOUND

The team doesn't exist, was deleted, or belongs to another organization

Both errors include a friendlyMessage that you can show to users.


Device compliance

GET /restful/organization/devices now tells you whether each device is compliant and why it isn't. These are the same results the Swif webapp shows. The new fields appear on every device record, so you don't need to change your existing requests. Authentication, q, offset, limit, teamId, paging and the records/meta layout all work as before.

New fields

Field

Type

Description

isCompliant

boolean

The device's overall compliance result, the same one the webapp shows. It's false when no compliance status is available.

failingComplianceChecks

array of { policyType, hint[] }

Built-in policy checks that haven't passed. This is always an array, but it can be empty.

nonComplianceReasons

array of reason objects

Every reason the device is non-compliant, from any source (see below). It's empty for compliant devices.

Reason object fields

Each item in nonComplianceReasons always contains source, reason, and hint. Other fields are conditionally present depending on the source. Compliant devices return an empty nonComplianceReasons: [] array.

Field

Type

When present

Description

source

string

Always

The source category: POLICY, CUSTOMER_CONTROL, APPLICATION, or COMPLIANCE_STATUS.

reason

string

Always

A human-readable explanation of why the device failed compliance.

hint

array of strings

Always

Remediation hints. Can be empty ([]), especially for customer controls or COMPLIANCE_STATUS.

policyType

string

Conditional

Present when source is POLICY. Also present for CUSTOMER_CONTROL when the failing control has a policy action with an associated policy type.

controlId

string

Conditional

Present when source is CUSTOMER_CONTROL. The ID of the failing customer control (e.g., ENC-1).

controlTitle

string

Conditional

Present when source is CUSTOMER_CONTROL. The title of the failing customer control (e.g., Full-Disk Encryption).

Reason sources

Multiple reasons across different sources can appear on a single non-compliant device.

Source

When it appears

Additional fields & Behavior

POLICY

The device is non-compliant and a built-in policy check has failed.

  • policyType is present.

  • Matches an entry in failingComplianceChecks.

CUSTOMER_CONTROL

A supported organization customer control does not match the device.

  • controlId and controlTitle are present.

  • policyType is present only if the failing control has a policy action with a policy type.

  • Customer controls of type APPLICATION are reported here as CUSTOMER_CONTROL.

APPLICATION

On desktop/laptop devices (non-iOS, iPadOS, Android), an enabled organization check finds that the required password manager or antivirus application is not installed.

  • No additional identifier fields.

  • The reason identifies which specific application check failed (can have one entry per failed check).

COMPLIANCE_STATUS

The device has no compliance status, or its overall verdict is false but no specific failed check details are available (fallback explanation).

  • No additional identifier fields.

  • hint is always an empty array ([]).

Sample JSON (nonComplianceReasons)

"isCompliant": false,
"failingComplianceChecks": [
{
"policyType": "FILEVAULT_POLICY",
"hint": [
"Assign and deploy team policy FILEVAULT_POLICY to this device."
]
}
],
"nonComplianceReasons": [
{
"source": "POLICY",
"policyType": "FILEVAULT_POLICY",
"reason": "Policy [FILEVAULT_POLICY] has not passed on this device.",
"hint": [
"Assign and deploy team policy FILEVAULT_POLICY to this device."
]
},
{
"source": "CUSTOMER_CONTROL",
"controlId": "ENC-1",
"controlTitle": "Full-Disk Encryption",
"policyType": "WINDOWS_BITLOCKER_AUTO_POLICY",
"reason": "Policy [WINDOWS_BITLOCKER_AUTO_POLICY] is deployed to the device but one or more settings do not meet the requirement.",
"hint": []
},
{
"source": "APPLICATION",
"reason": "Required password manager application is not installed.",
"hint": []
},
{
"source": "COMPLIANCE_STATUS",
"reason": "Device compliance status is not available.",
"hint": []
}
]

How to read the results

  • Use isCompliant for the overall answer. Use nonComplianceReasons to explain why a device fails, and failingComplianceChecks for details on each built-in policy. Don't try to work out one field from another.

  • Always read nonComplianceReasons to explain a non-compliant device. A device can be non-compliant with no failing policy checks. In that case failingComplianceChecks is empty, and nonComplianceReasons lists the failing customer control, application check or missing compliance status.

  • Show reason to users. Don't rely on hint alone, because it can be empty.

  • A device can be compliant while an encryption policy still shows as failing. If the device itself reports that it's encrypted, that counts toward the overall result.

  • Hints:

    • If a policy has no hint of its own, Swif creates one:

      • "Create and assign policy X for this team." means the policy hasn't been created or assigned yet.

      • "Assign and deploy team policy X to this device." means the policy is assigned but not deployed.

    • Hints written by policy authors are returned as they are.

    • Customer-control hints may be short labels such as "Fix Policy" or "Assign Policy", or they may be empty.


Device and evidence retrieval

CURL request

curl --location 'https://api.swifteam.com/restful/organization/devices?q=H070992XF6&offset=0&limit=1' \
--header 'Authorization: Bearer {TOKEN}'

Sample JSON response and its type

{
"records": [
{
"id": "6acfde512000002300157efb",
"isAntiVirusAppInstalled": true,
"isPasswordManagerAppInstalled": true,
"isActive": true,
"owner": {
"emails": [
"angelo@swifmssp.com"
]
},
"deviceInfo": {
"deviceName": "Angelo’s MacBook Pro",
"status": "ACTIVE",
"osVersion": "27.0.1",
"osName": "macOS",
"osBuildVersion": "26A434",
"modelName": "MacBook Pro",
"modelId": "MacBookPro18,1",
"productName": "MacBookPro18,1",
"deviceType": "Laptop",
"serialNumber": "H070992XF6",
"deviceCapacity": 994,
"availableDeviceCapacity": 282
},
"mdmDeviceInfo": {
"mdmDeviceId": "26A1B06E-639E-570D-8813-30D30F056837",
"mdm_LastEnrolledAt": "2026-10-14T19:56:01.152Z",
"mdm_LastPingAt": "2026-10-15T19:32:20.768Z",
"encryption": {
"encryptionStatus": "Encrypted",
"encryptionEnabled": true
}
},
"osQueryDeviceInfo": {
"os": {
"arch": "arm64",
"build": "26A434",
"major": "27",
"minor": "0",
"name": "macOS",
"patch": "1",
"version": "27.0.1"
},
"hardware": {
"chipType": "Apple M1 Pro",
"cpuType": "",
"currentProcessorSpeed": "",
"l2CacheCore": "",
"l3Cache": "",
"machineModel": "MacBookPro18,1",
"machineName": "MacBook Pro",
"modelNumber": "MK193LL/A",
"modelSpec": {
"colors": [
"Silver",
"Space Gray"
],
"fullName": "MacBook Pro (16-inch, 2021)",
"imageURL": "https://cdsassets.apple.com/live/7WUAS350/images/macbook-pro/macbook-pro-2021-16in.png",
"modelIdentifier": [
"MacBookPro18,1",
"MacBookPro18,2"
],
"newestOperatingSystem": "macOS Sequoia",
"partNumbers": [
"MK183xx/A",
"MK193xx/A",
"MK1A3xx/A",
"MK1E3xx/A",
"MK1F3xx/A",
"MK1H3xx/A"
],
"productYear": "2021",
"productYearInt": 2021,
"screenSize": "16-inch",
"techSpecsURL": "https://support.apple.com/en-us/111901",
"userGuideURL": "https://support.apple.com/guide/macbook-pro/welcome/2021/mac"
},
"numberProcessors": "proc 10:0:8:2",
"totalCoreCount": 10,
"performanceCoreCount": 0,
"efficiencyCoreCount": 8,
"superCoreCount": 2,
"physicalMemory": "16 GB"
},
"applicationInfo": [],
"extension": {
"chromeExtension": [],
"safariExtension": [],
"firefoxAddon": [],
"edgeExtension": [],
"ieExtension": []
},
"network": {
"macAddress": {
"bridge0": "36:65:a6:25:fa:40",
"en5": "ae:41:6f:c7:4a:70",
"anpi0": "ae:41:6f:c7:4a:8f",
"ethernet": "bc:d0:74:5a:8c:5c",
"ap1": "da:2c:cb:a3:df:e1",
"en0": "36:6e:dd:1d:fa:1e",
"en1": "36:65:a6:25:fa:40",
"wifi": "bc:d0:74:5a:8c:5c",
"en4": "ae:41:6f:c7:4a:6f",
"awdl0": "a2:90:f6:1c:2b:43",
"anpi2": "ae:41:6f:c7:4a:91",
"en6": "ae:41:6f:c7:4a:71",
"nan0": "f2:c2:20:98:c1:06",
"llw0": "a2:90:f6:1c:2b:43",
"en2": "36:65:a6:25:fa:44",
"anpi1": "ae:41:6f:c7:4a:90",
"bluetooth": "BC:D0:74:59:7F:26",
"en3": "36:65:a6:25:fa:48"
},
"localIP": "172.18.205.146",
"externalIP": "50.145.36.26"
}
},
"systemPolicy": {
"password": {
"minLength": 8,
"pinHistory": 2,
"allowSimple": true,
"maxInactivity": 0,
"maxGracePeriod": 0,
"minimumPasswordAge": 0,
"maximumPasswordAge": 180,
"minComplexChars": 1,
"maxFailedAttempts": 6,
"requireAlphanumeric": true,
"minutesUntilFailedLoginReset": 0,
"lockoutBadCount": 0,
"lockoutDuration": 0
},
"screenSaver": {
"idleTime": 900,
"askForPassword": true,
"askForPasswordDelay": 0,
"screenSaveActive": false,
"screenSaverExe": "",
"screenSaverGracePeriod": 0
}
},
"teamId": "6acfb1a82400002a00a49fa1",
"teamName": "Swif's Team",
"isCompliant": false,
"failingComplianceChecks": [
{
"policyType": "FILEVAULT_POLICY",
"hint": [
"Assign and deploy team policy FILEVAULT_POLICY to this device."
]
}
],
"nonComplianceReasons": [
{
"source": "POLICY",
"policyType": "FILEVAULT_POLICY",
"reason": "Policy [FILEVAULT_POLICY] has not passed on this device.",
"hint": [
"Assign and deploy team policy FILEVAULT_POLICY to this device."
]
},
{
"source": "CUSTOMER_CONTROL",
"controlId": "ENC-1",
"controlTitle": "Full-Disk Encryption",
"reason": "Policy [WINDOWS_BITLOCKER_AUTO_POLICY] is deployed to the device but one or more settings do not meet the requirement.",
"hint": []
}
]
}
],
"meta": {
"totalCount": 1,
"resultCount": 1,
"haveMore": false
}
}

Note: applicationInfo and extension are still in the inventory response so older integrations don't break, but they're always empty.

  • To get a device's applications, call /restful/organization/devices/:deviceId/applications.

  • For browser extensions, call /restful/organization/devices/:deviceId/extensions.

Did this answer your question?