Files
sentryagent-idp/docs/openapi/agent-registry.yaml
SentryAgent.ai Developer d3530285b9 feat: Phase 1 MVP — complete AgentIdP implementation
Implements all P0 features per OpenSpec change phase-1-mvp-implementation:
- Agent Registry Service (CRUD) — full lifecycle management
- OAuth 2.0 Token Service (Client Credentials flow)
- Credential Management (generate, rotate, revoke)
- Immutable Audit Log Service

Tech: Node.js 18+, TypeScript 5.3+ strict, Express 4.18+, PostgreSQL 14+, Redis 7+
Standards: OpenAPI 3.0 specs, DRY/SOLID, zero `any` types
Quality: 18 unit test suites, 244 tests passing, 97%+ coverage
OpenAPI: 4 complete specs (14 endpoints total)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 09:14:41 +00:00

817 lines
27 KiB
YAML

openapi: 3.0.3
info:
title: SentryAgent.ai — Agent Registry Service
version: 1.0.0
description: |
The Agent Registry Service provides full lifecycle management for AI agent
identities on the SentryAgent.ai AgentIdP platform. Every AI agent is treated
as a first-class non-human identity, aligned with the AGNTCY standard
(Linux Foundation).
Agents receive unique, immutable identifiers (UUIDs), typed capabilities,
and lifecycle status management. The registry is the authoritative source of
truth for all registered agent identities.
**Free Tier Limits**:
- Max 100 registered agents per account
- API rate limit: 100 requests/minute
servers:
- url: http://localhost:3000/api/v1
description: Local development server
- url: https://api.sentryagent.ai/v1
description: Production server
tags:
- name: Agent Registry
description: CRUD operations for AI agent identities
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: |
JWT access token obtained via the OAuth 2.0 Client Credentials flow
(`POST /token`). Include in the `Authorization` header as:
`Authorization: Bearer <token>`
schemas:
AgentType:
type: string
description: The functional classification of the AI agent.
enum:
- screener
- classifier
- orchestrator
- extractor
- summarizer
- router
- monitor
- custom
example: screener
DeploymentEnv:
type: string
description: The target deployment environment for the agent.
enum:
- development
- staging
- production
example: production
AgentStatus:
type: string
description: |
Lifecycle status of the agent.
- `active`: Agent is operational and can authenticate.
- `suspended`: Agent is temporarily disabled; credentials cannot be used.
- `decommissioned`: Agent is permanently retired; soft-deleted record remains.
enum:
- active
- suspended
- decommissioned
example: active
Agent:
type: object
description: Full representation of a registered AI agent identity.
required:
- agentId
- email
- agentType
- version
- capabilities
- owner
- deploymentEnv
- status
- createdAt
- updatedAt
properties:
agentId:
type: string
format: uuid
description: >
Immutable, system-assigned unique identifier for the agent.
Assigned at registration and never changes.
readOnly: true
example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
email:
type: string
format: email
description: >
Unique email-format identifier for the agent. Acts as the human-readable
stable name for this agent identity.
example: "screener-001@sentryagent.ai"
agentType:
$ref: '#/components/schemas/AgentType'
version:
type: string
description: Semantic version string of the agent software.
pattern: '^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$'
example: "1.4.2"
capabilities:
type: array
description: >
List of capability strings representing what this agent is permitted
to do. Uses a `resource:action` convention.
items:
type: string
pattern: '^[a-z0-9_-]+:[a-z0-9_*-]+$'
minItems: 1
example:
- "resume:read"
- "email:send"
- "candidate:score"
owner:
type: string
description: Team or organisation that owns and is responsible for this agent.
minLength: 1
maxLength: 128
example: "talent-acquisition-team"
deploymentEnv:
$ref: '#/components/schemas/DeploymentEnv'
status:
$ref: '#/components/schemas/AgentStatus'
createdAt:
type: string
format: date-time
description: ISO 8601 timestamp when the agent was first registered.
readOnly: true
example: "2026-03-28T09:00:00.000Z"
updatedAt:
type: string
format: date-time
description: ISO 8601 timestamp of the most recent update to this agent record.
readOnly: true
example: "2026-03-28T11:30:00.000Z"
CreateAgentRequest:
type: object
description: Request body for registering a new AI agent identity.
required:
- email
- agentType
- version
- capabilities
- owner
- deploymentEnv
properties:
email:
type: string
format: email
description: >
Unique email-format identifier for the agent.
Must be unique across all registered agents in the system.
example: "screener-001@sentryagent.ai"
agentType:
$ref: '#/components/schemas/AgentType'
version:
type: string
description: Semantic version string of the agent software.
pattern: '^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$'
example: "1.0.0"
capabilities:
type: array
description: List of capability strings for this agent.
items:
type: string
pattern: '^[a-z0-9_-]+:[a-z0-9_*-]+$'
minItems: 1
example:
- "resume:read"
- "email:send"
owner:
type: string
description: Team or organisation that owns this agent.
minLength: 1
maxLength: 128
example: "talent-acquisition-team"
deploymentEnv:
$ref: '#/components/schemas/DeploymentEnv'
UpdateAgentRequest:
type: object
description: >
Request body for updating agent metadata. All fields are optional;
only provided fields are updated. `agentId`, `email`, and `createdAt`
are immutable and cannot be changed.
minProperties: 1
properties:
agentType:
$ref: '#/components/schemas/AgentType'
version:
type: string
description: Updated semantic version string.
pattern: '^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$'
example: "1.5.0"
capabilities:
type: array
description: Updated list of capability strings. Replaces the full list.
items:
type: string
pattern: '^[a-z0-9_-]+:[a-z0-9_*-]+$'
minItems: 1
example:
- "resume:read"
- "email:send"
- "candidate:score"
- "report:write"
owner:
type: string
description: Updated owner team or organisation.
minLength: 1
maxLength: 128
example: "platform-team"
deploymentEnv:
$ref: '#/components/schemas/DeploymentEnv'
status:
$ref: '#/components/schemas/AgentStatus'
PaginatedAgentsResponse:
type: object
description: Paginated list of agent identities.
required:
- data
- total
- page
- limit
properties:
data:
type: array
items:
$ref: '#/components/schemas/Agent'
total:
type: integer
description: Total number of agents matching the query filters.
example: 47
page:
type: integer
description: Current page number (1-based).
example: 1
limit:
type: integer
description: Number of items per page.
example: 20
ErrorResponse:
type: object
description: Standard error response envelope used across all SentryAgent.ai APIs.
required:
- code
- message
properties:
code:
type: string
description: >
Machine-readable error code. Use this field for programmatic error handling.
example: "AGENT_NOT_FOUND"
message:
type: string
description: Human-readable description of the error.
example: "Agent with the specified ID was not found."
details:
type: object
description: >
Optional structured details providing additional context about the error,
such as field-level validation failures.
additionalProperties: true
example:
field: "email"
reason: "Email address is already registered to another agent."
responses:
Unauthorized:
description: Missing or invalid Bearer token.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
code: "UNAUTHORIZED"
message: "A valid Bearer token is required to access this resource."
Forbidden:
description: Valid token but insufficient permissions.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
code: "FORBIDDEN"
message: "You do not have permission to perform this action."
NotFound:
description: The requested resource was not found.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
code: "AGENT_NOT_FOUND"
message: "Agent with the specified ID was not found."
TooManyRequests:
description: Rate limit exceeded. Retry after the reset time.
headers:
X-RateLimit-Limit:
schema:
type: integer
description: Maximum number of requests allowed per minute.
example: 100
X-RateLimit-Remaining:
schema:
type: integer
description: Number of requests remaining in the current window.
example: 0
X-RateLimit-Reset:
schema:
type: integer
description: Unix timestamp (seconds) when the rate limit window resets.
example: 1743155400
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
code: "RATE_LIMIT_EXCEEDED"
message: "Too many requests. Please retry after the rate limit window resets."
InternalServerError:
description: Unexpected server error. Contact support if the issue persists.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
code: "INTERNAL_SERVER_ERROR"
message: "An unexpected error occurred. Please try again later."
security:
- BearerAuth: []
paths:
/agents:
post:
operationId: registerAgent
tags:
- Agent Registry
summary: Register a new AI agent
description: |
Creates a new AI agent identity in the SentryAgent.ai registry.
A unique immutable `agentId` (UUID) is system-assigned on creation.
The `email` must be unique across all registered agents.
**Free Tier**: Maximum 100 registered agents per account. Attempting to
register beyond this limit returns `403 Forbidden` with code `FREE_TIER_LIMIT_EXCEEDED`.
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateAgentRequest'
example:
email: "screener-001@sentryagent.ai"
agentType: "screener"
version: "1.0.0"
capabilities:
- "resume:read"
- "email:send"
owner: "talent-acquisition-team"
deploymentEnv: "production"
responses:
'201':
description: Agent registered successfully.
headers:
X-RateLimit-Limit:
schema:
type: integer
example: 100
X-RateLimit-Remaining:
schema:
type: integer
example: 99
X-RateLimit-Reset:
schema:
type: integer
example: 1743155400
content:
application/json:
schema:
$ref: '#/components/schemas/Agent'
example:
agentId: "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
email: "screener-001@sentryagent.ai"
agentType: "screener"
version: "1.0.0"
capabilities:
- "resume:read"
- "email:send"
owner: "talent-acquisition-team"
deploymentEnv: "production"
status: "active"
createdAt: "2026-03-28T09:00:00.000Z"
updatedAt: "2026-03-28T09:00:00.000Z"
'400':
description: Invalid request body. Check `details` for field-level errors.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
code: "VALIDATION_ERROR"
message: "Request validation failed."
details:
field: "email"
reason: "Must be a valid email address."
'401':
$ref: '#/components/responses/Unauthorized'
'403':
description: Forbidden. Either insufficient permissions or free tier limit reached.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
examples:
insufficientPermissions:
summary: Insufficient permissions
value:
code: "FORBIDDEN"
message: "You do not have permission to register agents."
freeTierLimit:
summary: Free tier agent limit reached
value:
code: "FREE_TIER_LIMIT_EXCEEDED"
message: "Free tier limit of 100 registered agents has been reached."
details:
limit: 100
current: 100
'409':
description: An agent with the provided email address is already registered.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
code: "AGENT_ALREADY_EXISTS"
message: "An agent with this email address is already registered."
details:
email: "screener-001@sentryagent.ai"
'429':
$ref: '#/components/responses/TooManyRequests'
'500':
$ref: '#/components/responses/InternalServerError'
get:
operationId: listAgents
tags:
- Agent Registry
summary: List registered agents
description: |
Returns a paginated list of all registered AI agent identities accessible
to the authenticated caller.
Results can be filtered by `owner`, `agentType`, and/or `status`.
Results are ordered by `createdAt` descending (most recent first).
parameters:
- name: page
in: query
description: Page number (1-based). Defaults to `1`.
required: false
schema:
type: integer
minimum: 1
default: 1
example: 1
- name: limit
in: query
description: Number of results per page. Defaults to `20`, maximum `100`.
required: false
schema:
type: integer
minimum: 1
maximum: 100
default: 20
example: 20
- name: owner
in: query
description: Filter agents by owner name (exact match).
required: false
schema:
type: string
example: "talent-acquisition-team"
- name: agentType
in: query
description: Filter agents by type.
required: false
schema:
$ref: '#/components/schemas/AgentType'
- name: status
in: query
description: Filter agents by lifecycle status.
required: false
schema:
$ref: '#/components/schemas/AgentStatus'
responses:
'200':
description: Paginated list of agents returned successfully.
headers:
X-RateLimit-Limit:
schema:
type: integer
example: 100
X-RateLimit-Remaining:
schema:
type: integer
example: 95
X-RateLimit-Reset:
schema:
type: integer
example: 1743155400
content:
application/json:
schema:
$ref: '#/components/schemas/PaginatedAgentsResponse'
example:
data:
- agentId: "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
email: "screener-001@sentryagent.ai"
agentType: "screener"
version: "1.4.2"
capabilities:
- "resume:read"
- "email:send"
- "candidate:score"
owner: "talent-acquisition-team"
deploymentEnv: "production"
status: "active"
createdAt: "2026-03-01T08:00:00.000Z"
updatedAt: "2026-03-28T09:00:00.000Z"
- agentId: "b2c3d4e5-f6a7-8901-bcde-f12345678901"
email: "classifier-002@sentryagent.ai"
agentType: "classifier"
version: "2.1.0"
capabilities:
- "document:classify"
- "label:write"
owner: "talent-acquisition-team"
deploymentEnv: "staging"
status: "active"
createdAt: "2026-03-10T10:00:00.000Z"
updatedAt: "2026-03-10T10:00:00.000Z"
total: 47
page: 1
limit: 20
'400':
description: Invalid query parameters.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
code: "VALIDATION_ERROR"
message: "Invalid query parameter value."
details:
field: "limit"
reason: "Must be an integer between 1 and 100."
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'429':
$ref: '#/components/responses/TooManyRequests'
'500':
$ref: '#/components/responses/InternalServerError'
/agents/{agentId}:
parameters:
- name: agentId
in: path
description: The unique UUID identifier of the agent.
required: true
schema:
type: string
format: uuid
example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
get:
operationId: getAgentById
tags:
- Agent Registry
summary: Get agent by ID
description: |
Retrieves the full identity record for a single AI agent by its immutable `agentId`.
responses:
'200':
description: Agent record returned successfully.
headers:
X-RateLimit-Limit:
schema:
type: integer
example: 100
X-RateLimit-Remaining:
schema:
type: integer
example: 94
X-RateLimit-Reset:
schema:
type: integer
example: 1743155400
content:
application/json:
schema:
$ref: '#/components/schemas/Agent'
example:
agentId: "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
email: "screener-001@sentryagent.ai"
agentType: "screener"
version: "1.4.2"
capabilities:
- "resume:read"
- "email:send"
- "candidate:score"
owner: "talent-acquisition-team"
deploymentEnv: "production"
status: "active"
createdAt: "2026-03-01T08:00:00.000Z"
updatedAt: "2026-03-28T09:00:00.000Z"
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
'429':
$ref: '#/components/responses/TooManyRequests'
'500':
$ref: '#/components/responses/InternalServerError'
patch:
operationId: updateAgent
tags:
- Agent Registry
summary: Update agent metadata
description: |
Partially updates the metadata for an existing agent.
Only the fields provided in the request body are updated. Omitted fields
are left unchanged. The following fields are immutable and cannot be
updated: `agentId`, `email`, `createdAt`.
Setting `status` to `decommissioned` is a one-way operation — a
decommissioned agent cannot be reactivated.
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateAgentRequest'
example:
version: "1.5.0"
capabilities:
- "resume:read"
- "email:send"
- "candidate:score"
- "report:write"
deploymentEnv: "production"
responses:
'200':
description: Agent updated successfully. Returns the full updated agent record.
headers:
X-RateLimit-Limit:
schema:
type: integer
example: 100
X-RateLimit-Remaining:
schema:
type: integer
example: 93
X-RateLimit-Reset:
schema:
type: integer
example: 1743155400
content:
application/json:
schema:
$ref: '#/components/schemas/Agent'
example:
agentId: "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
email: "screener-001@sentryagent.ai"
agentType: "screener"
version: "1.5.0"
capabilities:
- "resume:read"
- "email:send"
- "candidate:score"
- "report:write"
owner: "talent-acquisition-team"
deploymentEnv: "production"
status: "active"
createdAt: "2026-03-01T08:00:00.000Z"
updatedAt: "2026-03-28T11:30:00.000Z"
'400':
description: Invalid request body or attempt to modify an immutable field.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
examples:
validationError:
summary: Validation failure
value:
code: "VALIDATION_ERROR"
message: "Request validation failed."
details:
field: "version"
reason: "Must be a valid semantic version string."
immutableField:
summary: Attempt to modify immutable field
value:
code: "IMMUTABLE_FIELD"
message: "The field 'email' cannot be modified after registration."
details:
field: "email"
'401':
$ref: '#/components/responses/Unauthorized'
'403':
description: Forbidden. Insufficient permissions or agent is decommissioned.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
examples:
forbidden:
summary: Insufficient permissions
value:
code: "FORBIDDEN"
message: "You do not have permission to update this agent."
decommissioned:
summary: Agent is decommissioned
value:
code: "AGENT_DECOMMISSIONED"
message: "Decommissioned agents cannot be updated."
details:
agentId: "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
'404':
$ref: '#/components/responses/NotFound'
'429':
$ref: '#/components/responses/TooManyRequests'
'500':
$ref: '#/components/responses/InternalServerError'
delete:
operationId: deactivateAgent
tags:
- Agent Registry
summary: Deactivate (soft-delete) an agent
description: |
Permanently decommissions an AI agent. This is a **soft delete** — the
agent record is retained in the database for audit purposes, but the
agent's status is set to `decommissioned`.
**Effects of decommissioning**:
- All active credentials for this agent are immediately revoked.
- The agent can no longer authenticate or obtain tokens.
- The agent record remains visible in the registry with status `decommissioned`.
- This operation is **irreversible**.
responses:
'204':
description: Agent decommissioned successfully. No response body.
headers:
X-RateLimit-Limit:
schema:
type: integer
example: 100
X-RateLimit-Remaining:
schema:
type: integer
example: 92
X-RateLimit-Reset:
schema:
type: integer
example: 1743155400
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
'409':
description: Agent is already decommissioned.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
code: "AGENT_ALREADY_DECOMMISSIONED"
message: "This agent has already been decommissioned."
details:
agentId: "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
'429':
$ref: '#/components/responses/TooManyRequests'
'500':
$ref: '#/components/responses/InternalServerError'