Skip to content

Shadow AI Discovery API

The Shadow AI Discovery API provides endpoints for discovering unauthorized AI service usage across your organization. Use these endpoints to query discovered services, manage the service catalog, ingest network and identity signals, view user activity, and configure alert rules.

For the admin guide covering data sources, the discovery dashboard, and deployment patterns, see Shadow AI Discovery Admin Guide.


All endpoints require authentication via Bearer token with admin role:

Authorization: Bearer <admin-api-key>

Base URL: https://gateway.arbitex.ai


Method Path Auth Description
GET /api/shadow-ai/services/ Bearer (admin) List discovered AI services with filtering and pagination

Query parameters:

Parameter Type Required Description
status string No Filter by classification: "sanctioned", "unsanctioned", "unknown"
category string No Filter by service category (e.g., "llm", "image_generation", "code_assistant")
page integer No Page number (default: 1)
per_page integer No Results per page (default: 20, max: 100)
sort_by string No Sort field: "last_seen" (default), "first_seen", "user_count", "name"
date_from string No ISO 8601 date; only return services seen on or after this date
date_to string No ISO 8601 date; only return services seen on or before this date

Example:

Terminal window
curl -s "https://gateway.arbitex.ai/api/shadow-ai/services/?status=unsanctioned&sort_by=user_count&per_page=10" \
-H "Authorization: Bearer $ADMIN_TOKEN"

Response (200 OK):

{
"data": [
{
"id": "svc_01j4ab5cd6e7f8gh9i0j1k2l",
"name": "ChatGPT",
"domains": ["chat.openai.com", "chatgpt.com"],
"category": "llm",
"status": "unsanctioned",
"user_count": 47,
"first_seen": "2026-02-14T09:12:33Z",
"last_seen": "2026-04-01T11:45:02Z",
"data_volume_bytes": 12483200,
"source_channels": ["proxy_log", "dns_log", "idp_events"]
}
],
"pagination": {
"page": 1,
"per_page": 10,
"total": 8,
"total_pages": 1
}
}

Response fields per service:

Field Type Description
id string Unique service identifier
name string Human-readable service name
domains string[] Known domains and API endpoints for this service
category string Service category ("llm", "image_generation", "code_assistant", "transcription", "other")
status string Classification: "sanctioned", "unsanctioned", "unknown"
user_count integer Distinct users who accessed this service
first_seen string ISO 8601 timestamp of first detected access
last_seen string ISO 8601 timestamp of most recent detected access
data_volume_bytes integer Estimated data volume where proxy data is available; null if DNS-only
source_channels string[] Detection channels: "proxy_log", "dns_log", "idp_events"

Method Path Auth Description
GET /api/shadow-ai/services/:id Bearer (admin) Get detailed information for a single discovered service

Path parameters:

Parameter Type Description
id string Service ID (e.g., svc_01j4ab5cd6e7f8gh9i0j1k2l)

Example:

Terminal window
curl -s https://gateway.arbitex.ai/api/shadow-ai/services/svc_01j4ab5cd6e7f8gh9i0j1k2l \
-H "Authorization: Bearer $ADMIN_TOKEN"

Response (200 OK):

{
"id": "svc_01j4ab5cd6e7f8gh9i0j1k2l",
"name": "ChatGPT",
"domains": ["chat.openai.com", "chatgpt.com"],
"category": "llm",
"status": "unsanctioned",
"user_count": 47,
"first_seen": "2026-02-14T09:12:33Z",
"last_seen": "2026-04-01T11:45:02Z",
"data_volume_bytes": 12483200,
"source_channels": ["proxy_log", "dns_log", "idp_events"],
"access_frequency": {
"daily_avg_7d": 132,
"daily_avg_30d": 98
},
"top_users": [
{
"user_id": "user_01j2mn3op4q5r6st7u8v9w0x",
"email": "[email protected]",
"access_count": 214,
"last_seen": "2026-04-01T11:45:02Z"
}
],
"classification_history": [
{
"from": "unknown",
"to": "unsanctioned",
"changed_by": "[email protected]",
"changed_at": "2026-02-15T14:30:00Z",
"note": "Not approved per security policy SP-2026-003"
}
]
}

Method Path Auth Description
GET /api/shadow-ai/services/:id/users Bearer (admin) List users who accessed a specific service

Path parameters:

Parameter Type Description
id string Service ID

Query parameters:

Parameter Type Required Description
page integer No Page number (default: 1)
per_page integer No Results per page (default: 20, max: 100)

Example:

Terminal window
curl -s "https://gateway.arbitex.ai/api/shadow-ai/services/svc_01j4ab5cd6e7f8gh9i0j1k2l/users?per_page=5" \
-H "Authorization: Bearer $ADMIN_TOKEN"

Response (200 OK):

{
"data": [
{
"user_id": "user_01j2mn3op4q5r6st7u8v9w0x",
"email": "[email protected]",
"display_name": "Jane Smith",
"access_count": 214,
"first_seen": "2026-02-14T09:12:33Z",
"last_seen": "2026-04-01T11:45:02Z",
"source_channels": ["proxy_log", "idp_events"]
}
],
"pagination": {
"page": 1,
"per_page": 5,
"total": 47,
"total_pages": 10
}
}

Method Path Auth Description
PATCH /api/shadow-ai/services/:id Bearer (admin) Update service classification

Path parameters:

Parameter Type Description
id string Service ID

Request body:

Field Type Required Description
status string Yes New classification: "sanctioned", "unsanctioned", "unknown"
note string No Reason for the classification change (recorded in the audit log)

Example:

Terminal window
curl -s -X PATCH https://gateway.arbitex.ai/api/shadow-ai/services/svc_01j4ab5cd6e7f8gh9i0j1k2l \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"status": "sanctioned",
"note": "Approved via security review SR-2026-041"
}'

Response (200 OK):

{
"id": "svc_01j4ab5cd6e7f8gh9i0j1k2l",
"name": "ChatGPT",
"status": "sanctioned",
"previous_status": "unsanctioned",
"changed_by": "[email protected]",
"changed_at": "2026-04-01T12:00:00Z",
"note": "Approved via security review SR-2026-041"
}

Classification changes are recorded in the audit log. See the Audit Log Management Guide for export and verification procedures.


Method Path Auth Description
GET /api/shadow-ai/users/ Bearer (admin) List all users with detected shadow AI activity

Query parameters:

Parameter Type Required Description
page integer No Page number (default: 1)
per_page integer No Results per page (default: 20, max: 100)
sort_by string No Sort field: "last_seen" (default), "service_count", "unsanctioned_count"
status string No Filter to users who accessed services with this classification

Example:

Terminal window
curl -s "https://gateway.arbitex.ai/api/shadow-ai/users/?sort_by=unsanctioned_count&per_page=10" \
-H "Authorization: Bearer $ADMIN_TOKEN"

Response (200 OK):

{
"data": [
{
"user_id": "user_01j2mn3op4q5r6st7u8v9w0x",
"email": "[email protected]",
"display_name": "Jane Smith",
"service_count": 5,
"unsanctioned_count": 3,
"first_seen": "2026-02-14T09:12:33Z",
"last_seen": "2026-04-01T11:45:02Z",
"services": [
{
"service_id": "svc_01j4ab5cd6e7f8gh9i0j1k2l",
"name": "ChatGPT",
"status": "unsanctioned",
"access_count": 214,
"last_seen": "2026-04-01T11:45:02Z"
}
]
}
],
"pagination": {
"page": 1,
"per_page": 10,
"total": 132,
"total_pages": 14
}
}

Response fields per user:

Field Type Description
user_id string User identifier (from IdP or proxy authentication)
email string User email address; null if identity resolved from IP only
display_name string Display name from IdP; null if unavailable
service_count integer Total AI services this user has accessed
unsanctioned_count integer Number of unsanctioned services accessed
first_seen string First detected shadow AI access
last_seen string Most recent detected access
services object[] Summary of services accessed (service_id, name, status, access_count, last_seen)

Method Path Auth Description
GET /api/shadow-ai/overview Bearer (admin) Organization-wide shadow AI summary

Example:

Terminal window
curl -s https://gateway.arbitex.ai/api/shadow-ai/overview \
-H "Authorization: Bearer $ADMIN_TOKEN"

Response (200 OK):

{
"total_services": 34,
"sanctioned": 8,
"unsanctioned": 12,
"unknown": 14,
"total_users": 132,
"users_unsanctioned_7d": 47,
"new_services_7d": 3,
"new_services_30d": 11,
"data_sources_active": 3,
"data_sources_total": 3
}

Response fields:

Field Type Description
total_services integer Total AI services discovered
sanctioned integer Services classified as sanctioned
unsanctioned integer Services classified as unsanctioned
unknown integer Services awaiting classification review
total_users integer Distinct users with any shadow AI activity
users_unsanctioned_7d integer Users who accessed unsanctioned services in the last 7 days
new_services_7d integer New services discovered in the last 7 days
new_services_30d integer New services discovered in the last 30 days
data_sources_active integer Number of configured data sources currently receiving data
data_sources_total integer Total configured data sources

These endpoints accept network and identity signals for shadow AI analysis. Use them when integrating custom log pipelines or forwarding events from infrastructure that does not use the built-in source connectors.

Method Path Auth Description
POST /api/shadow-ai/ingest/proxy-logs Bearer (admin) Ingest proxy log entries for AI service detection

Request body:

Field Type Required Description
entries object[] Yes Array of proxy log entries
entries[].timestamp string Yes ISO 8601 timestamp of the request
entries[].source_ip string Yes Source IP address
entries[].destination_host string Yes Destination hostname (e.g., "api.openai.com")
entries[].destination_port integer No Destination port (default: 443)
entries[].user_identity string No Authenticated user identity from the proxy
entries[].bytes_sent integer No Request payload size in bytes
entries[].bytes_received integer No Response payload size in bytes
entries[].http_method string No HTTP method (e.g., "POST")
entries[].url_path string No URL path (e.g., "/v1/chat/completions")

Example:

Terminal window
curl -s -X POST https://gateway.arbitex.ai/api/shadow-ai/ingest/proxy-logs \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"entries": [
{
"timestamp": "2026-04-01T10:30:00Z",
"source_ip": "10.0.1.42",
"destination_host": "api.openai.com",
"user_identity": "[email protected]",
"bytes_sent": 1024,
"bytes_received": 4096,
"http_method": "POST",
"url_path": "/v1/chat/completions"
}
]
}'

Response (202 Accepted):

{
"accepted": 1,
"rejected": 0,
"errors": []
}

Method Path Auth Description
POST /api/shadow-ai/ingest/dns-logs Bearer (admin) Ingest DNS query logs for AI service domain detection

Request body:

Field Type Required Description
entries object[] Yes Array of DNS query log entries
entries[].timestamp string Yes ISO 8601 timestamp of the query
entries[].source_ip string Yes IP address of the DNS client
entries[].query_name string Yes Queried domain name (e.g., "api.anthropic.com")
entries[].query_type string No DNS record type (default: "A")
entries[].resolver string No DNS resolver identifier

Example:

Terminal window
curl -s -X POST https://gateway.arbitex.ai/api/shadow-ai/ingest/dns-logs \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"entries": [
{
"timestamp": "2026-04-01T10:29:58Z",
"source_ip": "10.0.1.42",
"query_name": "api.anthropic.com",
"query_type": "A",
"resolver": "infoblox-primary"
}
]
}'

Response (202 Accepted):

{
"accepted": 1,
"rejected": 0,
"errors": []
}

Method Path Auth Description
POST /api/shadow-ai/ingest/idp-events Bearer (admin) Ingest IdP audit events for AI service SSO detection

Request body:

Field Type Required Description
entries object[] Yes Array of IdP audit events
entries[].timestamp string Yes ISO 8601 timestamp of the event
entries[].user_id string Yes User identifier from the IdP
entries[].user_email string No User email address
entries[].event_type string Yes IdP event type (e.g., "sso_login", "oauth_grant", "saml_assertion")
entries[].target_app string Yes Target application name as registered in the IdP
entries[].target_domain string No Target application domain
entries[].idp_vendor string No IdP vendor: "okta", "entra_id"

Example:

Terminal window
curl -s -X POST https://gateway.arbitex.ai/api/shadow-ai/ingest/idp-events \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"entries": [
{
"timestamp": "2026-04-01T10:28:00Z",
"user_id": "00u1a2b3c4d5e6f7g8h9",
"user_email": "[email protected]",
"event_type": "sso_login",
"target_app": "ChatGPT Enterprise",
"target_domain": "chat.openai.com",
"idp_vendor": "okta"
}
]
}'

Response (202 Accepted):

{
"accepted": 1,
"rejected": 0,
"errors": []
}

Method Path Auth Description
GET /api/shadow-ai/alerts/config Bearer (admin) Retrieve current alert configuration

Example:

Terminal window
curl -s https://gateway.arbitex.ai/api/shadow-ai/alerts/config \
-H "Authorization: Bearer $ADMIN_TOKEN"

Response (200 OK):

{
"triggers": {
"new_unsanctioned_service": true,
"new_unknown_service": true,
"unsanctioned_user_threshold": {
"enabled": true,
"threshold": 5
}
},
"webhook": {
"enabled": true,
"url": "https://hooks.example.com/shadow-ai-alerts",
"secret_configured": true
}
}

Method Path Auth Description
PUT /api/shadow-ai/alerts/config Bearer (admin) Update alert triggers and webhook configuration

Request body:

Field Type Required Description
triggers object No Alert trigger configuration
triggers.new_unsanctioned_service boolean No Alert on first sighting of an unsanctioned service
triggers.new_unknown_service boolean No Alert on first sighting of an uncataloged service
triggers.unsanctioned_user_threshold object No Alert when user count for an unsanctioned service exceeds threshold
triggers.unsanctioned_user_threshold.enabled boolean Yes (if parent provided) Enable or disable the threshold trigger
triggers.unsanctioned_user_threshold.threshold integer Yes (if parent provided) User count threshold (minimum: 1)
webhook object No Webhook delivery configuration
webhook.enabled boolean No Enable or disable webhook delivery
webhook.url string No Webhook URL (must be HTTPS)
webhook.secret string No HMAC-SHA256 signing secret for webhook payloads

Example:

Terminal window
curl -s -X PUT https://gateway.arbitex.ai/api/shadow-ai/alerts/config \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"triggers": {
"new_unsanctioned_service": true,
"new_unknown_service": true,
"unsanctioned_user_threshold": {
"enabled": true,
"threshold": 10
}
},
"webhook": {
"enabled": true,
"url": "https://hooks.example.com/shadow-ai-alerts",
"secret": "whsec_a1b2c3d4e5f6..."
}
}'

Response (200 OK):

{
"triggers": {
"new_unsanctioned_service": true,
"new_unknown_service": true,
"unsanctioned_user_threshold": {
"enabled": true,
"threshold": 10
}
},
"webhook": {
"enabled": true,
"url": "https://hooks.example.com/shadow-ai-alerts",
"secret_configured": true
}
}

Webhook payload:

Webhook deliveries include the following headers:

Header Description
X-Arbitex-Signature HMAC-SHA256 signature of the request body using the configured secret
Content-Type application/json

Webhook payload body example:

{
"trigger": "new_unsanctioned_service",
"service_id": "svc_01j4ab5cd6e7f8gh9i0j1k2l",
"service_name": "ChatGPT",
"classification": "unsanctioned",
"user_count": 1,
"timestamp": "2026-04-01T10:30:05Z"
}

Method Path Auth Description
GET /api/shadow-ai/sources Bearer (admin) List configured data sources and their connection status

Example:

Terminal window
curl -s https://gateway.arbitex.ai/api/shadow-ai/sources \
-H "Authorization: Bearer $ADMIN_TOKEN"

Response (200 OK):

{
"sources": [
{
"id": "src_01j5cd6ef7g8h9ij0k1l2m3n",
"type": "proxy_log",
"vendor": "zscaler",
"label": "Zscaler NSS Feed",
"delivery": "syslog",
"status": "connected",
"last_event_at": "2026-04-01T12:29:55Z",
"events_24h": 14832
},
{
"id": "src_01j5ef7gh8i9j0kl1m2n3o4p",
"type": "dns_log",
"vendor": "infoblox",
"label": "Infoblox WAPI",
"delivery": "api_pull",
"status": "connected",
"last_event_at": "2026-04-01T12:25:00Z",
"events_24h": 52410
},
{
"id": "src_01j5gh8ij9k0l1mn2o3p4q5r",
"type": "idp_events",
"vendor": "okta",
"label": "Okta System Log",
"delivery": "api_pull",
"status": "connected",
"last_event_at": "2026-04-01T12:29:00Z",
"events_24h": 3241
}
]
}

Response fields per source:

Field Type Description
id string Unique data source identifier
type string Source type: "proxy_log", "dns_log", "idp_events"
vendor string Vendor name (e.g., "zscaler", "infoblox", "okta")
label string Admin-provided label for this source
delivery string Delivery method: "syslog", "api_pull"
status string Connection status: "connected", "disconnected", "error"
last_event_at string ISO 8601 timestamp of the most recent event received
events_24h integer Number of events received in the last 24 hours

All paginated endpoints return results in the following format:

{
"data": [...],
"pagination": {
"page": 1,
"per_page": 20,
"total": 132,
"total_pages": 7
}
}
Field Type Description
page integer Current page number
per_page integer Results per page
total integer Total matching records
total_pages integer Total number of pages

Status Code Description
400 invalid_request Malformed request body or invalid query parameter value
400 invalid_status Status must be "sanctioned", "unsanctioned", or "unknown"
400 batch_too_large Ingestion batch exceeds 1000 entries
403 forbidden Authenticated user does not have admin role
404 service_not_found Service ID does not exist in the org
404 org_not_found Organization not found for the authenticated token
422 validation_error Required fields missing or field type mismatch in ingestion entries

Example error response:

{
"error": {
"code": "invalid_status",
"message": "status must be 'sanctioned', 'unsanctioned', or 'unknown'",
"field": "status"
}
}