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 `. 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."