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.
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": "Validation failed",
"message": "Invalid request body",
"issues": [
{ "path": ["name"], "message": "Required" },
{ "path": ["riskTier"], "message": "Invalid enum value" }
]
}Pagination
List endpoints that support pagination accept limit and offset query parameters and return a pagination object:
{
"data": [ ... ],
"pagination": {
"total": 142,
"limit": 50,
"offset": 0,
"hasMore": true
}
}Authentication
/auth/signupRegister a new tenant and admin user. Returns a JWT.
Rate-limited to 5 requests/minute.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| body | string | yes | User email address | |
| password | body | string | yes | Minimum 8 characters |
| tenantName | body | string | yes | Organization name |
{
"email": "admin@acme.com",
"password": "s3cure-passw0rd",
"tenantName": "Acme Corp"
}{
"token": "eyJhbGciOiJIUzI1NiIs...",
"user": { "id": "u_01abc...", "email": "admin@acme.com", "role": "tenant_admin" },
"tenant": { "id": "t_01xyz...", "name": "Acme Corp" }
}/auth/loginAuthenticate with email and password. Returns a JWT.
Rate-limited to 10 requests/minute. Returns 403 with SSORequired error if the account uses SSO.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| body | string | yes | User email address | |
| password | body | string | yes | User password |
{
"email": "admin@acme.com",
"password": "s3cure-passw0rd"
}{
"token": "eyJhbGciOiJIUzI1NiIs...",
"user": { "id": "u_01abc...", "email": "admin@acme.com", "role": "tenant_admin" },
"tenant": { "id": "t_01xyz...", "name": "Acme Corp" }
}/auth/meGet the currently authenticated user profile.
{
"id": "u_01abc...",
"email": "admin@acme.com",
"role": "tenant_admin",
"createdAt": "2026-01-15T10:30:00.000Z",
"tenant": { "id": "t_01xyz...", "name": "Acme Corp" }
}/auth/refresh-entitlementsRefresh JWT with current plan tier and entitlements.
{
"token": "eyJhbGciOiJIUzI1NiIs...",
"user": { "id": "u_01abc...", "email": "admin@acme.com", "role": "tenant_admin" },
"tenant": { "id": "t_01xyz...", "name": "Acme Corp" }
}Tenants
/tenantsCreate a new tenant organization.
tenant:write| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| name | body | string | yes | Tenant display name |
| planTier | body | string | no | One of: free, team, starter, pro, business, enterprise_cloud, enterprise_onprem. Defaults to free. |
| kmsKeyId | body | string | no | Optional KMS key for envelope encryption |
{
"name": "Acme Corp",
"planTier": "pro"
}{
"id": "t_01xyz...",
"name": "Acme Corp",
"planTier": "pro",
"createdAt": "2026-04-24T12:00:00.000Z"
}/tenantsList tenants. Platform admins see all; others see only their own tenant.
tenant:read[
{
"id": "t_01xyz...",
"name": "Acme Corp",
"planTier": "pro",
"createdAt": "2026-04-24T12:00:00.000Z"
}
]/tenants/:tenantIdGet a single tenant by ID.
tenant:read| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| tenantId | path | uuid | yes | Tenant UUID |
/tenants/:tenantIdUpdate tenant fields.
tenant:write| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| tenantId | path | uuid | yes | Tenant UUID |
| name | body | string | no | Updated tenant name |
| planTier | body | string | no | New plan tier |
| kmsKeyId | body | string | no | Updated KMS key ID |
/tenants/:tenantIdDelete a tenant and all associated data.
tenant:write| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| tenantId | path | uuid | yes | Tenant UUID |
{ "deleted": true, "id": "t_01xyz..." }Users
/tenants/:tenantId/usersList users in a tenant with their role assignments.
user:read| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| tenantId | path | uuid | yes | Tenant UUID |
[
{
"id": "u_01abc...",
"email": "admin@acme.com",
"role": "tenant_admin",
"active": true,
"createdAt": "2026-01-15T10:30:00.000Z"
}
]/tenants/:tenantId/users/inviteInvite a new user to the tenant.
user:write| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| tenantId | path | uuid | yes | Tenant UUID |
| body | string | yes | Email address of the user to invite | |
| password | body | string | yes | Initial password (min 8 characters) |
| role | body | string | no | One of: tenant_admin, security_operator, auditor, aiops_engineer, viewer. Default: viewer |
{
"email": "analyst@acme.com",
"password": "init-pass-123",
"role": "security_operator"
}{
"id": "u_02def...",
"email": "analyst@acme.com",
"role": "security_operator",
"active": true,
"createdAt": "2026-04-24T14:00:00.000Z"
}/tenants/:tenantId/users/:userIdUpdate a user's role or active status.
user:write| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| tenantId | path | uuid | yes | Tenant UUID |
| userId | path | uuid | yes | User UUID |
| role | body | string | no | New role assignment |
| active | body | boolean | no | Set false to deactivate |
/tenants/:tenantId/users/:userIdRemove a user from the tenant. Users cannot delete themselves.
user:delete| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| tenantId | path | uuid | yes | Tenant UUID |
| userId | path | uuid | yes | User UUID |
/rolesList all available roles with their permissions.
[
{
"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
/tenants/:tenantId/agentsRegister a new AI agent. Automatically generates an agent passport.
agent:write| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| tenantId | path | uuid | yes | Tenant UUID |
| name | body | string | yes | Agent display name |
| description | body | string | no | Agent description |
| riskTier | body | string | no | Initial risk tier (low, medium, high, critical) |
| shadowMode | body | boolean | no | Start in shadow mode (log-only, no enforcement) |
{
"name": "code-review-bot",
"description": "Reviews pull requests and suggests fixes",
"riskTier": "medium",
"shadowMode": true
}{
"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"
}/tenants/:tenantId/agentsList all agents in a tenant.
agent:read| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| tenantId | path | uuid | yes | Tenant UUID |
/tenants/:tenantId/agents/:agentIdGet agent details including current configuration.
agent:read| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| tenantId | path | uuid | yes | Tenant UUID |
| agentId | path | uuid | yes | Agent UUID |
/tenants/:tenantId/agents/:agentIdUpdate agent metadata, risk tier, or status.
agent:write| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| tenantId | path | uuid | yes | Tenant UUID |
| agentId | path | uuid | yes | Agent UUID |
| name | body | string | no | Updated agent name |
| description | body | string | no | Updated description |
| riskTier | body | string | no | Updated risk tier |
| status | body | string | no | active or inactive |
/tenants/:tenantId/agents/:agentIdToggle shadow mode for an agent.
agent:configure| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| tenantId | path | uuid | yes | Tenant UUID |
| agentId | path | uuid | yes | Agent UUID |
| shadowMode | body | boolean | null | yes | true to enable, false to disable, null to inherit tenant default |
{ "shadowMode": false }/tenants/:tenantId/agents/:agentId/security-configSet per-agent security configuration (DLP strategy, ML thresholds).
agent:configure| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| tenantId | path | uuid | yes | Tenant UUID |
| agentId | path | uuid | yes | Agent UUID |
| securityConfig | body | object | null | yes | Security config object, or null to reset to tenant defaults |
{
"securityConfig": {
"dlpStrategy": "redact",
"mlInjectionThreshold": 0.85
}
}/tenants/:tenantId/agents/:agentId/baseline-configConfigure agent baseline learning period.
agent:configure| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| tenantId | path | uuid | yes | Tenant UUID |
| agentId | path | uuid | yes | Agent UUID |
| learningDays | body | integer | yes | Learning period in days (1–30) |
{ "learningDays": 14 }/tenants/:tenantId/agents/:agentId/baseline-configGet agent baseline configuration including learning status and lock state.
agent:read/tenants/:tenantId/agents/:agentId/baseline/lockLock baselines — prevent drift updates from modifying the learned baseline.
agent:configure/tenants/:tenantId/agents/:agentId/baseline/unlockUnlock baselines — allow drift updates again.
agent:configure/tenants/:tenantId/agents/:agentId/baseline/resetDelete all baselines and restart the learning period.
agent:configure| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| learningDays | body | integer | no | New learning period (1–30). Uses previous value if omitted. |
/tenants/:tenantId/agents/:agentIdDeregister an agent.
agent:delete{ "deleted": true, "id": "a_01abc..." }Policies
/tenants/:tenantId/policiesCreate a policy rule that controls tool access for agents.
policy:write| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| tenantId | path | uuid | yes | Tenant UUID |
| agentId | body | uuid | no | Scope to a specific agent. Omit for tenant-wide policy. |
| toolName | body | string | yes | MCP tool name to match (e.g. "bash", "file_write") |
| action | body | string | yes | One of: allow, deny, shadow |
| conditions | body | object | string | no | Optional conditions (JSON object or YAML string) |
| conditionsFormat | body | string | no | json or yaml. Default: json |
| requiresHumanApproval | body | boolean | no | Require human review before execution |
{
"toolName": "bash",
"action": "deny",
"conditions": {
"type": "param_contains",
"field": "command",
"value": "rm -rf"
}
}{
"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"
}/tenants/:tenantId/policiesList policies. Optionally filter by agent.
policy:read| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| tenantId | path | uuid | yes | Tenant UUID |
| agentId | query | uuid | no | Filter to a specific agent |
/tenants/:tenantId/policies/:policyIdGet a single policy by ID.
policy:read/tenants/:tenantId/policies/:policyIdUpdate a policy rule. Supports partial updates.
policy:write/tenants/:tenantId/policies/:policyIdDelete a policy rule.
policy:delete/tenants/:tenantId/policies/schemaGet the schema for supported condition types.
policy:readReturns 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.
/tenants/:tenantId/policies/validateValidate policy conditions without persisting.
policy:read{
"conditions": {
"type": "rate_limit",
"maxCalls": 10,
"windowSeconds": 60
}
}{ "valid": true, "errors": [] }/tenants/:tenantId/policies/compiledGet compiled policy rules in the format consumed by the proxy engine.
policy:read/tenants/:tenantId/policies/invalidateNotify proxies to reload policy cache.
policy:write{ "invalidated": true, "tenantId": "t_01xyz...", "timestamp": "2026-04-24T12:05:00.000Z" }Policy Templates
/policy-templatesList system templates and tenant custom templates.
policy:read/tenants/:tenantId/policy-templatesCreate a custom policy template.
policy:write| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| name | body | string | yes | Template name |
| description | body | string | no | Template description |
| category | body | string | yes | One of: security, compliance, development |
| rules | body | array | yes | Array of {toolName, action, conditions?} |
{
"name": "Strict File Protection",
"category": "security",
"rules": [
{ "toolName": "file_write", "action": "deny" },
{ "toolName": "file_delete", "action": "deny" }
]
}/tenants/:tenantId/policy-templates/:templateId/applyApply a template — creates policies from its rules, deduplicating existing ones.
policy:write{
"policiesCreated": 2,
"policiesSkipped": 0,
"policies": [ ... ]
}/tenants/:tenantId/policy-templates/:templateIdUpdate a custom template. System templates are read-only.
policy:write/tenants/:tenantId/policy-templates/:templateIdDelete a custom template. Cannot delete system templates.
policy:writeIncidents
/tenants/:tenantId/incidentsCreate a security incident.
incident:write| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| tenantId | path | uuid | yes | Tenant UUID |
| title | body | string | yes | Incident title |
| severity | body | string | yes | critical, high, medium, or low |
| type | body | string | yes | Incident type (e.g. injection, data_leak, policy_violation) |
| agentId | body | uuid | no | Related agent ID |
| data | body | object | no | Arbitrary JSON payload with incident details |
{
"title": "Prompt injection detected on code-review-bot",
"severity": "high",
"type": "injection",
"agentId": "a_01abc...",
"data": { "toolName": "bash", "score": 0.97 }
}{
"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"
}/tenants/:tenantId/incidentsList incidents with filtering and pagination.
incident:read| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| tenantId | path | uuid | yes | Tenant UUID |
| status | query | string | no | Filter: open, investigating, resolved |
| severity | query | string | no | Filter: critical, high, medium, low |
| agentId | query | uuid | no | Filter by agent |
| type | query | string | no | Filter by incident type |
| limit | query | integer | no | Max results (default 50, max 500) |
| offset | query | integer | no | Pagination offset (default 0) |
/tenants/:tenantId/incidents/countGet incident counts grouped by status.
incident:read{ "open": 3, "investigating": 1, "resolved": 42 }/tenants/:tenantId/incidents/:incidentIdTriage an incident — update status, severity, or title.
incident:triage| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| incidentId | path | uuid | yes | Incident UUID |
| status | body | string | no | New status: open, investigating, resolved |
| severity | body | string | no | Updated severity |
| title | body | string | no | Updated title |
/tenants/:tenantId/incidents/bulkBulk-update multiple incidents at once.
incident:triage| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| ids | body | uuid[] | yes | Array of incident UUIDs |
| status | body | string | no | New status for all |
| severity | body | string | no | New severity for all |
{
"ids": ["inc_01...", "inc_02..."],
"status": "resolved"
}{ "updated": 2, "incidents": [ ... ] }/tenants/:tenantId/incidents/:incidentIdDelete an incident.
incident:deleteAudit Trail
/tenants/:tenantId/auditQuery the immutable audit trail with full-text search and filtering.
audit:read| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| tenantId | path | uuid | yes | Tenant UUID |
| agentId | query | uuid | no | Filter by agent |
| toolName | query | string | no | Filter by tool name |
| outcome | query | string | no | Filter: allowed, denied, shadow |
| threatType | query | string | no | Filter by threat type |
| keyword | query | string | no | Full-text search across event data |
| from | query | string | no | Start date (ISO-8601) |
| to | query | string | no | End date (ISO-8601) |
| limit | query | integer | no | Max results (default 50, max 500) |
| offset | query | integer | no | Pagination offset |
| orderBy | query | string | no | Sort field (default: createdAt) |
| orderDir | query | string | no | asc or desc (default: desc) |
{
"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 }
}/tenants/:tenantId/audit/verify-chainVerify the Merkle hash chain integrity for a range of events.
audit:read| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| fromId | query | string | no | Start event ID |
| toId | query | string | no | End event ID |
{
"valid": true,
"eventsVerified": 87,
"fromId": "evt_01...",
"toId": "evt_87..."
}/tenants/:tenantId/audit/merkle-snapshotsList hourly Merkle tree snapshots.
audit:read| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| limit | query | integer | no | Max results |
| offset | query | integer | no | Pagination offset |
/tenants/:tenantId/audit/verify-merkle-chainVerify the entire Merkle chain with optional recomputation.
audit:read| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| recompute | query | boolean | no | Recompute Merkle roots from raw events (default: false) |
Risk Scoring
/tenants/:tenantId/riskGet latest risk scores for all agents in a tenant.
risk:read[
{
"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 }
}
]/tenants/:tenantId/agents/:agentId/riskGet latest risk score for a specific agent.
risk:read/tenants/:tenantId/agents/:agentId/risk/historyGet risk score time series for an agent.
risk:read| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| limit | query | integer | no | Max data points (default 200, max 500) |
| from | query | string | no | Start date (ISO-8601) |
| to | query | string | no | End date (ISO-8601) |
/tenants/:tenantId/agents/:agentId/risk/calculateTrigger an on-demand risk score calculation.
risk:configure| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| version | body | string | no | Scoring model version: v1 or v2 |
{
"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"
}/tenants/:tenantId/risk-configGet risk enforcement thresholds for the tenant.
risk:read{
"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
}/tenants/:tenantId/risk-configCreate or update risk enforcement thresholds.
risk:configure| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| enabled | body | boolean | no | Enable/disable enforcement |
| elevatedThreshold | body | integer | yes | Score threshold for elevated tier (0–100) |
| highThreshold | body | integer | yes | Score threshold for high tier (0–100) |
| criticalThreshold | body | integer | yes | Score threshold for critical tier (0–100) |
| elevatedRateMult | body | number | no | Rate limit multiplier for elevated tier (0–1) |
| highRateMult | body | number | no | Rate limit multiplier for high tier (0–1) |
| unknownAgentTier | body | string | no | Default tier for unscored agents |
| gracePeriodSeconds | body | integer | no | Grace period before enforcement activates |
/tenants/:tenantId/risk-enforcement/previewPreview how current scores map to enforcement actions — no side effects.
risk:read[
{
"agentId": "a_01abc...",
"agentName": "code-review-bot",
"score": 42,
"tier": "elevated",
"wouldBlock": false,
"wouldRateLimit": true,
"rateLimitMultiplier": 0.5,
"wouldForceShadow": false,
"gracePeriodActive": false
}
]/tenants/:tenantId/risk-overridesCreate a manual risk tier override for an agent.
risk:configure| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| agentId | body | uuid | yes | Agent to override |
| overrideTier | body | string | yes | Tier to override to: low, elevated, high, critical |
| reason | body | string | yes | Justification for the override |
| category | body | string | yes | Override category |
| expiresAt | body | string | no | Expiration (ISO-8601). Permanent if omitted. |
{
"agentId": "a_01abc...",
"overrideTier": "low",
"reason": "Verified safe after manual review",
"category": "manual_review"
}/tenants/:tenantId/risk-overridesList active risk tier overrides.
risk:read/tenants/:tenantId/risk-overrides/:overrideIdRevoke a risk tier override.
risk:configureCompliance
Compliance endpoints support multiple frameworks: soc2, iso42001, nist-ai-rmf, and eu-ai-act.
/tenants/:tenantId/compliance/gapsUnified gap analysis across all supported compliance frameworks.
compliance:read| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| framework | query | string | no | soc2, iso42001, nist-ai-rmf, or eu-ai-act (default: soc2) |
| agentId | query | uuid | no | Scope to a specific agent |
| windowDays | query | integer | no | Analysis window in days (default: 30, max: 365) |
{
"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"
}
]
}/tenants/:tenantId/compliance/progressCompliance progress over time for trend charts.
compliance:read| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| framework | query | string | no | Framework (default: soc2) |
| days | query | integer | no | History window in days (default: 90, max: 365) |
/tenants/:tenantId/compliance/reportGenerate a full SOC2 compliance report.
compliance:read| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| agentId | query | uuid | no | Scope to a specific agent |
| windowDays | query | integer | no | Report window (default: 30) |
/tenants/:tenantId/compliance/statusLightweight compliance summary for dashboard widgets.
compliance:read/tenants/:tenantId/compliance/{framework}/reportFramework-specific report. Replace {framework} with iso42001, nist-ai-rmf, etc.
compliance:readAvailable sub-paths: /report, /status, /controls for each framework.
/tenants/:tenantId/compliance/annex-iv/reportGenerate an EU AI Act Annex IV technical documentation report.
compliance:read| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| windowDays | query | integer | no | Report window (default: 30) |
Alerts
/tenants/:tenantId/alert-rulesCreate an alert rule with webhook or email channels.
alert:write| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| tenantId | path | uuid | yes | Tenant UUID |
| name | body | string | yes | Rule name |
| condition | body | object | yes | { metric, operator, threshold } |
| condition.metric | body | string | yes | risk_score, anomaly_score, or compliance_score |
| condition.operator | body | string | yes | gt, gte, lt, or lte |
| condition.threshold | body | number | yes | Threshold value (0–100) |
| channels | body | array | yes | Array of {type, url?, to?}. Type: webhook or email |
| cooldownMinutes | body | integer | no | Min minutes between firings (1–1440, default: 15) |
| enabled | body | boolean | no | Active on creation (default: true) |
{
"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
}{
"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"
}/tenants/:tenantId/alert-rulesList alert rules. Optionally filter by enabled state.
alert:read| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| enabled | query | boolean | no | Filter by enabled true/false |
/tenants/:tenantId/alert-rules/:ruleIdUpdate an alert rule (partial update).
alert:write/tenants/:tenantId/alert-rules/:ruleIdDelete an alert rule.
alert:delete/tenants/:tenantId/alert-eventsList alert firing events with pagination.
alert:read| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| ruleId | query | uuid | no | Filter by rule |
| limit | query | integer | no | Max results (default 50, max 500) |
| offset | query | integer | no | Pagination offset |
MCP Servers
/tenants/:tenantId/mcp-serversRegister an MCP server. Automatically discovers tools from upstream.
mcp_server:write| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| tenantId | path | uuid | yes | Tenant UUID |
| name | body | string | yes | Server display name |
| description | body | string | no | Server description |
| upstreamUrl | body | string | yes | Upstream MCP server URL |
{
"name": "GitHub MCP",
"description": "GitHub integration tools",
"upstreamUrl": "http://localhost:8080/mcp"
}{
"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"
}/tenants/:tenantId/mcp-serversList registered MCP servers.
mcp_server:read/tenants/:tenantId/mcp-servers/:mcpServerIdGet an MCP server with its discovered tools.
mcp_server:read/tenants/:tenantId/mcp-servers/:mcpServerIdUpdate MCP server name, description, URL, or status.
mcp_server:write/tenants/:tenantId/mcp-servers/:mcpServerIdDeregister an MCP server.
mcp_server:delete/tenants/:tenantId/mcp-servers/:mcpServerId/refresh-toolsRe-discover tools from the upstream server.
mcp_server:write/tenants/:tenantId/mcp-servers/:mcpServerId/scanRun a security scan on the MCP server.
mcp_server:configure{
"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
}/tenants/:tenantId/mcp-servers/:mcpServerId/scansGet scan history for an MCP server.
mcp_server:read| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| limit | query | integer | no | Max results (default 20, max 100) |
/tenants/:tenantId/scansTenant-wide scan history across all MCP servers.
mcp_server:read| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| limit | query | integer | no | Max results (default 50, max 200) |
Reviews
Human-in-the-loop review queue for tool calls that require approval before execution.
/tenants/:tenantId/reviewsList pending reviews with filtering and pagination.
review:read| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| status | query | string | no | Filter: pending, approved, denied |
| agentId | query | uuid | no | Filter by agent |
| limit | query | integer | no | Max results (default 50, max 500) |
| offset | query | integer | no | Pagination offset |
/tenants/:tenantId/reviews/countGet review counts by status.
review:read{ "pending": 5, "approved": 120, "denied": 8 }/tenants/:tenantId/reviews/:reviewIdGet a single review with agent name.
review:read/tenants/:tenantId/reviews/:reviewId/decideApprove or deny a pending review.
review:triage| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| decision | body | string | yes | approved or denied |
| comment | body | string | no | Optional reviewer comment |
{
"decision": "approved",
"comment": "Verified safe — one-time file access needed"
}Notifications
/tenants/:tenantId/notificationsList in-app notifications for the current user.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| unreadOnly | query | boolean | no | Filter to unread only |
| limit | query | integer | no | Max results (default 50, max 200) |
/tenants/:tenantId/notifications/:id/readMark a single notification as read.
/tenants/:tenantId/notifications/read-allMark all unread notifications as read.
{ "marked": 12 }Passports
Agent Passports provide verifiable identity cards for AI agents. Requires Business tier or above.
/tenants/:tenantId/agents/:agentId/passportGet an agent's passport with risk assessment, compliance status, and signature.
passport:readRequires agent_passport feature entitlement (Business+ plan).
/tenants/:tenantId/agents/:agentId/passportUpdate passport display metadata.
passport:write| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| displayName | body | string | no | Public display name |
| description | body | string | no | Public description |
| avatarUrl | body | string | no | Avatar image URL (SSRF-protected) |
| visibility | body | string | no | private, internal, or public |
/tenants/:tenantId/agents/:agentId/passport/refreshRecompute and re-sign the passport with latest data.
passport:write/tenants/:tenantId/agents/:agentId/passport/publishPublish the passport for external verification.
passport:writePublishing as public requires elevated role (security_manager, tenant_admin, or platform_admin).
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| visibility | body | string | no | public or internal (default: internal) |
/tenants/:tenantId/agents/:agentId/passport/unpublishUnpublish a passport — sets visibility to private.
passport:write/public/passports/:tenantSlug/:agentSlugView a published passport (public, unauthenticated).
Rate-limited to 60 requests/minute per IP. Returns cached response (max-age 300s).
/public/passports/:tenantSlug/:agentSlug/verifyVerify a passport's cryptographic signature (public, unauthenticated).
{
"verified": true,
"valid": true,
"passportHash": "sha256:abc123...",
"signature": "base64:...",
"signedAt": "2026-04-24T12:00:00.000Z",
"keyId": "key_01...",
"publicKey": "-----BEGIN PUBLIC KEY-----..."
}/public/passports/:tenantSlug/:agentSlug/badge.svgRender an embeddable SVG badge for the agent (public, unauthenticated).
Rate-limited to 300 requests/minute per IP. Content-Type: image/svg+xml.
Billing
/billing/statusCurrent plan tier and subscription status.
tenant:read{
"planTier": "pro",
"billingState": "active",
"hasStripeCustomer": true,
"hasSubscription": true
}/billing/entitlementsFeature entitlements and limits for the current plan.
tenant:read{
"planTier": "pro",
"billingState": "active",
"entitlements": {
"maxAgents": 50,
"includedToolCalls": 100000,
"retentionDays": 365,
"features": ["agent_passport", "sso", "custom_policies"]
}
}/billing/usageCurrent month usage and plan limits.
tenant:read{
"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
}/billing/checkoutCreate a Stripe Checkout session for plan upgrade.
tenant:write| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| tier | body | string | yes | Target plan: free, team, starter, pro, business |
| successPath | body | string | no | Redirect path after success |
| cancelPath | body | string | no | Redirect path on cancel |
{ "checkoutUrl": "https://checkout.stripe.com/c/pay_..." }/billing/portalCreate a Stripe Customer Portal session for subscription management.
tenant:write{ "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.
/tenants/:tenantId/export-configsCreate an export configuration.
export:write| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| name | body | string | yes | Config display name |
| destinationType | body | string | yes | s3, webhook, or syslog |
| config | body | object | yes | Destination-specific config (bucket, url, host, etc.) |
| credentials | body | object | no | Auth credentials (encrypted at rest, never returned) |
| filters | body | object | no | Event filters (agent, tool, outcome, etc.) |
| intervalSeconds | body | integer | no | Export interval (30–86400 seconds) |
| format | body | string | no | ndjson or json (default: ndjson) |
| enabled | body | boolean | no | Active on creation (default: true) |
{
"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"
}/tenants/:tenantId/export-configsList export configs (credentials redacted).
export:read/tenants/:tenantId/export-configs/:configIdUpdate an export config (partial update, credentials redacted in response).
export:write/tenants/:tenantId/export-configs/:configIdDelete an export configuration.
export:delete/tenants/:tenantId/export-configs/:configId/testTest the export adapter connection.
export:write{ "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
/tenants/:tenantId/scanSubmit 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 <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.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| tenantId | path | string (uuid) | yes | Your tenant UUID |
| agentId | body | string (uuid) | no | ShieldAgent 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. |
| clientHint | body | string | no | MCP 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. |
| toolName | body | string | yes | Name of the tool being called (e.g. "read_file", "api:POST:/payments") |
| params | body | object | yes | Tool call parameters as a JSON object |
| include_findings | body | boolean | no | Request 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.transport | body | "mcp" | "rest" | "custom" | no | Transport protocol between agent and your server |
| context.sourceIp | body | string | no | IP address of the agent. Used for per-IP rate limiting. |
| context.sessionId | body | string | no | Session identifier. Used for excessive agency detection across calls in the same session. |
{
"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"
}
}{
"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.
{
"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
When to omit agentId
| Scenario | agentId | Pipeline behaviour |
|---|---|---|
| MCP server (typical) | omit | Tenant-level policies only. Optionally pass clientHint from the MCP clientInfo.name handshake. |
| HTTP API with agent auth mapping | provide | Full per-agent pipeline: policies, risk score, rate limits, baseline, approved tools. |
| HTTP API without agent mapping | omit | Tenant-level policies only. Rate limiting applies per-tenant. |
/tenants/:tenantId/verdict-confirmationsReport 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.
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.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
| tenantId | path | string (uuid) | yes | Your tenant UUID |
| auditEventId | body | string (uuid) | yes | The auditEventId returned by POST /scan |
| executed | body | boolean | yes | true 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) |
{
"auditEventId": "evt-a1b2c3d4-0000-0000-0000-000000000001",
"executed": false
}{ "recorded": true }Health
/healthzLiveness probe. Returns service status and timestamp.
Excluded from rate limiting. Use for Kubernetes liveness/readiness probes.
{
"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.
# Serve Swagger UI locally
npx @redocly/cli preview-docs docs/openapi/shieldagent-api.yaml