Skip to main content
Sign in →

REST API Reference

Complete endpoint reference for the ShieldAgent management API. Base URL: https://api.shieldagent.io (self-hosted: http://localhost:<api-port>)

Authentication

All endpoints (except those marked public) require a JWT Bearer token in the Authorization header. Tokens are obtained via /auth/login or /auth/signup.

Example
curl https://api.shieldagent.io/tenants \
  -H 'Authorization: Bearer <your-jwt>' \
  -H 'Content-Type: application/json'

Error Format

All error responses follow a consistent JSON structure. Validation errors (400) include field-level details via Zod.

Error response
{
  "error": "Validation failed",
  "message": "Invalid request body",
  "issues": [
    { "path": ["name"], "message": "Required" },
    { "path": ["riskTier"], "message": "Invalid enum value" }
  ]
}
400Validation error — check issues array for field details
401Missing or invalid Authorization header
403Valid token but insufficient RBAC permissions
404Resource not found
409Conflict — duplicate resource (e.g. email already exists)
429Rate limit exceeded — see Retry-After header

Pagination

List endpoints that support pagination accept limit and offset query parameters and return a pagination object:

Paginated response
{
  "data": [ ... ],
  "pagination": {
    "total": 142,
    "limit": 50,
    "offset": 0,
    "hasMore": true
  }
}

Authentication

POST
/auth/signup

Register a new tenant and admin user. Returns a JWT.

Auth:none (public)

Rate-limited to 5 requests/minute.

ParameterInTypeRequiredDescription
emailbodystringyesUser email address
passwordbodystringyesMinimum 8 characters
tenantNamebodystringyesOrganization name
Request body
{
  "email": "admin@acme.com",
  "password": "s3cure-passw0rd",
  "tenantName": "Acme Corp"
}
Response 201
{
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "user": { "id": "u_01abc...", "email": "admin@acme.com", "role": "tenant_admin" },
  "tenant": { "id": "t_01xyz...", "name": "Acme Corp" }
}
POST
/auth/login

Authenticate with email and password. Returns a JWT.

Auth:none (public)

Rate-limited to 10 requests/minute. Returns 403 with SSORequired error if the account uses SSO.

ParameterInTypeRequiredDescription
emailbodystringyesUser email address
passwordbodystringyesUser password
Request body
{
  "email": "admin@acme.com",
  "password": "s3cure-passw0rd"
}
Response 200
{
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "user": { "id": "u_01abc...", "email": "admin@acme.com", "role": "tenant_admin" },
  "tenant": { "id": "t_01xyz...", "name": "Acme Corp" }
}
GET
/auth/me

Get the currently authenticated user profile.

Auth:Bearer token
Response 200
{
  "id": "u_01abc...",
  "email": "admin@acme.com",
  "role": "tenant_admin",
  "createdAt": "2026-01-15T10:30:00.000Z",
  "tenant": { "id": "t_01xyz...", "name": "Acme Corp" }
}
POST
/auth/refresh-entitlements

Refresh JWT with current plan tier and entitlements.

Auth:Bearer token
Response 200
{
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "user": { "id": "u_01abc...", "email": "admin@acme.com", "role": "tenant_admin" },
  "tenant": { "id": "t_01xyz...", "name": "Acme Corp" }
}

Tenants

POST
/tenants

Create a new tenant organization.

Auth:Bearer token|Permission:tenant:write
ParameterInTypeRequiredDescription
namebodystringyesTenant display name
planTierbodystringnoOne of: free, team, starter, pro, business, enterprise_cloud, enterprise_onprem. Defaults to free.
kmsKeyIdbodystringnoOptional KMS key for envelope encryption
Request body
{
  "name": "Acme Corp",
  "planTier": "pro"
}
Response 201
{
  "id": "t_01xyz...",
  "name": "Acme Corp",
  "planTier": "pro",
  "createdAt": "2026-04-24T12:00:00.000Z"
}
GET
/tenants

List tenants. Platform admins see all; others see only their own tenant.

Auth:Bearer token|Permission:tenant:read
Response 200
[
  {
    "id": "t_01xyz...",
    "name": "Acme Corp",
    "planTier": "pro",
    "createdAt": "2026-04-24T12:00:00.000Z"
  }
]
GET
/tenants/:tenantId

Get a single tenant by ID.

Auth:Bearer token|Permission:tenant:read
ParameterInTypeRequiredDescription
tenantIdpathuuidyesTenant UUID
PUT
/tenants/:tenantId

Update tenant fields.

Auth:Bearer token|Permission:tenant:write
ParameterInTypeRequiredDescription
tenantIdpathuuidyesTenant UUID
namebodystringnoUpdated tenant name
planTierbodystringnoNew plan tier
kmsKeyIdbodystringnoUpdated KMS key ID
DELETE
/tenants/:tenantId

Delete a tenant and all associated data.

Auth:Bearer token|Permission:tenant:write
ParameterInTypeRequiredDescription
tenantIdpathuuidyesTenant UUID
Response 200
{ "deleted": true, "id": "t_01xyz..." }

Users

GET
/tenants/:tenantId/users

List users in a tenant with their role assignments.

Auth:Bearer token|Permission:user:read
ParameterInTypeRequiredDescription
tenantIdpathuuidyesTenant UUID
Response 200
[
  {
    "id": "u_01abc...",
    "email": "admin@acme.com",
    "role": "tenant_admin",
    "active": true,
    "createdAt": "2026-01-15T10:30:00.000Z"
  }
]
POST
/tenants/:tenantId/users/invite

Invite a new user to the tenant.

Auth:Bearer token|Permission:user:write
ParameterInTypeRequiredDescription
tenantIdpathuuidyesTenant UUID
emailbodystringyesEmail address of the user to invite
passwordbodystringyesInitial password (min 8 characters)
rolebodystringnoOne of: tenant_admin, security_operator, auditor, aiops_engineer, viewer. Default: viewer
Request body
{
  "email": "analyst@acme.com",
  "password": "init-pass-123",
  "role": "security_operator"
}
Response 201
{
  "id": "u_02def...",
  "email": "analyst@acme.com",
  "role": "security_operator",
  "active": true,
  "createdAt": "2026-04-24T14:00:00.000Z"
}
PATCH
/tenants/:tenantId/users/:userId

Update a user's role or active status.

Auth:Bearer token|Permission:user:write
ParameterInTypeRequiredDescription
tenantIdpathuuidyesTenant UUID
userIdpathuuidyesUser UUID
rolebodystringnoNew role assignment
activebodybooleannoSet false to deactivate
DELETE
/tenants/:tenantId/users/:userId

Remove a user from the tenant. Users cannot delete themselves.

Auth:Bearer token|Permission:user:delete
ParameterInTypeRequiredDescription
tenantIdpathuuidyesTenant UUID
userIdpathuuidyesUser UUID
GET
/roles

List all available roles with their permissions.

Auth:Bearer token
Response 200
[
  {
    "id": "role_01...",
    "name": "security_operator",
    "scope": "tenant",
    "description": "Can triage incidents, manage alert rules, view audit logs",
    "isSystem": true,
    "permissions": ["incident:triage", "alert:write", "audit:read"]
  }
]

Agents

POST
/tenants/:tenantId/agents

Register a new AI agent. Automatically generates an agent passport.

Auth:Bearer token|Permission:agent:write
ParameterInTypeRequiredDescription
tenantIdpathuuidyesTenant UUID
namebodystringyesAgent display name
descriptionbodystringnoAgent description
riskTierbodystringnoInitial risk tier (low, medium, high, critical)
shadowModebodybooleannoStart in shadow mode (log-only, no enforcement)
Request body
{
  "name": "code-review-bot",
  "description": "Reviews pull requests and suggests fixes",
  "riskTier": "medium",
  "shadowMode": true
}
Response 201
{
  "id": "a_01abc...",
  "tenantId": "t_01xyz...",
  "name": "code-review-bot",
  "description": "Reviews pull requests and suggests fixes",
  "riskTier": "medium",
  "shadowMode": true,
  "status": "active",
  "createdAt": "2026-04-24T12:00:00.000Z"
}
GET
/tenants/:tenantId/agents

List all agents in a tenant.

Auth:Bearer token|Permission:agent:read
ParameterInTypeRequiredDescription
tenantIdpathuuidyesTenant UUID
GET
/tenants/:tenantId/agents/:agentId

Get agent details including current configuration.

Auth:Bearer token|Permission:agent:read
ParameterInTypeRequiredDescription
tenantIdpathuuidyesTenant UUID
agentIdpathuuidyesAgent UUID
PUT
/tenants/:tenantId/agents/:agentId

Update agent metadata, risk tier, or status.

Auth:Bearer token|Permission:agent:write
ParameterInTypeRequiredDescription
tenantIdpathuuidyesTenant UUID
agentIdpathuuidyesAgent UUID
namebodystringnoUpdated agent name
descriptionbodystringnoUpdated description
riskTierbodystringnoUpdated risk tier
statusbodystringnoactive or inactive
PATCH
/tenants/:tenantId/agents/:agentId

Toggle shadow mode for an agent.

Auth:Bearer token|Permission:agent:configure
ParameterInTypeRequiredDescription
tenantIdpathuuidyesTenant UUID
agentIdpathuuidyesAgent UUID
shadowModebodyboolean | nullyestrue to enable, false to disable, null to inherit tenant default
Request body
{ "shadowMode": false }
PUT
/tenants/:tenantId/agents/:agentId/security-config

Set per-agent security configuration (DLP strategy, ML thresholds).

Auth:Bearer token|Permission:agent:configure
ParameterInTypeRequiredDescription
tenantIdpathuuidyesTenant UUID
agentIdpathuuidyesAgent UUID
securityConfigbodyobject | nullyesSecurity config object, or null to reset to tenant defaults
Request body
{
  "securityConfig": {
    "dlpStrategy": "redact",
    "mlInjectionThreshold": 0.85
  }
}
PATCH
/tenants/:tenantId/agents/:agentId/baseline-config

Configure agent baseline learning period.

Auth:Bearer token|Permission:agent:configure
ParameterInTypeRequiredDescription
tenantIdpathuuidyesTenant UUID
agentIdpathuuidyesAgent UUID
learningDaysbodyintegeryesLearning period in days (1–30)
Request body
{ "learningDays": 14 }
GET
/tenants/:tenantId/agents/:agentId/baseline-config

Get agent baseline configuration including learning status and lock state.

Auth:Bearer token|Permission:agent:read
POST
/tenants/:tenantId/agents/:agentId/baseline/lock

Lock baselines — prevent drift updates from modifying the learned baseline.

Auth:Bearer token|Permission:agent:configure
POST
/tenants/:tenantId/agents/:agentId/baseline/unlock

Unlock baselines — allow drift updates again.

Auth:Bearer token|Permission:agent:configure
POST
/tenants/:tenantId/agents/:agentId/baseline/reset

Delete all baselines and restart the learning period.

Auth:Bearer token|Permission:agent:configure
ParameterInTypeRequiredDescription
learningDaysbodyintegernoNew learning period (1–30). Uses previous value if omitted.
DELETE
/tenants/:tenantId/agents/:agentId

Deregister an agent.

Auth:Bearer token|Permission:agent:delete
Response 200
{ "deleted": true, "id": "a_01abc..." }

Policies

POST
/tenants/:tenantId/policies

Create a policy rule that controls tool access for agents.

Auth:Bearer token|Permission:policy:write
ParameterInTypeRequiredDescription
tenantIdpathuuidyesTenant UUID
agentIdbodyuuidnoScope to a specific agent. Omit for tenant-wide policy.
toolNamebodystringyesMCP tool name to match (e.g. "bash", "file_write")
actionbodystringyesOne of: allow, deny, shadow
conditionsbodyobject | stringnoOptional conditions (JSON object or YAML string)
conditionsFormatbodystringnojson or yaml. Default: json
requiresHumanApprovalbodybooleannoRequire human review before execution
Request body
{
  "toolName": "bash",
  "action": "deny",
  "conditions": {
    "type": "param_contains",
    "field": "command",
    "value": "rm -rf"
  }
}
Response 201
{
  "id": "pol_01...",
  "tenantId": "t_01xyz...",
  "agentId": null,
  "toolName": "bash",
  "action": "deny",
  "conditions": { "type": "param_contains", "field": "command", "value": "rm -rf" },
  "requiresHumanApproval": false,
  "createdAt": "2026-04-24T12:00:00.000Z"
}
GET
/tenants/:tenantId/policies

List policies. Optionally filter by agent.

Auth:Bearer token|Permission:policy:read
ParameterInTypeRequiredDescription
tenantIdpathuuidyesTenant UUID
agentIdqueryuuidnoFilter to a specific agent
GET
/tenants/:tenantId/policies/:policyId

Get a single policy by ID.

Auth:Bearer token|Permission:policy:read
PUT
/tenants/:tenantId/policies/:policyId

Update a policy rule. Supports partial updates.

Auth:Bearer token|Permission:policy:write
DELETE
/tenants/:tenantId/policies/:policyId

Delete a policy rule.

Auth:Bearer token|Permission:policy:delete
GET
/tenants/:tenantId/policies/schema

Get the schema for supported condition types.

Auth:Bearer token|Permission:policy:read

Returns supported condition types: param_contains, param_matches, rate_limit, time_window, call_chain_depth, tool_breadth, first_use, risk_score_threshold, source_ip, origin_scope.

POST
/tenants/:tenantId/policies/validate

Validate policy conditions without persisting.

Auth:Bearer token|Permission:policy:read
Request body
{
  "conditions": {
    "type": "rate_limit",
    "maxCalls": 10,
    "windowSeconds": 60
  }
}
Response 200
{ "valid": true, "errors": [] }
GET
/tenants/:tenantId/policies/compiled

Get compiled policy rules in the format consumed by the proxy engine.

Auth:Bearer token|Permission:policy:read
POST
/tenants/:tenantId/policies/invalidate

Notify proxies to reload policy cache.

Auth:Bearer token|Permission:policy:write
Response 200
{ "invalidated": true, "tenantId": "t_01xyz...", "timestamp": "2026-04-24T12:05:00.000Z" }

Policy Templates

GET
/policy-templates

List system templates and tenant custom templates.

Auth:Bearer token|Permission:policy:read
POST
/tenants/:tenantId/policy-templates

Create a custom policy template.

Auth:Bearer token|Permission:policy:write
ParameterInTypeRequiredDescription
namebodystringyesTemplate name
descriptionbodystringnoTemplate description
categorybodystringyesOne of: security, compliance, development
rulesbodyarrayyesArray of {toolName, action, conditions?}
Request body
{
  "name": "Strict File Protection",
  "category": "security",
  "rules": [
    { "toolName": "file_write", "action": "deny" },
    { "toolName": "file_delete", "action": "deny" }
  ]
}
POST
/tenants/:tenantId/policy-templates/:templateId/apply

Apply a template — creates policies from its rules, deduplicating existing ones.

Auth:Bearer token|Permission:policy:write
Response 201
{
  "policiesCreated": 2,
  "policiesSkipped": 0,
  "policies": [ ... ]
}
PUT
/tenants/:tenantId/policy-templates/:templateId

Update a custom template. System templates are read-only.

Auth:Bearer token|Permission:policy:write
DELETE
/tenants/:tenantId/policy-templates/:templateId

Delete a custom template. Cannot delete system templates.

Auth:Bearer token|Permission:policy:write

Incidents

POST
/tenants/:tenantId/incidents

Create a security incident.

Auth:Bearer token|Permission:incident:write
ParameterInTypeRequiredDescription
tenantIdpathuuidyesTenant UUID
titlebodystringyesIncident title
severitybodystringyescritical, high, medium, or low
typebodystringyesIncident type (e.g. injection, data_leak, policy_violation)
agentIdbodyuuidnoRelated agent ID
databodyobjectnoArbitrary JSON payload with incident details
Request body
{
  "title": "Prompt injection detected on code-review-bot",
  "severity": "high",
  "type": "injection",
  "agentId": "a_01abc...",
  "data": { "toolName": "bash", "score": 0.97 }
}
Response 201
{
  "id": "inc_01...",
  "tenantId": "t_01xyz...",
  "title": "Prompt injection detected on code-review-bot",
  "severity": "high",
  "type": "injection",
  "status": "open",
  "createdAt": "2026-04-24T12:00:00.000Z"
}
GET
/tenants/:tenantId/incidents

List incidents with filtering and pagination.

Auth:Bearer token|Permission:incident:read
ParameterInTypeRequiredDescription
tenantIdpathuuidyesTenant UUID
statusquerystringnoFilter: open, investigating, resolved
severityquerystringnoFilter: critical, high, medium, low
agentIdqueryuuidnoFilter by agent
typequerystringnoFilter by incident type
limitqueryintegernoMax results (default 50, max 500)
offsetqueryintegernoPagination offset (default 0)
GET
/tenants/:tenantId/incidents/count

Get incident counts grouped by status.

Auth:Bearer token|Permission:incident:read
Response 200
{ "open": 3, "investigating": 1, "resolved": 42 }
PATCH
/tenants/:tenantId/incidents/:incidentId

Triage an incident — update status, severity, or title.

Auth:Bearer token|Permission:incident:triage
ParameterInTypeRequiredDescription
incidentIdpathuuidyesIncident UUID
statusbodystringnoNew status: open, investigating, resolved
severitybodystringnoUpdated severity
titlebodystringnoUpdated title
PATCH
/tenants/:tenantId/incidents/bulk

Bulk-update multiple incidents at once.

Auth:Bearer token|Permission:incident:triage
ParameterInTypeRequiredDescription
idsbodyuuid[]yesArray of incident UUIDs
statusbodystringnoNew status for all
severitybodystringnoNew severity for all
Request body
{
  "ids": ["inc_01...", "inc_02..."],
  "status": "resolved"
}
Response 200
{ "updated": 2, "incidents": [ ... ] }
DELETE
/tenants/:tenantId/incidents/:incidentId

Delete an incident.

Auth:Bearer token|Permission:incident:delete

Audit Trail

GET
/tenants/:tenantId/audit

Query the immutable audit trail with full-text search and filtering.

Auth:Bearer token|Permission:audit:read
ParameterInTypeRequiredDescription
tenantIdpathuuidyesTenant UUID
agentIdqueryuuidnoFilter by agent
toolNamequerystringnoFilter by tool name
outcomequerystringnoFilter: allowed, denied, shadow
threatTypequerystringnoFilter by threat type
keywordquerystringnoFull-text search across event data
fromquerystringnoStart date (ISO-8601)
toquerystringnoEnd date (ISO-8601)
limitqueryintegernoMax results (default 50, max 500)
offsetqueryintegernoPagination offset
orderByquerystringnoSort field (default: createdAt)
orderDirquerystringnoasc or desc (default: desc)
Response 200
{
  "data": [
    {
      "id": "evt_01...",
      "tenantId": "t_01xyz...",
      "agentId": "a_01abc...",
      "toolName": "bash",
      "outcome": "denied",
      "threatType": "injection",
      "data": { "score": 0.97, "policyId": "pol_01..." },
      "createdAt": "2026-04-24T12:00:00.000Z"
    }
  ],
  "pagination": { "total": 142, "limit": 50, "offset": 0, "hasMore": true }
}
GET
/tenants/:tenantId/audit/verify-chain

Verify the Merkle hash chain integrity for a range of events.

Auth:Bearer token|Permission:audit:read
ParameterInTypeRequiredDescription
fromIdquerystringnoStart event ID
toIdquerystringnoEnd event ID
Response 200
{
  "valid": true,
  "eventsVerified": 87,
  "fromId": "evt_01...",
  "toId": "evt_87..."
}
GET
/tenants/:tenantId/audit/merkle-snapshots

List hourly Merkle tree snapshots.

Auth:Bearer token|Permission:audit:read
ParameterInTypeRequiredDescription
limitqueryintegernoMax results
offsetqueryintegernoPagination offset
GET
/tenants/:tenantId/audit/verify-merkle-chain

Verify the entire Merkle chain with optional recomputation.

Auth:Bearer token|Permission:audit:read
ParameterInTypeRequiredDescription
recomputequerybooleannoRecompute Merkle roots from raw events (default: false)

Risk Scoring

GET
/tenants/:tenantId/risk

Get latest risk scores for all agents in a tenant.

Auth:Bearer token|Permission:risk:read
Response 200
[
  {
    "agentId": "a_01abc...",
    "agentName": "code-review-bot",
    "riskTier": "medium",
    "score": 42,
    "calculatedAt": "2026-04-24T12:00:00.000Z",
    "trend": "stable",
    "deltaVs24h": -3,
    "windows": { "1h": 40, "24h": 45, "7d": 42 }
  }
]
GET
/tenants/:tenantId/agents/:agentId/risk

Get latest risk score for a specific agent.

Auth:Bearer token|Permission:risk:read
GET
/tenants/:tenantId/agents/:agentId/risk/history

Get risk score time series for an agent.

Auth:Bearer token|Permission:risk:read
ParameterInTypeRequiredDescription
limitqueryintegernoMax data points (default 200, max 500)
fromquerystringnoStart date (ISO-8601)
toquerystringnoEnd date (ISO-8601)
POST
/tenants/:tenantId/agents/:agentId/risk/calculate

Trigger an on-demand risk score calculation.

Auth:Bearer token|Permission:risk:configure
ParameterInTypeRequiredDescription
versionbodystringnoScoring model version: v1 or v2
Response 200
{
  "version": "v2",
  "agentId": "a_01abc...",
  "score": 42,
  "securityScore": 35,
  "complianceScore": 50,
  "integrityScore": 40,
  "operationalScore": 45,
  "recommendations": [
    "Enable DLP redaction to reduce data-leak risk",
    "Lock agent baseline to prevent drift"
  ],
  "calculatedAt": "2026-04-24T12:05:00.000Z",
  "trend": "improving"
}
GET
/tenants/:tenantId/risk-config

Get risk enforcement thresholds for the tenant.

Auth:Bearer token|Permission:risk:read
Response 200
{
  "tenantId": "t_01xyz...",
  "enabled": true,
  "elevatedThreshold": 40,
  "highThreshold": 65,
  "criticalThreshold": 85,
  "elevatedRateMult": 0.5,
  "highRateMult": 0.1,
  "unknownAgentTier": "high",
  "gracePeriodSeconds": 300,
  "criticalAllowedMethods": ["tools/list"],
  "configured": true
}
PUT
/tenants/:tenantId/risk-config

Create or update risk enforcement thresholds.

Auth:Bearer token|Permission:risk:configure
ParameterInTypeRequiredDescription
enabledbodybooleannoEnable/disable enforcement
elevatedThresholdbodyintegeryesScore threshold for elevated tier (0–100)
highThresholdbodyintegeryesScore threshold for high tier (0–100)
criticalThresholdbodyintegeryesScore threshold for critical tier (0–100)
elevatedRateMultbodynumbernoRate limit multiplier for elevated tier (0–1)
highRateMultbodynumbernoRate limit multiplier for high tier (0–1)
unknownAgentTierbodystringnoDefault tier for unscored agents
gracePeriodSecondsbodyintegernoGrace period before enforcement activates
GET
/tenants/:tenantId/risk-enforcement/preview

Preview how current scores map to enforcement actions — no side effects.

Auth:Bearer token|Permission:risk:read
Response 200
[
  {
    "agentId": "a_01abc...",
    "agentName": "code-review-bot",
    "score": 42,
    "tier": "elevated",
    "wouldBlock": false,
    "wouldRateLimit": true,
    "rateLimitMultiplier": 0.5,
    "wouldForceShadow": false,
    "gracePeriodActive": false
  }
]
POST
/tenants/:tenantId/risk-overrides

Create a manual risk tier override for an agent.

Auth:Bearer token|Permission:risk:configure
ParameterInTypeRequiredDescription
agentIdbodyuuidyesAgent to override
overrideTierbodystringyesTier to override to: low, elevated, high, critical
reasonbodystringyesJustification for the override
categorybodystringyesOverride category
expiresAtbodystringnoExpiration (ISO-8601). Permanent if omitted.
Request body
{
  "agentId": "a_01abc...",
  "overrideTier": "low",
  "reason": "Verified safe after manual review",
  "category": "manual_review"
}
GET
/tenants/:tenantId/risk-overrides

List active risk tier overrides.

Auth:Bearer token|Permission:risk:read
DELETE
/tenants/:tenantId/risk-overrides/:overrideId

Revoke a risk tier override.

Auth:Bearer token|Permission:risk:configure

Compliance

Compliance endpoints support multiple frameworks: soc2, iso42001, nist-ai-rmf, and eu-ai-act.

GET
/tenants/:tenantId/compliance/gaps

Unified gap analysis across all supported compliance frameworks.

Auth:Bearer token|Permission:compliance:read
ParameterInTypeRequiredDescription
frameworkquerystringnosoc2, iso42001, nist-ai-rmf, or eu-ai-act (default: soc2)
agentIdqueryuuidnoScope to a specific agent
windowDaysqueryintegernoAnalysis window in days (default: 30, max: 365)
Response 200
{
  "framework": "soc2",
  "coveragePercent": 78,
  "totalControls": 42,
  "metControls": 33,
  "gaps": [
    {
      "controlId": "CC6.1",
      "title": "Logical Access Security",
      "severity": "major",
      "recommendation": "Enable MFA for all admin accounts"
    }
  ]
}
GET
/tenants/:tenantId/compliance/progress

Compliance progress over time for trend charts.

Auth:Bearer token|Permission:compliance:read
ParameterInTypeRequiredDescription
frameworkquerystringnoFramework (default: soc2)
daysqueryintegernoHistory window in days (default: 90, max: 365)
GET
/tenants/:tenantId/compliance/report

Generate a full SOC2 compliance report.

Auth:Bearer token|Permission:compliance:read
ParameterInTypeRequiredDescription
agentIdqueryuuidnoScope to a specific agent
windowDaysqueryintegernoReport window (default: 30)
GET
/tenants/:tenantId/compliance/status

Lightweight compliance summary for dashboard widgets.

Auth:Bearer token|Permission:compliance:read
GET
/tenants/:tenantId/compliance/{framework}/report

Framework-specific report. Replace {framework} with iso42001, nist-ai-rmf, etc.

Auth:Bearer token|Permission:compliance:read

Available sub-paths: /report, /status, /controls for each framework.

GET
/tenants/:tenantId/compliance/annex-iv/report

Generate an EU AI Act Annex IV technical documentation report.

Auth:Bearer token|Permission:compliance:read
ParameterInTypeRequiredDescription
windowDaysqueryintegernoReport window (default: 30)

Alerts

POST
/tenants/:tenantId/alert-rules

Create an alert rule with webhook or email channels.

Auth:Bearer token|Permission:alert:write
ParameterInTypeRequiredDescription
tenantIdpathuuidyesTenant UUID
namebodystringyesRule name
conditionbodyobjectyes{ metric, operator, threshold }
condition.metricbodystringyesrisk_score, anomaly_score, or compliance_score
condition.operatorbodystringyesgt, gte, lt, or lte
condition.thresholdbodynumberyesThreshold value (0–100)
channelsbodyarrayyesArray of {type, url?, to?}. Type: webhook or email
cooldownMinutesbodyintegernoMin minutes between firings (1–1440, default: 15)
enabledbodybooleannoActive on creation (default: true)
Request body
{
  "name": "High Risk Alert",
  "condition": {
    "metric": "risk_score",
    "operator": "gte",
    "threshold": 80
  },
  "channels": [
    { "type": "webhook", "url": "https://hooks.slack.com/..." },
    { "type": "email", "to": "security@acme.com" }
  ],
  "cooldownMinutes": 30
}
Response 201
{
  "id": "rule_01...",
  "tenantId": "t_01xyz...",
  "name": "High Risk Alert",
  "condition": { "metric": "risk_score", "operator": "gte", "threshold": 80 },
  "channels": [ ... ],
  "cooldownMinutes": 30,
  "enabled": true,
  "createdAt": "2026-04-24T12:00:00.000Z"
}
GET
/tenants/:tenantId/alert-rules

List alert rules. Optionally filter by enabled state.

Auth:Bearer token|Permission:alert:read
ParameterInTypeRequiredDescription
enabledquerybooleannoFilter by enabled true/false
PATCH
/tenants/:tenantId/alert-rules/:ruleId

Update an alert rule (partial update).

Auth:Bearer token|Permission:alert:write
DELETE
/tenants/:tenantId/alert-rules/:ruleId

Delete an alert rule.

Auth:Bearer token|Permission:alert:delete
GET
/tenants/:tenantId/alert-events

List alert firing events with pagination.

Auth:Bearer token|Permission:alert:read
ParameterInTypeRequiredDescription
ruleIdqueryuuidnoFilter by rule
limitqueryintegernoMax results (default 50, max 500)
offsetqueryintegernoPagination offset

MCP Servers

POST
/tenants/:tenantId/mcp-servers

Register an MCP server. Automatically discovers tools from upstream.

Auth:Bearer token|Permission:mcp_server:write
ParameterInTypeRequiredDescription
tenantIdpathuuidyesTenant UUID
namebodystringyesServer display name
descriptionbodystringnoServer description
upstreamUrlbodystringyesUpstream MCP server URL
Request body
{
  "name": "GitHub MCP",
  "description": "GitHub integration tools",
  "upstreamUrl": "http://localhost:8080/mcp"
}
Response 201
{
  "id": "mcp_01...",
  "name": "GitHub MCP",
  "upstreamUrl": "http://localhost:8080/mcp",
  "status": "active",
  "tools": [
    { "name": "create_issue", "description": "Create a GitHub issue" },
    { "name": "list_prs", "description": "List pull requests" }
  ],
  "createdAt": "2026-04-24T12:00:00.000Z"
}
GET
/tenants/:tenantId/mcp-servers

List registered MCP servers.

Auth:Bearer token|Permission:mcp_server:read
GET
/tenants/:tenantId/mcp-servers/:mcpServerId

Get an MCP server with its discovered tools.

Auth:Bearer token|Permission:mcp_server:read
PUT
/tenants/:tenantId/mcp-servers/:mcpServerId

Update MCP server name, description, URL, or status.

Auth:Bearer token|Permission:mcp_server:write
DELETE
/tenants/:tenantId/mcp-servers/:mcpServerId

Deregister an MCP server.

Auth:Bearer token|Permission:mcp_server:delete
POST
/tenants/:tenantId/mcp-servers/:mcpServerId/refresh-tools

Re-discover tools from the upstream server.

Auth:Bearer token|Permission:mcp_server:write
POST
/tenants/:tenantId/mcp-servers/:mcpServerId/scan

Run a security scan on the MCP server.

Auth:Bearer token|Permission:mcp_server:configure
Response 200
{
  "id": "scan_01...",
  "mcpServerId": "mcp_01...",
  "status": "completed",
  "findings": [
    {
      "severity": "high",
      "type": "unrestricted_tool",
      "tool": "bash",
      "description": "Tool allows arbitrary command execution"
    }
  ],
  "toolCount": 5,
  "scanDuration": 1240
}
GET
/tenants/:tenantId/mcp-servers/:mcpServerId/scans

Get scan history for an MCP server.

Auth:Bearer token|Permission:mcp_server:read
ParameterInTypeRequiredDescription
limitqueryintegernoMax results (default 20, max 100)
GET
/tenants/:tenantId/scans

Tenant-wide scan history across all MCP servers.

Auth:Bearer token|Permission:mcp_server:read
ParameterInTypeRequiredDescription
limitqueryintegernoMax results (default 50, max 200)

Reviews

Human-in-the-loop review queue for tool calls that require approval before execution.

GET
/tenants/:tenantId/reviews

List pending reviews with filtering and pagination.

Auth:Bearer token|Permission:review:read
ParameterInTypeRequiredDescription
statusquerystringnoFilter: pending, approved, denied
agentIdqueryuuidnoFilter by agent
limitqueryintegernoMax results (default 50, max 500)
offsetqueryintegernoPagination offset
GET
/tenants/:tenantId/reviews/count

Get review counts by status.

Auth:Bearer token|Permission:review:read
Response 200
{ "pending": 5, "approved": 120, "denied": 8 }
GET
/tenants/:tenantId/reviews/:reviewId

Get a single review with agent name.

Auth:Bearer token|Permission:review:read
POST
/tenants/:tenantId/reviews/:reviewId/decide

Approve or deny a pending review.

Auth:Bearer token|Permission:review:triage
ParameterInTypeRequiredDescription
decisionbodystringyesapproved or denied
commentbodystringnoOptional reviewer comment
Request body
{
  "decision": "approved",
  "comment": "Verified safe — one-time file access needed"
}

Notifications

GET
/tenants/:tenantId/notifications

List in-app notifications for the current user.

Auth:Bearer token
ParameterInTypeRequiredDescription
unreadOnlyquerybooleannoFilter to unread only
limitqueryintegernoMax results (default 50, max 200)
PATCH
/tenants/:tenantId/notifications/:id/read

Mark a single notification as read.

Auth:Bearer token
POST
/tenants/:tenantId/notifications/read-all

Mark all unread notifications as read.

Auth:Bearer token
Response 200
{ "marked": 12 }

Passports

Agent Passports provide verifiable identity cards for AI agents. Requires Business tier or above.

GET
/tenants/:tenantId/agents/:agentId/passport

Get an agent's passport with risk assessment, compliance status, and signature.

Auth:Bearer token|Permission:passport:read

Requires agent_passport feature entitlement (Business+ plan).

PATCH
/tenants/:tenantId/agents/:agentId/passport

Update passport display metadata.

Auth:Bearer token|Permission:passport:write
ParameterInTypeRequiredDescription
displayNamebodystringnoPublic display name
descriptionbodystringnoPublic description
avatarUrlbodystringnoAvatar image URL (SSRF-protected)
visibilitybodystringnoprivate, internal, or public
POST
/tenants/:tenantId/agents/:agentId/passport/refresh

Recompute and re-sign the passport with latest data.

Auth:Bearer token|Permission:passport:write
POST
/tenants/:tenantId/agents/:agentId/passport/publish

Publish the passport for external verification.

Auth:Bearer token|Permission:passport:write

Publishing as public requires elevated role (security_manager, tenant_admin, or platform_admin).

ParameterInTypeRequiredDescription
visibilitybodystringnopublic or internal (default: internal)
POST
/tenants/:tenantId/agents/:agentId/passport/unpublish

Unpublish a passport — sets visibility to private.

Auth:Bearer token|Permission:passport:write
GET
/public/passports/:tenantSlug/:agentSlug

View a published passport (public, unauthenticated).

Auth:none (public)

Rate-limited to 60 requests/minute per IP. Returns cached response (max-age 300s).

GET
/public/passports/:tenantSlug/:agentSlug/verify

Verify a passport's cryptographic signature (public, unauthenticated).

Auth:none (public)
Response 200
{
  "verified": true,
  "valid": true,
  "passportHash": "sha256:abc123...",
  "signature": "base64:...",
  "signedAt": "2026-04-24T12:00:00.000Z",
  "keyId": "key_01...",
  "publicKey": "-----BEGIN PUBLIC KEY-----..."
}
GET
/public/passports/:tenantSlug/:agentSlug/badge.svg

Render an embeddable SVG badge for the agent (public, unauthenticated).

Auth:none (public)

Rate-limited to 300 requests/minute per IP. Content-Type: image/svg+xml.

Billing

GET
/billing/status

Current plan tier and subscription status.

Auth:Bearer token|Permission:tenant:read
Response 200
{
  "planTier": "pro",
  "billingState": "active",
  "hasStripeCustomer": true,
  "hasSubscription": true
}
GET
/billing/entitlements

Feature entitlements and limits for the current plan.

Auth:Bearer token|Permission:tenant:read
Response 200
{
  "planTier": "pro",
  "billingState": "active",
  "entitlements": {
    "maxAgents": 50,
    "includedToolCalls": 100000,
    "retentionDays": 365,
    "features": ["agent_passport", "sso", "custom_policies"]
  }
}
GET
/billing/usage

Current month usage and plan limits.

Auth:Bearer token|Permission:tenant:read
Response 200
{
  "currentAgentCount": 12,
  "maxAgents": 50,
  "currentToolCalls": 45230,
  "includedToolCalls": 100000,
  "overageRate": 0.001,
  "billingPeriodStart": "2026-04-01T00:00:00.000Z",
  "billingPeriodEnd": "2026-04-30T23:59:59.999Z",
  "retentionDays": 365
}
POST
/billing/checkout

Create a Stripe Checkout session for plan upgrade.

Auth:Bearer token|Permission:tenant:write
ParameterInTypeRequiredDescription
tierbodystringyesTarget plan: free, team, starter, pro, business
successPathbodystringnoRedirect path after success
cancelPathbodystringnoRedirect path on cancel
Response 200
{ "checkoutUrl": "https://checkout.stripe.com/c/pay_..." }
POST
/billing/portal

Create a Stripe Customer Portal session for subscription management.

Auth:Bearer token|Permission:tenant:write
Response 200
{ "portalUrl": "https://billing.stripe.com/p/session_..." }

Export Configs

Configure automated audit trail export to S3, webhooks, or syslog destinations. Credentials are encrypted at rest (AES-256-GCM) and never returned in API responses.

POST
/tenants/:tenantId/export-configs

Create an export configuration.

Auth:Bearer token|Permission:export:write
ParameterInTypeRequiredDescription
namebodystringyesConfig display name
destinationTypebodystringyess3, webhook, or syslog
configbodyobjectyesDestination-specific config (bucket, url, host, etc.)
credentialsbodyobjectnoAuth credentials (encrypted at rest, never returned)
filtersbodyobjectnoEvent filters (agent, tool, outcome, etc.)
intervalSecondsbodyintegernoExport interval (30–86400 seconds)
formatbodystringnondjson or json (default: ndjson)
enabledbodybooleannoActive on creation (default: true)
Request body
{
  "name": "S3 Audit Export",
  "destinationType": "s3",
  "config": {
    "bucket": "acme-audit-logs",
    "region": "eu-west-1",
    "prefix": "shieldagent/"
  },
  "credentials": {
    "accessKeyId": "AKIA...",
    "secretAccessKey": "wJalr..."
  },
  "intervalSeconds": 300,
  "format": "ndjson"
}
GET
/tenants/:tenantId/export-configs

List export configs (credentials redacted).

Auth:Bearer token|Permission:export:read
PATCH
/tenants/:tenantId/export-configs/:configId

Update an export config (partial update, credentials redacted in response).

Auth:Bearer token|Permission:export:write
DELETE
/tenants/:tenantId/export-configs/:configId

Delete an export configuration.

Auth:Bearer token|Permission:export:delete
POST
/tenants/:tenantId/export-configs/:configId/test

Test the export adapter connection.

Auth:Bearer token|Permission:export:write
Response 200
{ "success": true, "latencyMs": 245 }

Verdict API

Enforcement responsibility

The Verdict API runs the full ShieldAgent security pipeline and returns a verdict. Your server code is responsible for enforcing that verdict — ShieldAgent does not forward or block traffic directly. If your code ignores a block verdict, the tool call executes anyway. All scan verdicts are recorded in the audit trail with source: "verdict_api"; anomaly detection can flag agents with 100% block verdicts but continued tool execution.

The Verdict API enables server-side scanning for customers who own and operate their own API or MCP server. Instead of routing traffic through the ShieldAgent proxy, your server submits the request payload to ShieldAgent, receives a security verdict, and enforces it locally. The agent's communication with your server is unchanged — no MCP messages are modified, no HTTP headers are added.

Auth model — tenant API key, not user JWT

Verdict API endpoints authenticate with a tenant-scoped API key (Bearer token), not the user JWT issued by /auth/login. Treat this key as a server-side secret — never expose it to agent clients.

Base URL (proxy service): https://proxy.shieldagent.io  |  Self-hosted: http://localhost:3100

POST
/tenants/:tenantId/scan

Submit a tool call or API request for security scanning. Returns a verdict (allow / block / human_review). Your server must enforce the verdict — ShieldAgent does not forward traffic.

Auth:Bearer token

Auth: Bearer <tenant-api-key>. Rate-limited per tenant and per agent (Redis-backed). An audit event is written on every call with source: "verdict_api". The full security pipeline runs — forwarding is skipped.

ParameterInTypeRequiredDescription
tenantIdpathstring (uuid)yesYour tenant UUID
agentIdbodystring (uuid)noShieldAgent agent UUID. Optional — omit when your server cannot identify the caller (e.g. typical MCP server, which has no agent identity in the protocol). When provided the agent must belong to this tenant; cross-tenant IDs are rejected with 403. When omitted the pipeline runs with tenant-level policies only.
clientHintbodystringnoMCP clientInfo.name or similar client software identifier (e.g. "Claude Desktop"). Used for best-effort agent matching when agentId is unavailable: if exactly one registered agent matches, per-agent policies apply; otherwise falls back to tenant-level. Ignored when agentId is provided.
toolNamebodystringyesName of the tool being called (e.g. "read_file", "api:POST:/payments")
paramsbodyobjectyesTool call parameters as a JSON object
include_findingsbodybooleannoRequest detailed findings in the response. Requires the verdictDetailedFindings tenant permission flag (off by default — see Response Tiering below). Without permission this field is ignored.
context.transportbody"mcp" | "rest" | "custom"noTransport protocol between agent and your server
context.sourceIpbodystringnoIP address of the agent. Used for per-IP rate limiting.
context.sessionIdbodystringnoSession identifier. Used for excessive agency detection across calls in the same session.
Request body
{
  "agentId": "a1b2c3d4-0000-0000-0000-000000000001",  // optional
  "clientHint": "Claude Desktop",                       // optional
  "toolName": "read_file",
  "params": { "path": "/etc/passwd" },
  "include_findings": false,
  "context": {
    "transport": "mcp",
    "sourceIp": "10.0.1.5",
    "sessionId": "sess-abc123"
  }
}
Response 200 — default tier (all callers)
{
  "action": "block",              // "allow" | "block" | "human_review"
  "reason": "Security threat detected",
  "riskScore": 87,
  "auditEventId": "evt-a1b2c3d4-0000-0000-0000-000000000001",
  "reviewId": null                // set when action is "human_review"
}

Response tiering — include_findings: true + verdictDetailedFindings tenant permission

Detailed findings are off by default. The default response deliberately omits scanner names, detection patterns, and strategy details to prevent iterative evasion attacks (mirrors the DLP findings model). Enable only for debugging or integration testing.

Response 200 — detailed tier
{
  "action": "block",
  "reason": "Prompt injection detected in tool arguments",
  "findings": [
    {
      "type": "injection",
      "severity": "critical",
      "detail": "Path traversal pattern detected",
      "scanner": "regex"
    }
  ],
  "riskScore": 87,
  "auditEventId": "evt-a1b2c3d4-...",
  "reviewId": null
}

Error responses

401Missing or invalid tenant API key
403agentId does not belong to this tenant (cross-tenant spoofing rejected)
429Rate limit exceeded — per-tenant or per-agent limit. See Retry-After header.

When to omit agentId

ScenarioagentIdPipeline behaviour
MCP server (typical)omitTenant-level policies only. Optionally pass clientHint from the MCP clientInfo.name handshake.
HTTP API with agent auth mappingprovideFull per-agent pipeline: policies, risk score, rate limits, baseline, approved tools.
HTTP API without agent mappingomitTenant-level policies only. Rate limiting applies per-tenant.
POST
/tenants/:tenantId/verdict-confirmations

Report whether a verdict was enforced by your server. Optional callback that closes the audit loop and satisfies EU AI Act Art. 9 enforcement evidence requirements. Tenants that never call this show as 'enforcement unknown' in compliance reports.

Auth:Bearer token

Not required — enforcement confirmation is voluntary. Contributes to the Verdict Enforcement Rate metric in Grafana. Call after executing or rejecting the tool call, not before.

ParameterInTypeRequiredDescription
tenantIdpathstring (uuid)yesYour tenant UUID
auditEventIdbodystring (uuid)yesThe auditEventId returned by POST /scan
executedbodybooleanyestrue if the tool call was executed (verdict was "allow" or human review approved); false if it was rejected (verdict was "block" or human review denied)
Request body
{
  "auditEventId": "evt-a1b2c3d4-0000-0000-0000-000000000001",
  "executed": false
}
Response 200
{ "recorded": true }

Health

GET
/healthz

Liveness probe. Returns service status and timestamp.

Auth:none (public)

Excluded from rate limiting. Use for Kubernetes liveness/readiness probes.

Response 200
{
  "status": "ok",
  "timestamp": "2026-04-24T12:00:00.000Z"
}

OpenAPI Specification

The full OpenAPI 3.1.0 spec is available for import into Postman, Insomnia, or any OpenAPI-compatible tool. See the OpenAPI Reference page for spec URLs and client generation instructions.

bash
# Serve Swagger UI locally
npx @redocly/cli preview-docs docs/openapi/shieldagent-api.yaml