fix(vv): resolve all 6 V&V issues — field trial unblocked
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>
This commit is contained in:
341
docs/openapi/tiers.yaml
Normal file
341
docs/openapi/tiers.yaml
Normal file
@@ -0,0 +1,341 @@
|
||||
openapi: "3.0.3"
|
||||
|
||||
info:
|
||||
title: SentryAgent.ai — Tier Management
|
||||
version: 1.0.0
|
||||
description: |
|
||||
Tier status and upgrade endpoints for the SentryAgent.ai AgentIdP platform.
|
||||
|
||||
The tier system defines per-organization limits on agents, tokens, and API calls.
|
||||
|
||||
**All endpoints require a valid Bearer JWT.**
|
||||
|
||||
**Available tiers:**
|
||||
| Tier | Max Agents | Max Tokens/Month | Rate Limit |
|
||||
|------|-----------|-----------------|------------|
|
||||
| `free` | 100 | 10,000 | 100 req/min |
|
||||
| `pro` | 1,000 | 100,000 | 1,000 req/min |
|
||||
| `enterprise` | unlimited | unlimited | custom |
|
||||
|
||||
servers:
|
||||
- url: http://localhost:3000/api/v1
|
||||
description: Local development server
|
||||
- url: https://api.sentryagent.ai/v1
|
||||
description: Production server
|
||||
|
||||
tags:
|
||||
- name: Tiers
|
||||
description: Tier status and upgrade management
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
BearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
description: |
|
||||
JWT access token obtained via `POST /token`.
|
||||
Include as `Authorization: Bearer <token>`.
|
||||
|
||||
schemas:
|
||||
PlanTier:
|
||||
type: string
|
||||
enum:
|
||||
- free
|
||||
- pro
|
||||
- enterprise
|
||||
description: Current subscription plan tier.
|
||||
example: free
|
||||
|
||||
TierLimits:
|
||||
type: object
|
||||
description: Hard limits defined by the current tier.
|
||||
required:
|
||||
- maxAgents
|
||||
- maxTokensPerMonth
|
||||
- rateLimitPerMinute
|
||||
properties:
|
||||
maxAgents:
|
||||
type: integer
|
||||
description: Maximum number of agents allowed for this organization.
|
||||
example: 100
|
||||
maxTokensPerMonth:
|
||||
type: integer
|
||||
description: Maximum OAuth 2.0 token requests per calendar month.
|
||||
example: 10000
|
||||
rateLimitPerMinute:
|
||||
type: integer
|
||||
description: Maximum API requests per minute.
|
||||
example: 100
|
||||
|
||||
TierUsage:
|
||||
type: object
|
||||
description: Live usage counters for the current billing period.
|
||||
required:
|
||||
- agentsRegistered
|
||||
- tokensThisMonth
|
||||
- requestsThisMinute
|
||||
properties:
|
||||
agentsRegistered:
|
||||
type: integer
|
||||
description: Current number of active (non-decommissioned) agents.
|
||||
minimum: 0
|
||||
example: 47
|
||||
tokensThisMonth:
|
||||
type: integer
|
||||
description: Total OAuth 2.0 tokens issued in the current calendar month.
|
||||
minimum: 0
|
||||
example: 3214
|
||||
requestsThisMinute:
|
||||
type: integer
|
||||
description: API requests in the current rate-limit window.
|
||||
minimum: 0
|
||||
example: 12
|
||||
|
||||
TierStatus:
|
||||
type: object
|
||||
description: Full tier status response — current tier, plan limits, and live usage.
|
||||
required:
|
||||
- organizationId
|
||||
- tier
|
||||
- limits
|
||||
- usage
|
||||
properties:
|
||||
organizationId:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Organization the tier status applies to.
|
||||
example: "org-1234-5678-abcd-ef01"
|
||||
tier:
|
||||
$ref: '#/components/schemas/PlanTier'
|
||||
limits:
|
||||
$ref: '#/components/schemas/TierLimits'
|
||||
usage:
|
||||
$ref: '#/components/schemas/TierUsage'
|
||||
billingPeriodStart:
|
||||
type: string
|
||||
format: date
|
||||
description: First day of the current billing period (UTC).
|
||||
example: "2026-04-01"
|
||||
billingPeriodEnd:
|
||||
type: string
|
||||
format: date
|
||||
description: Last day of the current billing period (UTC).
|
||||
example: "2026-04-30"
|
||||
|
||||
TierUpgradeRequest:
|
||||
type: object
|
||||
description: Request body for initiating a tier upgrade.
|
||||
required:
|
||||
- targetTier
|
||||
properties:
|
||||
targetTier:
|
||||
type: string
|
||||
enum:
|
||||
- pro
|
||||
- enterprise
|
||||
description: |
|
||||
The target plan tier to upgrade to.
|
||||
Downgrading is not permitted via this endpoint.
|
||||
example: "pro"
|
||||
successUrl:
|
||||
type: string
|
||||
format: uri
|
||||
description: |
|
||||
URL to redirect to after successful payment.
|
||||
Defaults to the platform dashboard when omitted.
|
||||
example: "https://my-app.example.com/dashboard?upgrade=success"
|
||||
cancelUrl:
|
||||
type: string
|
||||
format: uri
|
||||
description: |
|
||||
URL to redirect to if the user cancels checkout.
|
||||
Defaults to the platform dashboard when omitted.
|
||||
example: "https://my-app.example.com/dashboard?upgrade=cancel"
|
||||
|
||||
TierUpgradeResponse:
|
||||
type: object
|
||||
description: Stripe Checkout URL to initiate the tier upgrade payment flow.
|
||||
required:
|
||||
- checkoutUrl
|
||||
- targetTier
|
||||
properties:
|
||||
checkoutUrl:
|
||||
type: string
|
||||
format: uri
|
||||
description: |
|
||||
Stripe-hosted Checkout page URL.
|
||||
Redirect the authenticated user to this URL to complete payment.
|
||||
example: "https://checkout.stripe.com/pay/cs_test_abcdef1234567890"
|
||||
targetTier:
|
||||
$ref: '#/components/schemas/PlanTier'
|
||||
|
||||
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."
|
||||
|
||||
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."
|
||||
|
||||
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:
|
||||
/tiers/status:
|
||||
get:
|
||||
operationId: getTierStatus
|
||||
tags:
|
||||
- Tiers
|
||||
summary: Get current tier status
|
||||
description: |
|
||||
Returns the current tier, plan limits, and live usage counters for the
|
||||
authenticated organization.
|
||||
|
||||
The organization ID is derived from the `organization_id` claim in the
|
||||
Bearer JWT — no explicit organization ID is required in the request.
|
||||
|
||||
Use this endpoint to:
|
||||
- Display the current plan in your dashboard
|
||||
- Check remaining quota before performing bulk operations
|
||||
- Determine whether an upgrade is needed
|
||||
responses:
|
||||
'200':
|
||||
description: Tier status returned successfully.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/TierStatus'
|
||||
example:
|
||||
organizationId: "org-1234-5678-abcd-ef01"
|
||||
tier: "free"
|
||||
limits:
|
||||
maxAgents: 100
|
||||
maxTokensPerMonth: 10000
|
||||
rateLimitPerMinute: 100
|
||||
usage:
|
||||
agentsRegistered: 47
|
||||
tokensThisMonth: 3214
|
||||
requestsThisMinute: 12
|
||||
billingPeriodStart: "2026-04-01"
|
||||
billingPeriodEnd: "2026-04-30"
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
'403':
|
||||
$ref: '#/components/responses/Forbidden'
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalServerError'
|
||||
|
||||
/tiers/upgrade:
|
||||
post:
|
||||
operationId: initiateTierUpgrade
|
||||
tags:
|
||||
- Tiers
|
||||
summary: Initiate a tier upgrade via Stripe
|
||||
description: |
|
||||
Initiates a Stripe Checkout Session for upgrading the organization's plan tier.
|
||||
|
||||
The returned `checkoutUrl` is a Stripe-hosted payment page.
|
||||
Redirect the authenticated user to this URL to complete the upgrade payment.
|
||||
|
||||
After successful payment, Stripe notifies the platform via the
|
||||
`POST /billing/webhook` endpoint, which activates the new tier automatically.
|
||||
|
||||
**Constraints:**
|
||||
- Only upgrades are supported (free → pro, free → enterprise, pro → enterprise).
|
||||
- Attempting to "upgrade" to the current or lower tier returns `400`.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/TierUpgradeRequest'
|
||||
example:
|
||||
targetTier: "pro"
|
||||
successUrl: "https://my-app.example.com/dashboard?upgrade=success"
|
||||
cancelUrl: "https://my-app.example.com/dashboard?upgrade=cancel"
|
||||
responses:
|
||||
'201':
|
||||
description: Stripe Checkout Session created successfully. Redirect user to checkoutUrl.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/TierUpgradeResponse'
|
||||
example:
|
||||
checkoutUrl: "https://checkout.stripe.com/pay/cs_test_abcdef1234567890"
|
||||
targetTier: "pro"
|
||||
'400':
|
||||
description: Invalid upgrade request — already on target tier or attempting a downgrade.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
examples:
|
||||
alreadyOnTier:
|
||||
summary: Already on target tier
|
||||
value:
|
||||
code: "ALREADY_ON_TIER"
|
||||
message: "Your organization is already on the 'pro' tier."
|
||||
invalidDowngrade:
|
||||
summary: Downgrade not permitted
|
||||
value:
|
||||
code: "DOWNGRADE_NOT_PERMITTED"
|
||||
message: "Downgrading tiers is not supported via this endpoint."
|
||||
missingOrgId:
|
||||
summary: Missing organization_id in token
|
||||
value:
|
||||
code: "VALIDATION_ERROR"
|
||||
message: "organization_id is required in token."
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
'403':
|
||||
$ref: '#/components/responses/Forbidden'
|
||||
'500':
|
||||
description: Unexpected error or Stripe API failure.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
example:
|
||||
code: "STRIPE_ERROR"
|
||||
message: "Failed to create Stripe Checkout Session. Please try again."
|
||||
Reference in New Issue
Block a user