## ADDED Requirements

### Requirement: Per-tenant usage is tracked for API calls, active agents, and token issuances
The system SHALL track the following usage metrics per tenant per day: `api_calls` (every authenticated API request), `token_issuances` (every successful `POST /oauth2/token`), `active_agents` (count of non-revoked agents at end of day). Usage SHALL be aggregated in memory and flushed to a `usage_events` PostgreSQL table every 60 seconds.

#### Scenario: API call increments usage counter
- **WHEN** an authenticated tenant makes any API request
- **THEN** the tenant's `api_calls` counter for the current day is incremented

#### Scenario: Usage is persisted to database on flush interval
- **WHEN** 60 seconds elapse since the last flush
- **THEN** all in-memory counters are written to the `usage_events` table and reset to zero

### Requirement: Free tier limits are enforced per tenant
The system SHALL enforce free tier limits: 10 active agents maximum, 1,000 API calls per day. When a limit is exceeded, the offending request SHALL be rejected with HTTP 429 and a response body indicating which limit was reached and how to upgrade. Limit summaries SHALL be cached in Redis with a 60-second TTL.

#### Scenario: Agent registration blocked at free tier limit
- **WHEN** a free-tier tenant with 10 active agents calls `POST /agents`
- **THEN** the response is HTTP 429 with `{ "error": "free_tier_limit", "limit": "agents", "max": 10, "upgradeUrl": "..." }`

#### Scenario: API call blocked after daily limit
- **WHEN** a free-tier tenant has made 1,000 API calls today and makes another request
- **THEN** the response is HTTP 429 with `{ "error": "free_tier_limit", "limit": "api_calls", "max": 1000, "upgradeUrl": "..." }`

#### Scenario: Paid tenant is not rate limited by usage tiers
- **WHEN** a paid-tier tenant exceeds free tier thresholds
- **THEN** the request is processed normally with no usage-based rejection

### Requirement: Stripe Checkout initiates paid tier subscription
The system SHALL expose `POST /billing/checkout` (authenticated) that creates a Stripe Checkout session for the paid tier plan and returns a `checkoutUrl`. The tenant is redirected to Stripe Checkout to complete payment. On success, Stripe sends a `customer.subscription.created` webhook event.

#### Scenario: Checkout session created
- **WHEN** an authenticated tenant calls `POST /billing/checkout`
- **THEN** the response is HTTP 200 with `{ "checkoutUrl": "https://checkout.stripe.com/..." }`

#### Scenario: Duplicate subscription prevented
- **WHEN** a tenant with an active paid subscription calls `POST /billing/checkout`
- **THEN** the response is HTTP 409 with `{ "error": "already_subscribed" }`

### Requirement: Stripe webhooks update tenant subscription state
The system SHALL expose `POST /billing/webhook` (Stripe webhook endpoint) that verifies the `stripe-signature` header using `stripe.webhooks.constructEvent()` and processes: `customer.subscription.created` (set tenant to paid), `invoice.payment_succeeded` (extend subscription period), `customer.subscription.deleted` (revert tenant to free tier). All events without valid signatures SHALL be rejected with HTTP 400.

#### Scenario: Webhook without valid signature is rejected
- **WHEN** `POST /billing/webhook` is called with an invalid or missing `stripe-signature` header
- **THEN** the response is HTTP 400 and no state is changed

#### Scenario: Subscription created webhook activates paid tier
- **WHEN** Stripe sends a valid `customer.subscription.created` event for a tenant
- **THEN** the tenant's `subscriptionStatus` is updated to `active` and free tier limits no longer apply

#### Scenario: Subscription deleted webhook reverts to free tier
- **WHEN** Stripe sends a valid `customer.subscription.deleted` event
- **THEN** the tenant's `subscriptionStatus` is updated to `cancelled` and free tier limits are re-enforced

### Requirement: Billing is feature-flag gated
All billing enforcement and Stripe integration SHALL be gated behind the `BILLING_ENABLED` environment variable. When `BILLING_ENABLED=false`, free tier limits are not enforced, all tenants have paid-tier access, and Stripe webhook endpoint returns HTTP 200 without processing. Usage metering continues regardless of this flag.

#### Scenario: Billing disabled — no limits enforced
- **WHEN** `BILLING_ENABLED=false` and a free-tier tenant has 11 active agents
- **THEN** agent registration succeeds without HTTP 429
