The api-config/ folder contains endpoint configuration files that define how to fetch and parse API usage data from different providers. Each provider has its own JSON file with endpoint details, authentication, and response field mapping.
Location: ~/.claude/cc-api-statusline/api-config/
~/.claude/cc-api-statusline/
config.json # Style + timing (hot-reloadable)
.endpoint-config.lock # Lock file (hash of active configs)
api-config/
sub2api.json # Built-in sub2api provider
crs.json # Built-in CRS provider
my-custom-provider.json # User-added custom providers
Each *.json file in api-config/ must follow this schema:
{
"provider": "unique-provider-id",
"displayName": "Human Readable Name",
"endpoint": {
"path": "/api/usage",
"method": "GET",
"contentType": "application/json"
},
"auth": {
"type": "bearer-header",
"header": "Authorization",
"prefix": "Bearer ",
"bodyField": "apiKey"
},
"defaults": {
"unit": "USD",
"planName": "Unknown"
},
"detection": {
"healthMatch": { "status": "ok" }
},
"requestBody": null,
"responseMapping": {
"billingMode": "subscription",
"planName": "$.planName",
"daily.used": "$.usage.daily",
"daily.limit": "$.limits.daily"
},
"spoofClaudeCodeUA": false
}| Field | Type | Description |
|---|---|---|
provider |
string | Unique provider identifier (used internally) |
endpoint.path |
string | API endpoint path (appended to ANTHROPIC_BASE_URL) |
endpoint.method |
"GET" | "POST" |
HTTP method |
auth |
object | Authentication configuration (see below) |
responseMapping |
object | JSONPath mappings for response fields (see below) |
| Field | Type | Default | Description |
|---|---|---|---|
displayName |
string | provider value |
Human-readable name for display |
endpoint.contentType |
string | "application/json" |
Request Content-Type header |
defaults |
object | {} |
Default values for missing response fields |
detection |
object | null |
Auto-detection rules (health probe matching) |
requestBody |
object | null | null |
JSON body template for POST requests |
spoofClaudeCodeUA |
boolean | string | false |
User-Agent spoofing (see config.json docs) |
Standard Bearer token in Authorization header:
{
"auth": {
"type": "bearer-header",
"prefix": "Bearer "
}
}Uses: Authorization: Bearer <ANTHROPIC_AUTH_TOKEN>
Token passed in request body (for POST requests):
{
"auth": {
"type": "body-key",
"bodyField": "apiKey"
}
}Sends: { "apiKey": "<ANTHROPIC_AUTH_TOKEN>", ...requestBody }
Custom header name with optional prefix:
{
"auth": {
"type": "custom-header",
"header": "X-API-Key",
"prefix": ""
}
}Uses: X-API-Key: <ANTHROPIC_AUTH_TOKEN>
The responseMapping object uses JSONPath to extract fields from API responses.
$.field- Root-level field$.nested.field- Nested field$.array[0]- Array index$.data.items[0].value- Complex nested path- Literal values (no
$.prefix) are used as-is
Billing Mode:
billingMode-"subscription"or"balance"(or JSONPath)
Plan Info:
planName- Plan/account name (string or JSONPath)
Balance Mode (if billingMode = "balance"):
balance.remaining- Remaining balance (number)balance.initial- Initial balance (number)balance.unit- Currency unit (string, default:"USD")
Subscription Mode (if billingMode = "subscription"):
daily.used- Daily usage (number)daily.limit- Daily limit (number,0= unlimited)daily.resetsAt- Reset time (ISO-8601 string)weekly.used- Weekly usageweekly.limit- Weekly limitweekly.resetsAt- Reset timemonthly.used- Monthly usagemonthly.limit- Monthly limitmonthly.resetsAt- Reset time
Token Stats:
tokenStats.today.requests- Today's request counttokenStats.today.inputTokens- Today's input tokenstokenStats.today.outputTokens- Today's output tokenstokenStats.today.cacheCreationTokens- Today's cache creation tokenstokenStats.today.cacheReadTokens- Today's cache read tokenstokenStats.today.totalTokens- Today's total tokenstokenStats.today.cost- Today's costtokenStats.total.*- Same fields for all-time totaltokenStats.rpm- Requests per minutetokenStats.tpm- Tokens per minute
Rate Limiting:
rateLimit.windowSeconds- Rate limit window durationrateLimit.requestsUsed- Requests used in current windowrateLimit.requestsLimit- Request limit per windowrateLimit.costUsed- Cost used in current windowrateLimit.costLimit- Cost limit per windowrateLimit.remainingSeconds- Seconds until window resets
{
"provider": "sub2api",
"displayName": "sub2api",
"endpoint": {
"path": "/v1/usage",
"method": "GET"
},
"auth": {
"type": "bearer-header"
},
"defaults": {
"unit": "USD",
"planName": "Unknown"
},
"detection": {
"healthMatch": { "status": "ok" }
},
"responseMapping": {
"billingMode": "subscription",
"planName": "$.planName",
"balance.remaining": "$.remaining",
"balance.unit": "$.unit",
"daily.used": "$.subscription.daily_usage_usd",
"daily.limit": "$.subscription.daily_limit_usd",
"weekly.used": "$.subscription.weekly_usage_usd",
"weekly.limit": "$.subscription.weekly_limit_usd",
"monthly.used": "$.subscription.monthly_usage_usd",
"monthly.limit": "$.subscription.monthly_limit_usd",
"tokenStats.today.requests": "$.usage.today.requests",
"tokenStats.today.inputTokens": "$.usage.today.input_tokens",
"tokenStats.total.cost": "$.usage.total.cost"
}
}The detection object configures automatic provider detection:
{
"detection": {
"healthMatch": { "status": "ok", "version": "*" }
}
}Detection priority:
CC_STATUSLINE_PROVIDERenv override- In-memory cache
- Disk cache (24h TTL)
- Health probe (
healthMatch) — most-specific match wins - Built-in fallback patterns
- Default to
sub2api
Health Match:
- Probes
<baseUrl>/healthor<baseUrl>/v1/health - Matches response fields against
healthMatch - Use
"*"to match any non-null value
The .endpoint-config.lock file enforces restart requirement:
{
"hash": "abc123def456",
"lockedAt": "2026-02-28T12:00:00Z"
}Behavior:
- Lock file created on first run and
--install - Hash computed from all
api-config/*.jsonfiles (deterministic) - On each invocation:
- If
currentHash === lockedHash→ normal operation - If
currentHash !== lockedHash→ Path B2 (locked out)- Shows:
⚠ Endpoint config changed — run: cc-api-statusline --apply-config - Serves from cache (does NOT fetch with new config)
- Prevents accidental endpoint changes
- Shows:
- If
Applying Changes:
# After editing api-config/*.json files
cc-api-statusline --apply-configThis updates the lock file and clears caches.
-
Create config file:
~/.claude/cc-api-statusline/api-config/my-provider.json -
Define endpoint config:
{ "provider": "my-provider", "displayName": "My API", "endpoint": { "path": "/usage", "method": "GET" }, "auth": { "type": "bearer-header" }, "detection": { "healthMatch": { "service": "my-api" } }, "responseMapping": { "billingMode": "subscription", "daily.used": "$.usage.today", "daily.limit": "$.limits.daily" } } -
Apply config:
cc-api-statusline --apply-config
-
Test:
ANTHROPIC_BASE_URL=https://my-api.com \ ANTHROPIC_AUTH_TOKEN=your-token \ cc-api-statusline --once
Config changes not taking effect?
- Run
cc-api-statusline --apply-configto update lock file
Provider not detected?
- Check
healthMatchin detection config — ensure the fields/values match your/healthresponse - Set
CC_STATUSLINE_PROVIDER=my-providerto force provider - Enable debug logging:
DEBUG=1 cc-api-statusline --once
Response fields not showing?
- Verify JSONPath mapping with actual API response
- Check
defaultsobject for missing field defaults - Look at debug log for fetch errors
See also:
docs/spec-custom-providers.md- Original custom provider specdocs/implementation-handbook.md- Implementation details~/.claude/cc-api-statusline/debug.log- Debug output (whenDEBUG=1)