7.8 KiB
Specification: API Key Self-Service Usage
ADDED Requirements
Requirement: Self-service status endpoint
OmniRoute SHALL provide GET /api/v1/me/status for a valid Bearer API key to retrieve status for that same API key.
Scenario: Valid key reads own status
- GIVEN a valid API key with own-usage visibility
- WHEN it calls
GET /api/v1/me/status - THEN the response status SHALL be
200 - AND the response SHALL include the API key id and name
- AND the response SHALL include cost usage for that key
- AND the response SHALL include token usage for that key
Scenario: Invalid key is rejected
- GIVEN a missing or invalid Bearer token
- WHEN the caller calls
GET /api/v1/me/status - THEN the response status SHALL be
401
Scenario: Anonymous client API mode does not bypass self-service auth
- GIVEN global client API auth allows anonymous local traffic
- WHEN a caller without a Bearer API key calls
GET /api/v1/me/status - THEN the response status SHALL be
401
Scenario: Environment management key is not a self-service key
- GIVEN the deployment has an environment management key
- WHEN that key calls
GET /api/v1/me/status - THEN the response SHALL NOT expose delegated API key usage
Requirement: Own-key isolation
The self-service endpoint SHALL derive the API key id from the authenticated Bearer key and SHALL NOT accept caller-supplied key ids for lookup.
Scenario: Caller tries to query another key
- GIVEN API key A and API key B both have usage
- WHEN API key A calls
GET /api/v1/me/status?apiKeyId=<key-b-id> - THEN the response SHALL contain only API key A identity and usage
- AND the response SHALL NOT contain API key B usage
Requirement: USD budget status
The self-service endpoint SHALL report per-key USD budget usage using the existing budget system.
Scenario: Key has an active monthly budget
- GIVEN an API key has a monthly USD budget of
50 - AND the key has current-period cost of
12.50 - WHEN the key calls the self-service status endpoint
- THEN
usage.cost.limitUsdSHALL be50 - AND
usage.cost.usedUsdSHALL be12.50 - AND
usage.cost.usedPercentSHALL be25 - AND
usage.cost.remainingUsdSHALL be37.50
Scenario: Key has no budget
- GIVEN an API key has no configured budget
- WHEN the key calls the self-service status endpoint
- THEN
usage.cost.limitUsdSHALL benull - AND
usage.cost.usedPercentSHALL benull - AND cost and token totals SHALL still be returned for the default display period
Requirement: Token usage reporting
The self-service endpoint SHALL report token totals from usage_history for the authenticated API key and selected reporting period.
Scenario: Token totals include all tracked categories
- GIVEN an API key has usage rows with input, output, cache read, cache creation, and reasoning tokens
- WHEN the key calls the self-service status endpoint
- THEN the response SHALL include each token category total
- AND
totalTokensSHALL include all reported token categories
Requirement: Self-service scopes
OmniRoute SHALL support self:usage and self:account-quota API key scopes. These scopes SHALL NOT grant management API access.
Scenario: Self-service scope is not management
- GIVEN an API key has
self:usage - AND it does not have
manageoradmin - WHEN it calls a management usage endpoint
- THEN the response SHALL be forbidden
Scenario: New key defaults
- GIVEN an operator opens the create API key UI
- THEN own cost and token usage visibility SHALL be enabled by default
- AND shared account quota visibility SHALL be disabled by default
Scenario: Existing keys receive own-usage visibility on upgrade
- GIVEN an ordinary API key existed before this feature
- AND it does not have
self:usage - WHEN the compatibility migration or startup normalization runs
- THEN the API key SHALL have
self:usage - AND the API key SHALL NOT have
self:account-quota
Scenario: Key without own-usage scope is denied
- GIVEN a valid API key does not have
self:usage - WHEN it calls
GET /api/v1/me/status - THEN the response status SHALL be
403
Requirement: Shared account quota permission
The self-service endpoint SHALL include shared account quota only when the authenticated key has self:account-quota.
Scenario: Account quota hidden by default
- GIVEN a valid API key has own-usage visibility
- AND it does not have
self:account-quota - WHEN it calls the self-service endpoint
- THEN the response SHALL NOT include shared account quota details
Scenario: Codex quota shown with explicit permission
- GIVEN a valid API key has
self:account-quota - AND it is restricted to exactly one Codex connection
- AND Codex quota data is available
- WHEN it calls the self-service endpoint
- THEN the response SHALL include normalized
sessionandweeklyquota windows - AND each window SHALL include used percentage, remaining percentage, and reset timestamp when known
Scenario: Multiple connections are ambiguous
- GIVEN a valid API key has
self:account-quota - AND it is allowed to use more than one connection
- WHEN it calls the self-service endpoint
- THEN
accountQuota.availableSHALL befalse - AND
accountQuota.reasonSHALL beambiguous_connection
Scenario: Unrestricted connections are ambiguous
- GIVEN a valid API key has
self:account-quota - AND its
allowedConnectionslist is empty, meaning all connections are allowed - WHEN it calls the self-service endpoint
- THEN
accountQuota.availableSHALL befalse - AND
accountQuota.reasonSHALL beambiguous_connection
Requirement: Dashboard configuration
The API Manager SHALL allow operators to configure self-service visibility and SHALL reuse the existing budget configuration surface for USD limits.
Scenario: Edit preserves unrelated scopes
- GIVEN an API key has scopes
["self:usage", "custom:scope"] - WHEN an operator enables shared account quota in the permissions UI
- THEN the saved scopes SHALL include
self:usage - AND the saved scopes SHALL include
self:account-quota - AND the saved scopes SHALL still include
custom:scope
Scenario: Budget editing remains in existing budget UI
- GIVEN an operator wants to change a key's USD budget limit
- WHEN they use the dashboard
- THEN OmniRoute SHALL direct them to the existing budget configuration surface
- AND the create-key dialog SHALL NOT introduce a second budget editor
Scenario: No budget is displayed as not configured
- GIVEN an API key has no configured budget
- WHEN the API Manager shows self-service usage for that key
- THEN the UI SHALL show usage and token totals
- AND the budget limit, remaining amount, and percent SHALL be shown as not configured
Requirement: Dashboard internationalization
All new API Manager text for self-service usage visibility, shared account quota visibility, and no-budget display SHALL use OmniRoute's existing i18n message system.
Scenario: New UI strings use translation keys
- GIVEN the API Manager renders the new self-service controls
- THEN labels, descriptions, tooltips, empty states, and errors SHALL come from translation keys
- AND no new user-visible dashboard text SHALL be hard-coded in the component
Scenario: Locale files stay structurally compatible
- GIVEN new API Manager translation keys are added
- WHEN the translation consistency check runs
- THEN supported locale message files SHALL have compatible key structure
Requirement: Existing budget management remains protected
The existing /api/usage/budget management endpoint SHALL NOT become an own-key self-service data source.
Scenario: Self-service key cannot read arbitrary budget endpoint
- GIVEN an API key has
self:usage - AND it does not have
manageoradmin - WHEN it calls
/api/usage/budget?apiKeyId=<another-key-id> - THEN the response SHALL be rejected by management auth