Skip to main content

Public APIs: Fetch Script Execution Reports

Updated today

This article explains how to use Swif.ai’s new public APIs to fetch reports from custom scripts or commands run via the Swif agent/MDM. Typical use cases include:

  • Listing installed extensions for tools like Cursor or VS Code on a schedule

  • Pulling script outputs into external security/compliance platforms

  • Auditing command execution results across devices, users, and teams

These APIs are organization‑scoped and protected by your Swif organization public API token.

Your existing API key/token documentation is here: Your API key token.


1. Overview of the Script Report APIs

What this feature does

Swif now:

  • Ingests script/command execution results from MDM via an internal callback flow

  • Stores normalized script report records in an internal collection

  • Exposes two new public REST APIs so your systems can read those reports:

  1. GET /restful/organization/api/v1/script-reports
    – List and filter script reports (with pagination)

  2. GET /restful/organization/api/v1/script-reports/:reportId
    – Fetch a single script report by ID

All access to these endpoints is authorized by your organization public API token (not a per‑user access token).


2. Data Model: Script Report

Each script report represents the result of one logical script/command execution on one device. At a high level, a report includes:

  • Organization & team

    • organizationId

    • teamId

    • teamName

  • Device & owner

    • deviceId

    • mdmDeviceId

    • deviceName

    • deviceSerialNumber

    • deviceOwnerId

    • deviceOwnerName

    • deviceOwnerEmail

  • Command / script

    • commandId – execution ID

    • commandTemplateId – template ID used for execution

    • commandName – display name (e.g., “List VS Code Extensions”)

    • commandType – type/category (e.g., SCRIPT)

    • command – raw command or script text

    • response – raw output from the script/command

    • status – integer status code

  • Timestamps

    • startedAt – when execution started

    • completedAt – when execution ended (may be null)

    • collectedAt – when Swif stored/updated the record

    • updatedAt – last update time of the record

Reports are retained for up to 90 days, after which they are automatically removed as part of Swif’s data cleanup.


3. Generate an Organization Public API Token

Before you can call the Script Report APIs, you need your organization public API token. This is distinct from individual user API tokens and is scoped to your entire organization.

Your existing API key/token documentation is here: Your API key token.


4. API: List Script Reports

Use this endpoint to search, filter, and paginate through script reports for your organization.

  • Method: GET

  • Path: /restful/organization/api/v1/script-reports

  • Auth: Organization public API token (Authorization: Bearer <ORG_PUBLIC_API_TOKEN>)

  • Body: None – use query string parameters

4.1 Authentication

Authorization: Bearer <ORG_PUBLIC_API_TOKEN>

The token’s organization determines which reports are visible; you cannot use it to access data from another organization.

4.2 Query parameters

All parameters are optional. If not provided or set to null, they are ignored.

Name

Type

Matching behavior

teamId

string or null

Exact match (24‑char MongoID)

deviceId

string or null

Exact match (24‑char MongoID)

mdmDeviceId

string or null

Case‑insensitive partial match

deviceName

string or null

Case‑insensitive partial match

ownerId

string or null

Exact match (24‑char MongoID)

ownerName

string or null

Case‑insensitive partial match

ownerEmail

string or null

Case‑insensitive partial match

serialNumber

string or null

Case‑insensitive partial match

commandId

string or null

Case‑insensitive partial match

commandTemplateId

string or null

Case‑insensitive partial match

commandName

string or null

Case‑insensitive partial match

commandType

string or null

Case‑insensitive partial match

command

string or null

Case‑insensitive partial match

response

string or null

Case‑insensitive partial match

status

integer or null

Exact match

startedAtFrom

string or null

ISO‑8601, lower bound on startedAt

startedAtTo

string or null

ISO‑8601, upper bound on startedAt

completedAtFrom

string or null

ISO‑8601, lower bound on completedAt

completedAtTo

string or null

ISO‑8601, upper bound on completedAt

collectedAtFrom

string or null

ISO‑8601, lower bound on collectedAt

collectedAtTo

string or null

ISO‑8601, upper bound on collectedAt

search

string or null

Multi‑field search (see below)

offset

integer or null

Pagination offset (negative → 0)

limit

integer or null

Page size; ≤0 → 20; max 200

Search behavior

The search parameter performs a case‑insensitive search across multiple fields, including:

  • teamName

  • mdmDeviceId

  • deviceName

  • deviceOwnerName

  • deviceOwnerEmail

  • deviceSerialNumber

  • commandId

  • commandTemplateId

  • commandName

  • commandType

  • command

  • response

This is convenient for quick keyword searches (e.g., “python” or “vscode”).

Pagination rules

  • If offset is negative, it is normalized to 0.

  • If limit ≤ 0, it default to 20.

  • If limit > 200, it is capped at 200.

4.3 Example request

{
"headers": {
"Authorization": "Bearer <ORG_PUBLIC_API_TOKEN>"
},
"pathParams": {},
"queryParams": {
"teamId": null,
"deviceId": null,
"mdmDeviceId": "dev-001",
"deviceName": null,
"ownerId": null,
"ownerName": null,
"ownerEmail": null,
"serialNumber": null,
"commandId": null,
"commandTemplateId": "tpl-vscode-extensions-001",
"commandName": "List VS Code Extensions",
"commandType": "SCRIPT",
"command": null,
"response": null,
"status": 1,
"startedAtFrom": "2026-03-01T00:00:00Z",
"startedAtTo": "2026-03-31T23:59:59Z",
"completedAtFrom": null,
"completedAtTo": null,
"collectedAtFrom": null,
"collectedAtTo": null,
"search": "python",
"offset": 0,
"limit": 20
}
}

4.4 Response format

The response is paginated and includes metadata:

  • records[] – array of script report objects

  • meta.totalCount – total results matching the filters

  • meta.resultCount – number of records in this page

  • meta.haveMoretrue if there are more pages

When no results match, the API returns:

  • records: []

  • meta.totalCount: 0

  • meta.resultCount: 0

  • meta.haveMore: false

4.5 Access control

  • Organization access is strictly derived from the token’s orgId.

  • Even if you provide a teamId from another organization, the result set is always limited to your own organization.

  • Requests without a valid token, with an invalid token, or using a token from another org will not return cross‑org data.


5. API: Get Script Report Detail

Use this endpoint to fetch the full details of a single script report.

  • Method: GET

  • Path: /restful/organization/api/v1/script-reports/:reportId

  • Auth: Organization public API token

  • Body: None

5.1 Parameters

Headers

Name

Required

Description

Authorization

Yes

Bearer <ORG_PUBLIC_API_TOKEN>

Path

Name

Required

Description

reportId

Yes

24‑character MongoID of the report

5.2 Example request

{
"headers": {
"Authorization": "Bearer <ORG_PUBLIC_API_TOKEN>"
},
"pathParams": {
"reportId": "<SCRIPT_REPORT_MONGO_ID>"
},
"queryParams": {}
}

5.3 Response format

Returns a single object with all persisted and derived fields, including:

  • reportId

  • organizationId

  • teamId

  • teamName

  • deviceId

  • mdmDeviceId

  • deviceName

  • deviceOwnerName

  • deviceOwnerEmail

  • deviceSerialNumber

  • commandId

  • commandTemplateId

  • commandName

  • commandType

  • command

  • response

  • status

  • startedAt

  • completedAt

  • collectedAt

  • updatedAt

5.4 Error handling and access control

  • If reportId is malformed or not a 24‑character MongoID, you receive a bad request/validation error.

  • If reportId is well‑formed but does not exist, you receive a “not found” response.

  • If a report exists but belongs to another organization, the API still returns “not found” – it never reveals cross‑org data.


6. Common Usage Patterns

6.1 Scheduled polling for new reports

You can implement “new since last run” polling using collectedAtFrom or a combination of time filters.

Example:

GET /restful/organization/api/v1/script-reports?collectedAtFrom=2026-03-24T00:00:00Z&limit=100 Authorization: Bearer <ORG_PUBLIC_API_TOKEN>

Store the last collectedAt you received and reuse it as the next collectedAtFrom to avoid gaps or duplicates.

6.2 Filtering by script or device

  • All VS Code extension scripts in March:

GET /restful/organization/api/v1/script-reports?commandTemplateId=tpl-vscode-extensions-001&startedAtFrom=2026-03-01T00:00:00Z&startedAtTo=2026-03-31T23:59:59Z Authorization: Bearer <ORG_PUBLIC_API_TOKEN>

  • All completed reports for a specific MDM device:

GET /restful/organization/api/v1/script-reports?mdmDeviceId=dev-001&status=1 Authorization: Bearer <ORG_PUBLIC_API_TOKEN>

6.3 Quick keyword search

To find any script report whose command or response references a keyword (for example python):

GET /restful/organization/api/v1/script-reports?search=python&limit=20 Authorization: Bearer <ORG_PUBLIC_API_TOKEN>

This will search across command, response, and other text fields described in Section 5.2.


7. Security and Retention

  • Authorization: Both Script Report APIs require an organization public API token; they do not accept user‑level tokens directly.

  • Multi‑tenant isolation: Organization scoping is enforced at the API layer. A valid token can only read script reports for its own organization.

  • Data retention: Old script reports are automatically removed after 90 days as part of Swif’s data cleanup policy.


Did this answer your question?