# LLM Usage Server Protocol v1 A read-only HTTP/JSON protocol for querying LLM account quotas, balances and local usage telemetry. Base URL: `https://usage.adadaadadade.com` The dashboard at `/` is for humans. This file is the machine/agent contract. Protocol version: `1`. All timestamps are ISO-8601 UTC unless noted. ## Authentication All `/api/*` endpoints require a bearer token: ```http Authorization: Bearer ``` For simple GET probes, `?token=` is also accepted. Prefer the header because query strings may be written to access logs. `/`, `/llms.txt`, `/styles.css`, `/app.js` and `/favicon.svg` are public. A missing or invalid token returns HTTP 401 with `WWW-Authenticate: Bearer`. The server is read-only. It never accepts mutations and never returns API keys, OAuth tokens or refresh tokens. Do not ask it for secrets. ## Quick start ```bash curl -fsS \ -H "Authorization: Bearer $USAGE_SERVER_TOKEN" \ "https://usage.adadaadadade.com/api/usage" | jq ``` Single provider, bypassing the 60-second cache: ```bash curl -fsS \ -H "Authorization: Bearer $USAGE_SERVER_TOKEN" \ "https://usage.adadaadadade.com/api/usage?provider=deepseek&refresh=1" | jq ``` ## Endpoints ### GET /api/health Process and configuration status. Does not query upstream providers. ```json { "ok": true, "now": "2026-11-09T08:27:21.072Z", "uptimeSeconds": 25, "agentDir": "/home/weijj/.pi/agent", "envFile": "/home/weijj/.env.private", "warnings": [] } ``` ### GET /api/providers Lists provider ids, labels and credential/implementation status without making upstream requests. ### GET /api/usage Query parameters: - `provider` (optional): `openai`, `deepseek`, `xiaomi`, `glm`. Case-insensitive. Omit it to query all four. - `refresh=1` (optional): bypass the server cache. Use sparingly. Response shape: ```json { "generatedAt": "2026-11-09T08:27:21.102Z", "cacheTtlMs": 60000, "providers": [ { "provider": "openai", "label": "OpenAI", "status": "ok", "source": "Codex /wham/usage", "plan": "prolite", "subscriptionEndsAt": "2026-12-09T04:09:24.000Z", "windows": [ { "id": "primary", "label": "7 天额度", "percent": 0, "windowSeconds": 604800, "resetAt": "2026-11-16T07:29:16.000Z" } ], "balances": [], "metrics": [], "notes": ["数据来自 Codex ChatGPT 订阅额度接口。"], "fetchedAt": "2026-11-09T08:27:21.102Z", "latencyMs": 10973, "cached": true, "local": { "requests": 2, "input": 9821, "output": 208, "cacheRead": 8064, "cacheWrite": 0, "reasoning": 126, "totalTokens": 18093, "cost": 0.022528 } } ], "local": {} } ``` Provider ids and meanings: | id | label | remote source | | --- | --- | --- | | `openai` | OpenAI | Codex ChatGPT quota, or OpenAI organization usage/costs | | `deepseek` | DeepSeek | account balance | | `xiaomi` | Xiaomi MiMo | Token Plan credits and/or PAYG balance | | `glm` | GLM / Z.ai | Coding Plan 5-hour and 7-day quotas | `status` semantics: - `ok`: remote quota/balance was fetched successfully. Local stats may still be empty. - `partial`: remote data is unavailable or limited; local stats may still be present. - `error`: upstream request failed. See `error`. - `unconfigured`: no credential was found for this provider. `ProviderUsage` fields: | field | type | meaning | | --- | --- | --- | | `provider` | string | provider id | | `label` | string | display name | | `status` | string | `ok`, `partial`, `error`, `unconfigured` | | `source` | string | human-readable data source | | `plan` | string? | plan name when known | | `subscriptionEndsAt` | ISO string? | current subscription period end or expiry, when the provider exposes it | | `windows` | array | quota windows (always present; may be empty) | | `balances` | array | account balances (always present; may be empty) | | `metrics` | array | token/request/cost summaries (always present; may be empty) | | `notes` | string[] | provider-specific caveats | | `error` | string? | sanitized error message | | `fetchedAt` | ISO string | fetch completion time | | `latencyMs` | number? | upstream latency | | `cached` | boolean? | whether this value came from cache | | `local` | object or null | local summary for this provider | `subscriptionEndsAt` is the end of the current billing/subscription period. For auto-renewing plans this is the next renewal date, not necessarily the final cancellation date. It is currently available for OpenAI Codex subscriptions and Xiaomi Token Plan; providers that do not expose it omit the field. `UsageWindow`: ```json { "id": "CREDIT_LIMIT-6-1-1", "label": "7 天额度", "percent": 0, "used": 0, "limit": 60000, "remaining": 60000, "unit": "credits", "resetAt": "2026-11-16T05:11:03.998Z", "windowSeconds": 604800 } ``` `percent` is 0–100. `used`, `limit` and `remaining` use the unit in `unit` (`tokens`, `credits`, or `requests`). `resetAt` is absent when the provider does not expose a reset time. `BalanceEntry`: ```json { "currency": "CNY", "total": 119.76, "granted": 0, "toppedUp": 119.76 } ``` Other optional balance fields: `cash`, `gift`, `frozen`, `creditLimit`, `creditAvailable`, `label`. `UsageMetric`: ```json { "label": "今日输入", "tokens": 231502, "requests": 190, "cost": 0.371852, "currency": "USD" } ``` ### GET /api/local Returns local pi session telemetry only, without querying providers. ```json { "generatedAt": "2026-11-09T08:27:21.102Z", "scannedAt": "2026-11-09T08:27:21.100Z", "windowDays": 90, "sessions": 5, "totals": { "today": { "requests": 190, "totalTokens": 10929930, "cost": 0.371852 }, "last7d": { "requests": 232, "totalTokens": 11985153, "cost": 0.379414 }, "last30d": { "requests": 243, "totalTokens": 12233911, "cost": 0.400917 }, "all": { "requests": 243, "totalTokens": 12233911, "cost": 0.400917 } }, "byDay": [], "byProvider": [], "byModel": [] } ``` Local usage is derived from assistant `message.usage` records under `~/.pi/agent/sessions`. `totalTokens` includes input, output, cache reads and cache writes. `cost` is pi's recorded estimate, usually USD, and may be zero for subscription/included models. Day buckets use the server's local timezone. ## Caching, errors and limits - Successful provider results are cached for `cacheTtlMs` (default 60000). - `refresh=1` forces a new upstream request; do not loop with refresh enabled. - `GET` and `HEAD` are supported. Mutating methods return 405. - Errors are JSON: `{"error": "message"}` with 400, 401, 404 or 500. - An upstream failure is returned as a normal 200 `UsageResponse` with `status: "error"` or `partial`, not an HTTP 500. - The endpoint is intended for local, trusted agents. Do not publish the token or proxy this API to untrusted users. ## Advice for agent callers 1. Fetch `/api/usage` once, then reuse the result for at least 60 seconds. 2. Use `?provider=` when only one provider is needed. 3. Treat `status` before reading numbers: `partial` means remote quota may be absent, while `local` still provides pi session usage. 4. Do not call `refresh=1` automatically in a polling loop. 5. Never print the bearer token in logs, prompts or generated code. 6. For human-readable context, open `/`; for the contract, use this file.