Scans API
Maintained by: Aether365 Team Audience: Developers Scope: Scan API endpoints - triggering and listing scans
List Scans
Returns a paginated list of scans for the authenticated tenant, newest first.
GET /tenants/me/scansQuery Parameters
| Parameter | Type | Description |
|---|---|---|
page | integer | Page number (default: 1) |
limit | integer | Results per page (default: 20, max: 100) |
scanType | string | Filter by type: compliance |
showHidden | boolean | Include hidden scans (default: false) |
INFO
There is no server-side status filter. To find, for example, the latest completed scan, filter the returned list on the status field client-side.
Example Request
bash
curl "https://api.aether365.io/tenants/me/scans?limit=20" \
-H "Authorization: Bearer ak_live_..."Example Response
json
{
"success": true,
"data": [
{
"id": "0d9f6f9e-3b0c-4a9d-9c1e-2f6a8b7c5d4e",
"tenantId": "7c1b2a3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
"status": "completed",
"scanType": "compliance",
"triggeredBy": "manual",
"mode": "manual",
"startedAt": "2026-04-09T00:00:12+00:00",
"completedAt": "2026-04-09T00:14:23+00:00",
"passCount": 87,
"failCount": 12,
"skipCount": 5,
"errorMessage": null,
"createdAt": "2026-04-09T00:00:00+00:00",
"msTenantId": "f1e2d3c4-b5a6-9788-1c2d-3e4f5a6b7c8d",
"orgName": "Contoso Ltd",
"reportStatus": "ready",
"reportLocale": "en",
"highCount": 4,
"medCount": 8,
"lowCount": 0,
"frameworkBreakdown": [
{ "name": "CIS", "value": 64, "passed": 55 },
{ "name": "EIDSCA", "value": 40, "passed": 32 }
]
}
],
"meta": {
"total": 24,
"page": 1,
"limit": 20
}
}The example omits some always-present fields for brevity. The complete set is listed in the Scan Object reference below.
Scan Object
All field names are camelCase. Every scan response contains:
| Field | Type | Description |
|---|---|---|
id | string | Scan ID (UUID) |
tenantId | string | Aether365 tenant ID |
status | string | pending, running, completed, failed, cancelled, or expired |
scanType | string | compliance |
scannerVersion | string or null | Scanner engine version |
triggeredBy | string | manual or scheduler |
mode | string | manual or ai_pilot |
startedAt / completedAt | string or null | ISO 8601 timestamps |
passCount / failCount / skipCount | integer | Final result counters |
s3ResultKey | string or null | Internal storage reference for the raw result file |
errorMessage | string or null | Failure reason when status is failed |
isHidden | boolean | Whether the scan is hidden from the default list |
createdAt / updatedAt | string or null | ISO 8601 timestamps |
currentPhase / currentTestId / currentTestTitle | string or null | Live progress while the scan runs |
phaseUpdatedAt | string or null | Timestamp of the last progress update |
partialPassCount / partialFailCount | integer | Running counters while the scan is in progress |
msTenantId | string or null | Microsoft tenant the scan ran against |
orgName | string or null | Organization display name |
reportStatus | string | PDF report state: none, rendering, ready, or error |
reportLocale | string or null | Report language |
reportGeneratedAt | string or null | When the PDF report was rendered |
reportError | string or null | Report render failure reason |
List responses additionally include highCount, medCount, lowCount (failed findings bucketed by severity) and frameworkBreakdown (per-framework totals as { name, value, passed }). Single-scan responses (GET /scans/{scanId}) additionally include unchangedSincePrevious (boolean).
There is no score field. If you need a pass rate, derive it from the counters: passCount / (passCount + failCount).
Get Scan
Returns details of a single scan.
GET /scans/{scanId}Example Request
bash
curl https://api.aether365.io/scans/0d9f6f9e-3b0c-4a9d-9c1e-2f6a8b7c5d4e \
-H "Authorization: Bearer ak_live_..."Example Response
json
{
"success": true,
"data": {
"id": "0d9f6f9e-3b0c-4a9d-9c1e-2f6a8b7c5d4e",
"tenantId": "7c1b2a3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
"status": "completed",
"scanType": "compliance",
"triggeredBy": "manual",
"mode": "manual",
"startedAt": "2026-04-09T00:00:12+00:00",
"completedAt": "2026-04-09T00:14:23+00:00",
"passCount": 87,
"failCount": 12,
"skipCount": 5,
"errorMessage": null,
"createdAt": "2026-04-09T00:00:00+00:00",
"msTenantId": "f1e2d3c4-b5a6-9788-1c2d-3e4f5a6b7c8d",
"orgName": "Contoso Ltd",
"reportStatus": "ready",
"reportLocale": "en",
"unchangedSincePrevious": false
}
}Trigger a Scan
Starts a scan immediately for the authenticated tenant.
POST /tenants/me/scansRequest Body
json
{
"scanType": "compliance"
}| Field | Type | Required | Description |
|---|---|---|---|
scanType | string | No | compliance |
connectionId | string | No | Target a specific connected Microsoft tenant. Defaults to the primary connection. |
Example Request
bash
curl -X POST https://api.aether365.io/tenants/me/scans \
-H "Authorization: Bearer ak_live_..." \
-H "Content-Type: application/json" \
-d '{"scanType": "compliance"}'Example Response
Returns 201 with the newly created scan object:
json
{
"success": true,
"data": {
"id": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e",
"tenantId": "7c1b2a3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
"status": "pending",
"scanType": "compliance",
"triggeredBy": "manual",
"mode": "manual",
"startedAt": null,
"completedAt": null,
"passCount": 0,
"failCount": 0,
"skipCount": 0,
"errorMessage": null,
"reportStatus": "none",
"reportLocale": null
}
}Errors
| Code | HTTP | Description |
|---|---|---|
SCAN_ALREADY_RUNNING | 409 | A scan (of any type) is already in progress for this tenant |
TENANT_NOT_CONNECTED | 400 | Microsoft consent has not been completed for this tenant |
AUTH_INSUFFICIENT_SCOPE | 403 | On-demand scans not available on the current plan |
SCAN_TYPE_DISABLED | 403 | This scan type is currently disabled for the tenant |
SCAN_PLAN_LIMIT_REACHED | 429 | Plan scan window reached (the scan window for your plan) |
Other Scan Operations
| Endpoint | Description |
|---|---|
POST /scans/{scanId}/cancel | Cancels a pending or running scan. A terminal-state scan returns 409 SCAN_NOT_CANCELLABLE. Returns the scan. |
PATCH /scans/{scanId}/hide | Hides the scan from the default list (data: null). Reverse with PATCH /scans/{scanId}/unhide. |
DELETE /scans/{scanId} | Deletes a scan and its results. A pending or running scan returns 409 SCAN_NOT_DELETABLE - cancel it first. |