Skip to main content

API Reference

The Shadow AI Guard API is a REST interface for managing your EDR connector configuration, querying detections, and controlling per-tenant detection policy. The service runs on port 8400 by default. Interactive docs are available at http://<your-host>:8400/docs.

Prerequisites

  • Base URL — your organization's Shadow AI Guard deployment (e.g. https://<your-org>.virtueai.io). Replace YOUR_BASE_URL in all examples.
  • API key — passed in the X-API-Key header, or use Authorization: Bearer YOUR_TOKEN obtained from the Auth endpoints below.

Authentication

POST /auth/login

Exchange credentials for a JWT access token.

Request body

FieldTypeRequiredDescription
usernamestringYesAccount username
passwordstringYesAccount password
tenant_namestringNoTenant name (default: "system")

Response

FieldTypeDescription
access_tokenstringJWT bearer token
refresh_tokenstringToken to obtain a new access token
token_typestringAlways "bearer"
expires_inintegerSeconds until access token expires
curl -X POST "https://YOUR_BASE_URL/auth/login" \
-H "Content-Type: application/json" \
-d '{
"username": "alice@example.com",
"password": "s3cr3t",
"tenant_name": "acme"
}'

Expected response:

{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer",
"expires_in": 3600
}

POST /auth/refresh

Exchange a refresh token for a new access token.

Request body: { "refresh_token": "YOUR_TOKEN" }


POST /auth/logout

Invalidate a refresh token.

Request body: { "refresh_token": "YOUR_TOKEN" }


GET /auth/me

Return the authenticated user's profile. Requires Authorization: Bearer YOUR_TOKEN.

Response: { "id": "...", "username": "..." }


POST /auth/register

Register a new user account.

Request body

FieldTypeRequiredDescription
usernamestringYesNew account username
passwordstringYesNew account password
tenant_namestringNoTenant to register under (default: "system")

EDR Connector Configuration

Manage the EDR data source for the tenant (Microsoft Defender, CrowdStrike, SentinelOne).

GET /api/v1/shadow-ai/config

Return the current tenant's active EDR connector configuration. Returns null when no connector has been configured yet.

Query parameters

ParameterTypeDescription
tenant_idstringOverride the tenant from the API key (admin use)

Response

FieldTypeDescription
edr_frameworkstringConnector type: "microsoft-defender", "crowdstrike", "crowdstrike-ngsiem", "sentinelone"
credential_fieldsobjectNon-secret credential values (IDs, tenant IDs, etc.)
has_secretbooleanWhether a secret credential is stored
settingsobjectConnector-specific settings
created_atstring | nullISO-8601 creation timestamp
updated_atstring | nullISO-8601 last-update timestamp
curl "https://YOUR_BASE_URL/api/v1/shadow-ai/config" \
-H "X-API-Key: YOUR_API_KEY"

Expected response:

{
"edr_framework": "microsoft-defender",
"credential_fields": {
"tenant_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"client_id": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy"
},
"has_secret": true,
"settings": {},
"created_at": "2025-01-10T09:00:00+00:00",
"updated_at": "2025-03-22T14:30:00+00:00"
}

PUT /api/v1/shadow-ai/config

Create or update the tenant's EDR connector configuration. If a config for the same connector type already exists it is updated in place — secrets already on file are preserved when omitted from the request. Switching to a different connector type disables the previous configuration.

Query parameters

ParameterTypeDescription
tenant_idstringOverride the tenant from the API key (admin use)

Request body

FieldTypeRequiredDescription
edr_frameworkstringYes"microsoft-defender", "crowdstrike", "crowdstrike-ngsiem", "sentinelone"
credentialsobjectYesConnector credential fields (see table below)
settingsobjectNoConnector-specific settings

Required credential fields by connector

ConnectorFields
microsoft-defendertenant_id, client_id, client_secret
crowdstrikeclient_id, client_secret, base_url
crowdstrike-ngsiemclient_id, client_secret, base_url
sentinelonebase_url, api_token

Response: same shape as GET /api/v1/shadow-ai/config.

curl -X PUT "https://YOUR_BASE_URL/api/v1/shadow-ai/config" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"edr_framework": "microsoft-defender",
"credentials": {
"tenant_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"client_id": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
"client_secret": "YOUR_SECRET"
}
}'

Detection Events

GET /api/v1/shadow-ai/events

Return a paginated list of Shadow AI detections for the tenant, ordered by started_at descending. Detections whose detection rule is currently disabled by tenant policy are automatically excluded.

Query parameters

ParameterTypeDefaultDescription
tenant_idstringOverride tenant (admin use)
start_datestringISO-8601 — include events at or after this time
end_datestringISO-8601 — include events at or before this time
offsetinteger0Pagination offset
limitinteger50Results per page (max 1000)
detection_modestringFilter by detection mode
device_osstring[]Filter by OS (e.g. Windows, macOS). Repeat the parameter for multiple values.

Response

FieldTypeDescription
eventsarrayDetection records (see fields below)
totalintegerTotal matching records (for pagination)
scanned_atstringISO-8601 query timestamp

Event fields

FieldTypeDescription
idintegerDetection ID
device_namestringHostname where activity was detected
device_osstring | nullOperating system
agent_frameworkstringDetection rule / framework that matched
promptstring | nullExtracted prompt text (when extraction is configured)
account_namestring | nullUser account associated with the activity
started_atstring | nullISO-8601 session start
ended_atstring | nullISO-8601 session end
process_countintegerProcess events in the session
network_countintegerNetwork events in the session
file_countintegerFile events in the session
total_eventsintegerSum of process + network + file counts
detection_modestring | nullDetection mode label
activity_tagsstring[]Behavioral tags on the session
action_guard_allowedboolean | nullAction Guard result (null = not yet evaluated)
action_guard_violations_countintegerNumber of Action Guard violations
created_atstring | nullISO-8601 record creation timestamp
curl "https://YOUR_BASE_URL/api/v1/shadow-ai/events?limit=20&start_date=2025-01-01T00:00:00Z" \
-H "X-API-Key: YOUR_API_KEY"

GET /api/v1/shadow-ai/events/stats

Return aggregate KPI statistics for the Shadow AI dashboard.

Query parameters

ParameterTypeDescription
tenant_idstringOverride tenant (admin use)
start_datestringISO-8601 filter start
end_datestringISO-8601 filter end
device_osstring[]Filter by OS

Response

FieldTypeDescription
total_detectionsintegerTotal detections in the time window
top_application{ name: string, count: integer }Most-detected AI framework and its count
active_devices_monitoredintegerNumber of distinct devices with at least one detection
curl "https://YOUR_BASE_URL/api/v1/shadow-ai/events/stats" \
-H "X-API-Key: YOUR_API_KEY"

Expected response:

{
"total_detections": 142,
"top_application": { "name": "cursor", "count": 58 },
"active_devices_monitored": 23
}

GET /api/v1/shadow-ai/events/{event_id}/tree

Return the full process / network / file event timeline for a single detection.

Path parameters

ParameterTypeDescription
event_idintegerDetection ID (from the events list)

Response

FieldTypeDescription
idintegerDetection ID
agent_frameworkstringRule that triggered the detection
device_namestringHostname
account_namestring | nullUser account
promptstring | nullExtracted prompt
started_atstring | nullSession start
ended_atstring | nullSession end
process_countintegerNumber of process events
network_countintegerNumber of network events
file_countintegerNumber of file events
eventsarrayOrdered event timeline (see fields below)

Timeline event fields

FieldTypeDescription
timestampstringISO-8601 event time
dimensionstring"Process", "Network", "File", or "DNS"
detailstringHuman-readable event summary
device_namestringDevice hostname
account_namestringUser account
file_namestringFile name (File events)
process_command_linestringFull command line (Process events)
initiating_processstringParent process command line
curl "https://YOUR_BASE_URL/api/v1/shadow-ai/events/42/tree" \
-H "X-API-Key: YOUR_API_KEY"

GET /api/v1/shadow-ai/events/{event_id}/guard-result — Coming Soon

Coming Soon

Action Guard evaluation is under active development. This endpoint exists in the API today but returns placeholder data until the evaluation pipeline is complete.

Return the Action Guard policy evaluation result for a detection.

Path parameters

ParameterTypeDescription
event_idintegerDetection ID

Response

FieldTypeDescription
evaluatedbooleanWhether Action Guard has run on this detection
allowedboolean | nulltrue = allowed, false = blocked, null = not yet evaluated
violationsarrayPolicy violation objects
violations_countintegerNumber of violations
explanationstring | nullHuman-readable explanation from Action Guard

POST /api/v1/shadow-ai/evaluate-all — Coming Soon

Coming Soon

Bulk re-evaluation of unevaluated detections via Action Guard is not yet implemented. The endpoint accepts requests but always returns { "message": "Not yet implemented" }.

Trigger a re-evaluation pass over all unevaluated detections for the tenant.

Response: { "message": "Not yet implemented", "evaluated": 0, "total": 0 }


AI Connect Awareness

Monitor outbound network connections from managed endpoints to AI provider domains. These endpoints surface connection-level telemetry normalised from EDR network events — giving you visibility into which apps, users, and devices are calling AI APIs regardless of whether a full agent session was detected.

All AI Connect endpoints share a common set of query parameters:

ParameterTypeDefaultDescription
tenant_idstringOverride tenant (admin use)
startdatetimeISO-8601 window start
enddatetimeISO-8601 window end
connectorstringFilter to a specific EDR connector (e.g. crowdstrike_ngsiem, mde)

GET /api/v1/ai-connect/summary

Top-line KPI counters for the AI Connect Awareness dashboard.

Response

FieldTypeDescription
total_connectionsintegerTotal network rows hitting any AI provider domain in the window
distinct_usersintegerDistinct usernames observed
distinct_devicesintegerDistinct device UIDs observed
distinct_providersintegerDistinct AI providers matched
window_startdatetimeStart of the query window
window_enddatetimeEnd of the query window
curl "https://YOUR_BASE_URL/api/v1/ai-connect/summary" \
-H "X-API-Key: YOUR_API_KEY"

Expected response:

{
"total_connections": 3821,
"distinct_users": 47,
"distinct_devices": 31,
"distinct_providers": 6,
"window_start": "2025-05-12T00:00:00+00:00",
"window_end": "2025-05-19T23:59:59+00:00"
}

GET /api/v1/ai-connect/by-provider

Connection counts grouped and folded by AI provider. Domain-level rows are aggregated in SQL then mapped to named providers in application code.

Additional query parameters

(none beyond the common set above)

Response

FieldTypeDescription
providersarrayPer-provider breakdown items (see below)
window_startdatetimeStart of the query window
window_enddatetimeEnd of the query window

Provider breakdown item fields

FieldTypeDescription
provider_idstringRule ID that matched (e.g. ai-connect-anthropic)
provider_namestringHuman-readable provider name
connection_countintegerTotal connections to this provider
distinct_usersintegerDistinct users that connected
distinct_devicesintegerDistinct devices that connected
last_seendatetime | nullMost recent connection time
curl "https://YOUR_BASE_URL/api/v1/ai-connect/by-provider" \
-H "X-API-Key: YOUR_API_KEY"

GET /api/v1/ai-connect/by-app

Connection counts grouped by the initiating application process name. actor_process_name is promoted to a dedicated column at ingest time, making this aggregation a cheap GROUP BY even over large windows.

Additional query parameters

ParameterTypeDefaultDescription
limitinteger20Max apps to return (max 200)

Response

FieldTypeDescription
appsarrayPer-application breakdown items (see below)
window_startdatetimeStart of the query window
window_enddatetimeEnd of the query window

App breakdown item fields

FieldTypeDescription
app_namestringProcess name (e.g. msedge.exe)
connection_countintegerTotal connections from this app
distinct_providersintegerDistinct AI providers contacted
distinct_usersintegerDistinct users running this app
last_seendatetime | nullMost recent connection time
curl "https://YOUR_BASE_URL/api/v1/ai-connect/by-app?limit=10" \
-H "X-API-Key: YOUR_API_KEY"

GET /api/v1/ai-connect/events

Paginated row-level connection feed for the dashboard table.

Additional query parameters

ParameterTypeDefaultDescription
limitinteger50Results per page (max 500)
provider_idstringFilter to a single AI provider (e.g. ai-connect-anthropic)

Response

FieldTypeDescription
eventsarrayConnection event records (see below)
totalintegerTotal matching records
window_startdatetimeStart of the query window
window_enddatetimeEnd of the query window

Connection event fields

FieldTypeDescription
timedatetimeEvent timestamp
connector_idstringEDR connector that sourced this row (e.g. crowdstrike_ngsiem, mde)
device_uidstringDevice identifier
device_namestring | nullDevice hostname
user_namestring | nullUsername
app_namestring | nullInitiating application process name
app_cmd_linestring | nullFull command line of the initiating process
dst_domainstring | nullDestination domain
dst_ipstring | nullDestination IP address
dst_portinteger | nullDestination port
provider_idstring | nullAI provider rule ID matched
provider_namestring | nullAI provider human-readable name
curl "https://YOUR_BASE_URL/api/v1/ai-connect/events?limit=20&provider_id=ai-connect-openai" \
-H "X-API-Key: YOUR_API_KEY"

Detection Rules & Policy

The rule catalog is read-only — rule definitions are managed in code and deployed with the service. These endpoints expose the catalog with per-tenant policy overrides merged in and allow tenants to enable/disable rules or adjust their severity.

GET /api/v1/rules

Return the full detection rule catalog with the current tenant's policy state merged. Rules default to enabled: true when no override exists.

Response

FieldTypeDescription
categoriesarrayRule category definitions (see below)
rulesarrayAll rules with merged policy state (see below)

Category fields

FieldTypeDescription
idstringCategory key (e.g. "CODING_CLI", "CODING_IDE_PLUGIN")
labelstringDisplay label
descriptionstringShort description
groupstring"active" (live detections) or "upcoming" (planned)

Rule fields

FieldTypeDescription
idstringRule identifier (e.g. "cursor-v2")
versionintegerRule version
severitystring"CRITICAL", "HIGH", "MEDIUM", "LOW", or "INFORMATIONAL"
confidencefloatDetection confidence 0.0–1.0
categorystringCategory ID
subcategorystringOptional sub-category
descriptionstringHuman-readable description
matchobjectDetection signals: process_names, cli_patterns, dst_domains, dns_hostname_suffixes, api_domains
tagsstring[]Free-form tags
mitrestring[] | nullMITRE ATT&CK technique IDs
enabledbooleanWhether this rule is enabled for the tenant
severity_overridestring | nullTenant severity override (null = use rule default)
curl "https://YOUR_BASE_URL/api/v1/rules" \
-H "X-API-Key: YOUR_API_KEY"

PATCH /api/v1/rules/{rule_id}

Upsert the tenant policy override for a single rule. Only fields present in the request body are written — omitted fields are left unchanged. Send "severity_override": null to clear the override and restore the rule's default severity.

Path parameters

ParameterTypeDescription
rule_idstringRule ID from GET /api/v1/rules

Request body (all fields optional)

FieldTypeDescription
enabledbooleanEnable or disable this rule for the tenant
severity_overridestring | nullOverride severity, or null to clear

Response: the updated rule object.

# Disable a rule
curl -X PATCH "https://YOUR_BASE_URL/api/v1/rules/cursor-v2" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"enabled": false}'

PUT /api/v1/rules/bulk

Apply many rule overrides in a single atomic transaction. All rule IDs must exist in the catalog — unknown IDs return 422. Intended for select-all / select-none dashboard flows.

Request body

FieldTypeDescription
rulesarrayList of override items

Each item in rules:

FieldTypeRequiredDescription
rule_idstringYesRule identifier
enabledbooleanNoEnable / disable
severity_overridestring | nullNoOverride severity or null to clear

Response

FieldTypeDescription
updatedintegerNumber of rules updated
rulesarrayUpdated rule objects
curl -X PUT "https://YOUR_BASE_URL/api/v1/rules/bulk" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"rules": [
{"rule_id": "cursor-v2", "enabled": false},
{"rule_id": "github-copilot-v1", "severity_override": "HIGH"}
]
}'

SaaS Config BETA

BETA

SaaS connector support is a beta feature currently scoped to ServiceNow. The request/response shape may change before general availability.

Manage credentials for the SaaS connector (currently ServiceNow). Credentials are stored encrypted in the same connector config store used by EDR connectors.

GET /api/v1/shadow-ai/saas-config

Return the current tenant's SaaS connector configuration with the password masked.

Response

FieldTypeDescription
platformstringAlways "servicenow"
auth_typestringAlways "basic"
hoststring | nullServiceNow instance hostname
userstring | nullServiceNow username
has_passwordbooleanWhether a password is stored
instance_urlstring | nullFull instance URL
last_modifiedstring | nullISO-8601 last-update timestamp
curl "https://YOUR_BASE_URL/api/v1/shadow-ai/saas-config" \
-H "X-API-Key: YOUR_API_KEY"

PUT /api/v1/shadow-ai/saas-config

Create or update the SaaS connector credentials.

Request body

FieldTypeRequiredDescription
platformstringNoAlways "servicenow"
auth_typestringNoAlways "basic"
hoststringYesServiceNow instance hostname or URL (protocol prefix stripped automatically)
userstringYesServiceNow username
passwordstringYesServiceNow password

Response: same shape as GET /api/v1/shadow-ai/saas-config.

curl -X PUT "https://YOUR_BASE_URL/api/v1/shadow-ai/saas-config" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"host": "mycompany.service-now.com",
"user": "admin",
"password": "YOUR_PASSWORD"
}'

SaaS Inventory BETA

BETA

SaaS inventory scanning is a beta feature scoped to ServiceNow. It runs against the live ServiceNow instance on every request and has no caching layer. Response times scale with instance size.

GET /api/v1/shadow-ai/saas-inventory

Scan the configured ServiceNow instance and return all discovered AI-related resources. The scan executes in real time — each call hits ServiceNow directly.

Query parameters

ParameterTypeDescription
tenant_idstringOverride tenant (admin use)
platformstringSaaS platform to scan. Currently only "servicenow" is supported.

Response

FieldTypeDescription
findingsarrayDiscovered AI resource records (see below)
countintegerTotal number of findings
instancestringServiceNow hostname that was scanned
scan_duration_secondsfloatTime taken for the scan
generated_atstringISO-8601 timestamp of the scan

Finding fields

FieldTypeDescription
platformstringAlways "servicenow"
resource_typestringType of discovered resource
resource_idstringServiceNow sys_id
resource_namestringHuman-readable resource name
scopestringServiceNow application scope
created_bystringUsername of the creator
discovered_atstringISO-8601 discovery timestamp
detailsobjectAdditional resource-specific metadata
curl "https://YOUR_BASE_URL/api/v1/shadow-ai/saas-inventory" \
-H "X-API-Key: YOUR_API_KEY"

Health

GET /health

Returns service health. No authentication required.

curl "https://YOUR_BASE_URL/health"

Expected response:

{
"status": "healthy",
"version": "0.1.0",
"environment": "production"
}

Error responses

All endpoints return standard HTTP status codes. Error bodies use this shape:

{
"detail": "Human-readable error message"
}
StatusMeaning
400Bad request — malformed JSON or missing required field
401Unauthorized — missing or invalid API key / token
404Not found — resource does not exist
409Conflict — duplicate resource
422Unprocessable entity — validation error (e.g. unknown rule ID, invalid severity)
502Bad gateway — upstream auth service unreachable