Files
sentryagent-idp/openspec/changes/phase-6-market-expansion/specs/api-gateway-tiers/spec.md
SentryAgent.ai Developer 0fad328329 feat(openspec): propose phase-6-market-expansion change
Analytics Dashboard, API Gateway Tiers, AGNTCY Compliance — 62 tasks across 8 groups.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 12:57:23 +00:00

4.7 KiB

ADDED Requirements

Requirement: Tenants are assigned to a tier with defined rate limits

The system SHALL maintain a tenant_tiers table linking each tenant to a tier (free, pro, enterprise) with associated limits: max agents, max API calls per day, and max token issuances per day. Tier configuration SHALL be defined in a TIER_CONFIG constant (not in the database) to enable zero-latency enforcement.

Tier defaults:

  • free: 10 agents, 1,000 API calls/day, 1,000 token issuances/day
  • pro: 100 agents, 50,000 API calls/day, 50,000 token issuances/day
  • enterprise: unlimited (no enforcement)

Scenario: New tenant defaults to free tier

  • WHEN a new tenant is created via POST /api/tenants
  • THEN a tenant_tiers row SHALL be created with tier=free

Scenario: Enterprise tier bypasses all rate limits

  • WHEN a tenant on the enterprise tier makes any API call
  • THEN no rate limit check SHALL be applied for that tenant

Requirement: API calls are rate-limited per tenant tier

The system SHALL enforce daily API call limits per tenant using Redis keys rate:tier:calls:<tenant_id> with a TTL aligned to UTC midnight. When a tenant exceeds their daily call limit, subsequent requests SHALL be rejected.

Scenario: Tenant within call limit proceeds normally

  • WHEN a tenant on the free tier has made fewer than 1,000 API calls today
  • THEN the request SHALL proceed and the counter SHALL be incremented

Scenario: Tenant exceeding daily call limit is rejected

  • WHEN a tenant on the free tier has made 1,000 or more API calls today
  • THEN any further API request SHALL return HTTP 429 with Retry-After header set to seconds until UTC midnight

Scenario: Rate limit headers are present on all responses

  • WHEN any authenticated API request is made
  • THEN the response SHALL include X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers reflecting the tenant's daily call allowance

Requirement: Agent count is enforced per tenant tier

The system SHALL prevent tenants from creating more agents than their tier allows. The check SHALL occur at agent creation time.

Scenario: Tenant at agent limit cannot create new agent

  • WHEN a free tier tenant already has 10 agents and calls POST /api/agents
  • THEN the response SHALL be HTTP 429 with an error message indicating the agent limit and a link to upgrade

Scenario: Tenant below agent limit can create agents

  • WHEN a free tier tenant has fewer than 10 agents and calls POST /api/agents
  • THEN the request SHALL proceed normally

Requirement: Tier enforcement can be toggled via feature flag

The system SHALL respect a TIER_ENFORCEMENT environment variable (default: true). When TIER_ENFORCEMENT=false, all tier limit checks SHALL be bypassed and requests SHALL proceed as if on the enterprise tier. Rate limit headers SHALL still be present but reflect unlimited limits.

Scenario: Tier enforcement disabled allows all requests

  • WHEN TIER_ENFORCEMENT=false and a free tier tenant has exceeded their daily limit
  • THEN the request SHALL succeed with HTTP 200 (no 429 returned)

Requirement: Tenant can self-service upgrade their tier

The system SHALL expose POST /api/tiers/upgrade allowing an authenticated tenant admin to request an upgrade to a higher tier. The endpoint SHALL validate the target tier is higher than the current tier and initiate a Stripe checkout session for the new tier's price. On successful payment webhook, the tenant_tiers row SHALL be updated.

Scenario: Successful tier upgrade initiation

  • WHEN a free tier tenant calls POST /api/tiers/upgrade with { "target_tier": "pro" }
  • THEN the response SHALL be HTTP 200 with a Stripe checkout URL

Scenario: Downgrade attempt is rejected

  • WHEN a pro tier tenant calls POST /api/tiers/upgrade with { "target_tier": "free" }
  • THEN the response SHALL be HTTP 400 with an error indicating downgrades require support

Scenario: Stripe webhook updates tier on payment success

  • WHEN Stripe sends a checkout.session.completed event for a tier upgrade
  • THEN the tenant's tier SHALL be updated to the purchased tier within 5 seconds

Requirement: Tenant can view their current tier and usage

The system SHALL expose GET /api/tiers/status returning the tenant's current tier, daily limits, current usage counts (calls today, tokens today, agent count), and time until daily limit reset.

Scenario: Tier status returns current usage

  • WHEN an authenticated tenant admin calls GET /api/tiers/status
  • THEN the response SHALL be HTTP 200 with tier name, limits, and live usage counters