Skip to main content

Security overview API

Reference

Lookup material for the Security overview endpoint in Nirmata AIControls. It returns finding counts, gateway request outcomes, the trend, and shadow AI exposure for a time window, in bounded, cached reads. A read that is slow becomes a partial section with a reason code instead of failing the whole response.

Endpoint​

GET /api/v1/security-dashboard returns JSON. It runs on the same dedicated read capacity as the Cost overview API, so a slow Security read does not compete with analytics queries.

Authorization​

The response is shared across viewers, so the endpoint accepts only admin and viewer tokens. A builder or developer token receives 403, and a request with missing or invalid credentials receives 401. Authorization always runs before any cached response is returned. A request that has a token query parameter is rejected with 400 before AIControls looks at the token.

Parameters​

ParameterDescription
from, toThe window, as UTC RFC 3339 timestamps that end in Z and have whole seconds, for example 2026-10-10T09:14:00Z. Required. The start is included and the end is excluded. The window can be at most 31 days.
refreshSet to 1 to recompute instead of serving the cached response. AIControls honors a refresh at most once every 10 seconds per response, across all replicas; a refresh inside that interval returns the cached response. The Retry button on Home, Security uses it.
userLimit to a recorded user.
agentLimit to a recorded agent.
sessionLimit to a session.
workload, clusterLimit to a workload (namespace/Kind/name) in a cluster. Both are needed together.

Any other parameter returns 400. The Home page offers the last 24 hours and the last 7 days. The endpoint also accepts other window lengths up to 31 days, for example from a saved link.

The response describes the window and the equal-length window before it, so each count carries a comparison.

Section status​

The response is made of four independent reads. Each has a status in sections: ok, partial, or unavailable. When the status isn't ok, the section has a reason. The endpoint answers 200 even when every section fails.

SectionCovers
contextQualification of the sources for the scope. Only reads data when session is set.
findingsFinding groups, affected users and agents, and the trend, for the window and the previous window.
gatewayGateway requests, denials, response blocks, redactions, and holds, for the window and the previous window.
shadowShadow AI exposure counts.
ReasonMeaning
timeoutThe read did not finish within its 2-second deadline.
lane_busyThe dashboard read capacity was full. Retry shortly.
not_readyThe daily rollup that serves a window longer than 25 hours is still being built (after an upgrade or a data reset) or is being repaired after a retention purge. Only the shadow read uses it. It clears on its own, usually within a few job runs.
computing_elsewhereAnother replica is computing the response and no recent response was available to serve.
unavailableThe data store isn't configured, or the source can't answer for this scope.
errorAn internal error, which is logged and not included in the response.

A value that could not be read is null with reasonCode set to section_ followed by the reason, for example section_timeout. It is never reported as zero. If only the previous window of a section failed, the current value is still returned, without a comparison, and reasonCode is previous_window_ followed by the reason. A failed read also adds a dashboard_<section>_<reason> entry to completeness.gaps. When the findings or context read fails, no source is reported as succeeded: each shows queryState unavailable with reasonCode section_ followed by the reason.

Caching​

Responses are cached for 45 seconds. A response in which any section is not ok is cached for only 5 seconds, so partial results recover quickly. Errors are never cached.

The cache key contains the exact from and to, and every scope filter, so two requests that differ in any of them never share an entry. The same scope sent with its parameters in a different order does share one. Concurrent requests for the same key run the reads once.

With SQLite, each process keeps its own cache. With PostgreSQL, replicas share a cache table: one replica computes a response while the others serve the previous response with stale set, for up to twice the cache lifetime, or wait for the result. cached is true when a stored response was served.

Resetting data clears the cache.

Response fields​

FieldDescription
scope, previousScopeThe window and filters that were read, and the preceding equal window.
asOfWhen the response was computed. A cached response keeps its own asOf.
cached, stale, staleAgeSecondsCache state. stale and staleAgeSeconds appear only when true.
sectionsThe status of each read, as above.
metricsfindingGroups, gatewayRequests, requestsDenied, responsesBlocked, responsesRedacted, historicalHolds, affectedUsers, affectedAgents. Each has current, previous, delta, percentChange, and reasonCode.
trendUp to 24 buckets of finding groups, with the previous window's count for each.
shadowAgents without an inventory identity, unregistered MCP servers, workloads, tools, and agents using unregistered MCP.
sources, completenessWhich sources were read and what coverage gaps apply.

Example​

curl -s -H "Authorization: Bearer $TOKEN" \
"https://aicontrols.example.com/api/v1/security-dashboard?from=2026-10-10T09:14:00Z&to=2026-10-11T09:14:00Z"
{
"asOf": "2026-10-11T09:14:03Z",
"cached": false,
"sections": {
"context": { "status": "ok" },
"findings": { "status": "ok" },
"gateway": { "status": "ok" },
"shadow": { "status": "partial", "reason": "timeout" }
},
"metrics": {
"gatewayRequests": { "current": 1840, "previous": 1622, "delta": 218, "percentChange": 13.4, "reasonCode": "retained_history_coverage_unknown" }
},
"shadow": { "agentsWithoutInventoryIdentity": null, "reasonCodes": ["section_timeout"] }
}