mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-23 15:42:12 +03:00
feat(api): structured ?format=json for the self-service usage endpoint (#11190)
* feat(api): structured ?format=json for the self-service usage endpoint GET /api/usage/om-usage already let any key read its own usage — personal daily/weekly USD limits and the provider quota snapshot — but only as text/plain, which a UI cannot parse safely. OmniCopilot issue #8 asks exactly for this surface. Adds ?format=json, returning the ApiKeyUsageLimitStatus + UsageSnapshot the text is rendered from. Text and JSON share the same collectors (collectUsageSnapshots, getApiKeyUsageLimitStatus), so the two can never disagree about a number. The response is a discriminated union: a key without allowUsageCommand (403) or an invalid key (401) returns { allowed:false, error:{message} }, distinct from allowed:true with empty sections — the state a panel must render as "nothing learned yet", not a refusal. Text form unchanged; without ?format the contract is untouched. The endpoint was previously missing from API_REFERENCE.md; it now has a section documenting both forms, the allowUsageCommand gate, and the self-service auth model (caller's own key, not requireManagementAuth). Regression guards in tests/unit/usage-command-json-format.test.ts (4 tests: json shape, text default preserved, structured 403, sanitized 401 with no stack trace). Existing internal-usage-command suite still 12/12. * chore(changelog): correct the fragment to the real PR number (#11190) --------- Co-authored-by: Xiangzhe <bakryun0718@proton.me>
This commit is contained in:
committed by
GitHub
parent
62ab93d789
commit
eb9fa33ee7
@@ -636,6 +636,47 @@ completion.
|
||||
|
||||
---
|
||||
|
||||
## Self-service usage (`/api/usage/om-usage`)
|
||||
|
||||
Any API key can read **its own** usage and quotas — no management auth. This is the endpoint a
|
||||
client (CLI, the OmniCopilot panel) uses to show a key holder their spend.
|
||||
|
||||
```bash
|
||||
# Text form (the historical contract — plain text for a terminal)
|
||||
curl -H "Authorization: Bearer <your-api-key>" \
|
||||
http://localhost:20128/api/usage/om-usage
|
||||
|
||||
# Structured form — what a UI consumes
|
||||
curl -H "Authorization: Bearer <your-api-key>" \
|
||||
"http://localhost:20128/api/usage/om-usage?format=json"
|
||||
```
|
||||
|
||||
The key must have **`allowUsageCommand`** enabled (off by default — the dashboard's API-key
|
||||
manager toggles it per key). Without it the endpoint answers `403`.
|
||||
|
||||
`?format=json` returns a discriminated shape so a caller never reads a data field off a
|
||||
refusal. On success:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"allowed": true,
|
||||
// present only when the key opted into per-key usage limits (daily/weekly USD):
|
||||
"personal": { "dailySpentUsd": 1.25, "dailyLimitUsd": 5, "dailyResetAtIso": "…", "weeklySpentUsd": 8, "weeklyLimitUsd": 20, "weeklyResetAtIso": "…" /* … */ },
|
||||
// the selected provider quota snapshot, or null when nothing is cached yet:
|
||||
"provider": { "connectionId": "…", "provider": "claude", "plan": "…", "quotas": { /* … */ } }
|
||||
}
|
||||
```
|
||||
|
||||
On refusal (`401` bad key / `403` not allowed) the same route returns
|
||||
`{ "allowed": false, "error": { "message": "…" } }` — a present-but-empty `personal`/`provider`
|
||||
(key allowed, nothing learned yet) is a different state from a refusal, and only the JSON form
|
||||
distinguishes them.
|
||||
|
||||
**Auth:** the caller's own Bearer API key, validated with `isValidApiKey` — this is *not* the
|
||||
management surface (`/api/keys/…`), which stays behind `requireManagementAuth`.
|
||||
|
||||
---
|
||||
|
||||
## Semantic Cache
|
||||
|
||||
```bash
|
||||
|
||||
Reference in New Issue
Block a user