All findings from the inaugural LeadValidator audit resolved and confirmed. Release gate: PASS. VV_ISSUE_002 (BLOCKER): 15 OpenAPI specs verified present covering all 20 route groups (46 endpoints documented in docs/openapi/) VV_ISSUE_003 (MAJOR): Remove any types from src/db/pool.ts — replaced pool.query shim with unknown[] + Object.defineProperty, zero any types, eslint-disable suppressions removed VV_ISSUE_004 (MAJOR): Remove raw Pool from ScaffoldController and HealthDetailedController — injected AgentRepository/CredentialRepository and DbProbe interface respectively; added CredentialRepository.findActiveClientId() VV_ISSUE_005 (MAJOR): Add unit tests for 5 untested services — ComplianceStatusStore, EventPublisher, MarketplaceService, OIDCTrustPolicyService, UsageService VV_ISSUE_006 (MAJOR): Add integration tests for 7 missing route groups — analytics, billing, tiers, webhooks, marketplace, oidc-trust-policies, oidc-token-exchange VV_ISSUE_001 (MINOR): Create missing design.md and tasks.md in 4 OpenSpec archives — all archives now complete Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
429 lines
14 KiB
YAML
429 lines
14 KiB
YAML
openapi: "3.0.3"
|
||
|
||
info:
|
||
title: SentryAgent.ai — Tenant Analytics
|
||
version: 1.0.0
|
||
description: |
|
||
Tenant analytics endpoints for the SentryAgent.ai AgentIdP platform.
|
||
|
||
Provides usage trend data, agent activity heatmaps, and per-agent usage summaries
|
||
scoped to the authenticated organization (tenant).
|
||
|
||
**All endpoints require a valid Bearer JWT.** Data is always scoped to the
|
||
organization identified by the `organization_id` claim in the token.
|
||
|
||
**Feature flag:** When `ANALYTICS_ENABLED=false` these routes return 404.
|
||
|
||
**Available endpoints:**
|
||
- `GET /analytics/tokens` — Daily token issuance trend (last N days)
|
||
- `GET /analytics/agents/activity` — Agent activity heatmap by day-of-week + hour
|
||
- `GET /analytics/agents` — Per-agent usage summary for the current month
|
||
|
||
servers:
|
||
- url: http://localhost:3000/api/v1
|
||
description: Local development server
|
||
- url: https://api.sentryagent.ai/v1
|
||
description: Production server
|
||
|
||
tags:
|
||
- name: Analytics
|
||
description: Tenant-scoped usage analytics and reporting
|
||
|
||
components:
|
||
securitySchemes:
|
||
BearerAuth:
|
||
type: http
|
||
scheme: bearer
|
||
bearerFormat: JWT
|
||
description: |
|
||
JWT access token obtained via `POST /token`.
|
||
Include as `Authorization: Bearer <token>`.
|
||
|
||
schemas:
|
||
TokenTrendDataPoint:
|
||
type: object
|
||
description: Token issuance count for a single calendar day.
|
||
required:
|
||
- date
|
||
- count
|
||
properties:
|
||
date:
|
||
type: string
|
||
format: date
|
||
description: Calendar date (UTC) in `YYYY-MM-DD` format.
|
||
example: "2026-04-01"
|
||
count:
|
||
type: integer
|
||
description: Number of OAuth 2.0 tokens issued on this date.
|
||
minimum: 0
|
||
example: 842
|
||
|
||
TokenTrendResponse:
|
||
type: object
|
||
description: Daily token issuance trend for the last N days.
|
||
required:
|
||
- organizationId
|
||
- days
|
||
- data
|
||
properties:
|
||
organizationId:
|
||
type: string
|
||
format: uuid
|
||
description: Organization the analytics data belongs to.
|
||
example: "org-1234-5678-abcd-ef01"
|
||
days:
|
||
type: integer
|
||
description: Number of days included in the trend window.
|
||
example: 30
|
||
data:
|
||
type: array
|
||
description: |
|
||
Array of daily data points ordered by date ascending.
|
||
Days with no token issuances have `count: 0`.
|
||
items:
|
||
$ref: '#/components/schemas/TokenTrendDataPoint'
|
||
|
||
ActivityHeatmapCell:
|
||
type: object
|
||
description: |
|
||
A single cell in the agent activity heatmap, identified by
|
||
day-of-week (0 = Sunday) and hour of day (0–23 UTC).
|
||
required:
|
||
- dayOfWeek
|
||
- hour
|
||
- count
|
||
properties:
|
||
dayOfWeek:
|
||
type: integer
|
||
description: Day of week (0 = Sunday, 6 = Saturday).
|
||
minimum: 0
|
||
maximum: 6
|
||
example: 1
|
||
hour:
|
||
type: integer
|
||
description: Hour of day in UTC (0–23).
|
||
minimum: 0
|
||
maximum: 23
|
||
example: 14
|
||
count:
|
||
type: integer
|
||
description: Number of token issuances or API calls in this slot.
|
||
minimum: 0
|
||
example: 217
|
||
|
||
AgentActivityResponse:
|
||
type: object
|
||
description: |
|
||
Agent activity heatmap — shows when agents are most active
|
||
by day-of-week and hour (UTC). Useful for identifying peak usage patterns.
|
||
required:
|
||
- organizationId
|
||
- data
|
||
properties:
|
||
organizationId:
|
||
type: string
|
||
format: uuid
|
||
example: "org-1234-5678-abcd-ef01"
|
||
data:
|
||
type: array
|
||
description: |
|
||
Array of heatmap cells. Contains only cells with `count > 0`.
|
||
Maximum 168 cells (7 days × 24 hours).
|
||
items:
|
||
$ref: '#/components/schemas/ActivityHeatmapCell'
|
||
|
||
AgentUsageSummary:
|
||
type: object
|
||
description: Per-agent usage summary for the current calendar month.
|
||
required:
|
||
- agentId
|
||
- tokensIssued
|
||
- apiCalls
|
||
properties:
|
||
agentId:
|
||
type: string
|
||
format: uuid
|
||
description: UUID of the agent.
|
||
example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
|
||
agentEmail:
|
||
type: string
|
||
format: email
|
||
description: Email identifier of the agent.
|
||
example: "screener-001@sentryagent.ai"
|
||
tokensIssued:
|
||
type: integer
|
||
description: Number of tokens issued for this agent in the current month.
|
||
minimum: 0
|
||
example: 1204
|
||
apiCalls:
|
||
type: integer
|
||
description: Total API calls made by this agent in the current month.
|
||
minimum: 0
|
||
example: 5432
|
||
lastActiveAt:
|
||
type: string
|
||
format: date-time
|
||
nullable: true
|
||
description: Timestamp of the agent's last API activity. Null if no activity this month.
|
||
example: "2026-04-07T08:45:00.000Z"
|
||
|
||
AgentSummaryResponse:
|
||
type: object
|
||
description: Per-agent usage summary for the current month, across all agents in the organization.
|
||
required:
|
||
- organizationId
|
||
- month
|
||
- data
|
||
properties:
|
||
organizationId:
|
||
type: string
|
||
format: uuid
|
||
example: "org-1234-5678-abcd-ef01"
|
||
month:
|
||
type: string
|
||
description: Current billing month in `YYYY-MM` format.
|
||
example: "2026-04"
|
||
data:
|
||
type: array
|
||
description: Per-agent usage summaries, ordered by `tokensIssued` descending.
|
||
items:
|
||
$ref: '#/components/schemas/AgentUsageSummary'
|
||
|
||
ErrorResponse:
|
||
type: object
|
||
description: Standard error response envelope.
|
||
required:
|
||
- code
|
||
- message
|
||
properties:
|
||
code:
|
||
type: string
|
||
example: "UNAUTHORIZED"
|
||
message:
|
||
type: string
|
||
example: "A valid Bearer token is required to access this resource."
|
||
details:
|
||
type: object
|
||
additionalProperties: true
|
||
|
||
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."
|
||
|
||
InternalServerError:
|
||
description: Unexpected server error.
|
||
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:
|
||
/analytics/tokens:
|
||
get:
|
||
operationId: getTokenTrend
|
||
tags:
|
||
- Analytics
|
||
summary: Get daily token issuance trend
|
||
description: |
|
||
Returns a daily breakdown of OAuth 2.0 token issuances for the authenticated
|
||
organization over the last N days.
|
||
|
||
The `days` parameter controls the window size (default: 30, max: 90).
|
||
Days with no token activity are included with `count: 0`.
|
||
|
||
Data is scoped to the `organization_id` from the Bearer token.
|
||
parameters:
|
||
- name: days
|
||
in: query
|
||
required: false
|
||
description: Number of days to include in the trend window. Default: 30, max: 90.
|
||
schema:
|
||
type: integer
|
||
minimum: 1
|
||
maximum: 90
|
||
default: 30
|
||
example: 30
|
||
responses:
|
||
'200':
|
||
description: Token trend data returned successfully.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/TokenTrendResponse'
|
||
example:
|
||
organizationId: "org-1234-5678-abcd-ef01"
|
||
days: 7
|
||
data:
|
||
- date: "2026-04-01"
|
||
count: 842
|
||
- date: "2026-04-02"
|
||
count: 967
|
||
- date: "2026-04-03"
|
||
count: 0
|
||
- date: "2026-04-04"
|
||
count: 1201
|
||
- date: "2026-04-05"
|
||
count: 1087
|
||
- date: "2026-04-06"
|
||
count: 953
|
||
- date: "2026-04-07"
|
||
count: 412
|
||
'400':
|
||
description: Invalid `days` parameter.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
examples:
|
||
tooLarge:
|
||
summary: Exceeds maximum
|
||
value:
|
||
code: "VALIDATION_ERROR"
|
||
message: "Query parameter `days` must not exceed 90."
|
||
details:
|
||
field: "days"
|
||
max: 90
|
||
provided: 120
|
||
invalid:
|
||
summary: Non-positive integer
|
||
value:
|
||
code: "VALIDATION_ERROR"
|
||
message: "Query parameter `days` must be a positive integer."
|
||
details:
|
||
field: "days"
|
||
'401':
|
||
$ref: '#/components/responses/Unauthorized'
|
||
'404':
|
||
description: Analytics feature is not enabled on this instance.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
code: "NOT_FOUND"
|
||
message: "Analytics is not enabled on this instance."
|
||
'500':
|
||
$ref: '#/components/responses/InternalServerError'
|
||
|
||
/analytics/agents/activity:
|
||
get:
|
||
operationId: getAgentActivity
|
||
tags:
|
||
- Analytics
|
||
summary: Get agent activity heatmap
|
||
description: |
|
||
Returns agent activity aggregated by day-of-week (0 = Sunday) and hour of day (UTC).
|
||
|
||
The heatmap shows when agents in the organization are most active,
|
||
based on token issuances and API calls. Only cells with `count > 0` are returned.
|
||
|
||
Data is scoped to the `organization_id` from the Bearer token.
|
||
The heatmap covers the last 90 days of activity.
|
||
responses:
|
||
'200':
|
||
description: Agent activity heatmap returned successfully.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/AgentActivityResponse'
|
||
example:
|
||
organizationId: "org-1234-5678-abcd-ef01"
|
||
data:
|
||
- dayOfWeek: 1
|
||
hour: 9
|
||
count: 342
|
||
- dayOfWeek: 1
|
||
hour: 14
|
||
count: 217
|
||
- dayOfWeek: 2
|
||
hour: 10
|
||
count: 189
|
||
- dayOfWeek: 3
|
||
hour: 11
|
||
count: 405
|
||
- dayOfWeek: 4
|
||
hour: 14
|
||
count: 278
|
||
- dayOfWeek: 5
|
||
hour: 9
|
||
count: 121
|
||
'401':
|
||
$ref: '#/components/responses/Unauthorized'
|
||
'404':
|
||
description: Analytics feature is not enabled on this instance.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
code: "NOT_FOUND"
|
||
message: "Analytics is not enabled on this instance."
|
||
'500':
|
||
$ref: '#/components/responses/InternalServerError'
|
||
|
||
/analytics/agents:
|
||
get:
|
||
operationId: getAgentSummary
|
||
tags:
|
||
- Analytics
|
||
summary: Get per-agent usage summary
|
||
description: |
|
||
Returns per-agent token issuance counts and API call totals for the
|
||
current calendar month, across all agents in the authenticated organization.
|
||
|
||
Results are ordered by `tokensIssued` descending (most active agents first).
|
||
|
||
Data is scoped to the `organization_id` from the Bearer token.
|
||
responses:
|
||
'200':
|
||
description: Per-agent usage summary returned successfully.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/AgentSummaryResponse'
|
||
example:
|
||
organizationId: "org-1234-5678-abcd-ef01"
|
||
month: "2026-04"
|
||
data:
|
||
- agentId: "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
|
||
agentEmail: "screener-001@sentryagent.ai"
|
||
tokensIssued: 1204
|
||
apiCalls: 5432
|
||
lastActiveAt: "2026-04-07T08:45:00.000Z"
|
||
- agentId: "b2c3d4e5-f6a7-8901-bcde-f12345678901"
|
||
agentEmail: "classifier-002@sentryagent.ai"
|
||
tokensIssued: 876
|
||
apiCalls: 3120
|
||
lastActiveAt: "2026-04-06T14:30:00.000Z"
|
||
- agentId: "c3d4e5f6-a7b8-9012-cdef-123456789012"
|
||
agentEmail: "router-003@sentryagent.ai"
|
||
tokensIssued: 0
|
||
apiCalls: 0
|
||
lastActiveAt: null
|
||
'401':
|
||
$ref: '#/components/responses/Unauthorized'
|
||
'404':
|
||
description: Analytics feature is not enabled on this instance.
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ErrorResponse'
|
||
example:
|
||
code: "NOT_FOUND"
|
||
message: "Analytics is not enabled on this instance."
|
||
'500':
|
||
$ref: '#/components/responses/InternalServerError'
|