Skip to content

Latest commit

 

History

History
1203 lines (944 loc) · 31.3 KB

File metadata and controls

1203 lines (944 loc) · 31.3 KB

ccflare HTTP API Documentation

Quick Start

# Check health status
curl http://localhost:8080/health

# Proxy a request to Anthropic
curl -X POST http://localhost:8080/v1/anthropic/v1/messages \
  -H "Content-Type: application/json" \
  -H "anthropic-version: 2023-06-01" \
  -d '{
    "model": "claude-sonnet-4-20250514",
    "messages": [{"role": "user", "content": "Hello!"}],
    "max_tokens": 100
  }'

# Proxy a request to OpenAI
curl -X POST http://localhost:8080/v1/openai/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o-mini",
    "messages": [{"role": "user", "content": "Hello!"}]
  }'

# List all accounts
curl http://localhost:8080/api/accounts

# View dashboard
open http://localhost:8080

Overview

ccflare provides a RESTful HTTP API for managing accounts, monitoring usage, and proxying requests to Anthropic and OpenAI. The API runs on port 8080 by default and requires no authentication.

Base URL

http://localhost:8080

Content Type

All API responses are in JSON format with Content-Type: application/json.

Endpoints

Health Check

GET /health

Check the health status of the ccflare service.

Response:

{
  "status": "ok",
  "accounts": 5,
  "timestamp": "2024-12-17T10:30:45.123Z",
  "strategy": "session",
  "providers": ["anthropic", "openai"]
}

Example:

curl http://localhost:8080/health

Provider Proxy

/v1/{provider}/*

Proxy requests to upstream provider APIs. The /v1/{provider} prefix is stripped exactly once before forwarding upstream. Requests are routed using the configured load balancing strategy across accounts matching the target provider.

Supported Providers:

  • /v1/anthropic/*https://api.anthropic.com/*
  • /v1/openai/*https://api.openai.com/v1/*
  • /v1/kimi/*https://api.kimi.com/coding/v1/*
  • POST /v1/grok/responseshttps://cli-chat-proxy.grok.com/v1/responses

Grok accepts only POST /v1/grok/responses; other Grok paths and methods are rejected locally.

Headers:

  • All standard provider API headers are supported
  • Authorization header is managed by ccflare (no need to provide)

Request Body: Same as the upstream provider API requirements for the specific endpoint.

Response: Proxied response from the upstream provider API, including streaming responses.

Automatic Failover: If a request fails or an account is rate limited, ccflare automatically retries with the next available account according to the configured load balancing strategy. This ensures high availability and reliability.

Examples:

# Anthropic
curl -X POST http://localhost:8080/v1/anthropic/v1/messages \
  -H "Content-Type: application/json" \
  -H "anthropic-version: 2023-06-01" \
  -d '{
    "model": "claude-sonnet-4-20250514",
    "messages": [{"role": "user", "content": "Hello!"}],
    "max_tokens": 100
  }'

# OpenAI chat completions
curl -X POST http://localhost:8080/v1/openai/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o-mini",
    "messages": [{"role": "user", "content": "Hello!"}]
  }'

# OpenAI responses
curl -X POST http://localhost:8080/v1/openai/responses \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o",
    "input": "Hello!"
  }'

ccflare Compatibility Proxy

POST /v1/ccflare/anthropic/messages

POST /v1/ccflare/openai/chat/completions

POST /v1/ccflare/openai/responses

Compatibility routes keep the client-facing Anthropic/OpenAI schema while routing through a connected provider family chosen from the model prefix.

Model Prefix Rules:

  • openai/<model-id> → prefers codex, then openai
  • anthropic/<model-id> → prefers claude-code, then anthropic

Unprefixed models use the compatibility route's native family. Kimi models are not translated by compatibility routes; send their native Chat Completions payloads to POST /v1/kimi/chat/completions instead. A kimi/ model on any compatibility endpoint returns 400 with that guidance.

Empty or non-string model values are rejected with 400.

Examples:

# Ask for an Anthropic model through the OpenAI chat schema
curl -X POST http://localhost:8080/v1/ccflare/openai/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "anthropic/claude-sonnet-4",
    "messages": [{"role": "user", "content": "Hello!"}]
  }'

# Ask for an OpenAI model through the Anthropic Messages schema
curl -X POST http://localhost:8080/v1/ccflare/anthropic/messages \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-4o-mini",
    "max_tokens": 100,
    "messages": [{"role": "user", "content": "Hello!"}]
  }'

Behavior:

  • HTTP only; websocket upgrades are not supported on /v1/ccflare/*
  • requests use the same load-balancing and failover logic as native provider routes
  • responses are translated back into the requested client schema, including SSE streams
  • if no usable accounts exist in the requested family, ccflare returns 503

Account Management

GET /api/accounts

List all configured accounts with their current status.

Response:

[
  {
    "id": "uuid-here",
    "name": "account1",
    "provider": "anthropic",
    "auth_method": "api_key",
    "base_url": null,
    "requestCount": 150,
    "totalRequests": 1500,
    "lastUsed": "2024-12-17T10:25:30.123Z",
    "created": "2024-12-01T08:00:00.000Z",
    "weight": 1,
    "paused": false,
    "tokenStatus": "valid",
    "tokenExpiresAt": null,
    "rateLimitStatus": {
      "code": "ok",
      "isLimited": false,
      "until": null
    },
    "rateLimitReset": "2024-12-17T10:30:00.000Z",
    "rateLimitRemaining": 100,
    "sessionInfo": {
      "active": true,
      "startedAt": "2024-12-17T10:00:00.000Z",
      "requestCount": 25
    },
    "quota": null
  }
]

Example:

curl http://localhost:8080/api/accounts

GET /api/accounts/:accountId/quota

Fetch live provider-native quota data for one selected OAuth account. The account is addressed directly by its ccflare account ID; load balancing, paused state, and current inference rate-limit state do not affect which credentials are queried.

Supported providers:

  • claude-code — collects Anthropic OAuth usage and profile data
  • codex — collects ChatGPT usage, account-check, and reset-credit data
  • kimi — collects Kimi Coding usage limits
  • grok — collects Grok Build included and enabled on-demand credit usage

The large Codex profile-history probe is intentionally omitted because it does not provide current quota windows.

The handler refreshes missing, expired, expiry-less, or nearly expired OAuth credentials before querying. A fully unauthorized collective response also triggers one refresh-and-retry. Rotated tokens are persisted but are never included in the API response.

If the token endpoint reports invalid_grant or HTTP 401/403, the endpoint returns 401 with a clear instruction to sign that account in again. Temporary token endpoint and network failures remain upstream 502 errors.

Response:

{
  "account": {
    "id": "uuid-here",
    "name": "claude-work",
    "provider": "claude-code"
  },
  "state": "ok",
  "collectedAt": "2026-07-25T08:30:00.000Z",
  "windows": [
    {
      "id": "claude-code:account:5h",
      "label": "5-hour limit",
      "period": "5h",
      "scope": "account",
      "usedPercent": 31
    }
  ],
  "sources": {
    "usage": {
      "state": "ok",
      "status": 200,
      "data": {
        "five_hour": {
          "utilization": 31
        }
      }
    },
    "profile": {
      "state": "ok",
      "status": 200,
      "data": {
        "subscription_type": "max"
      }
    }
  }
}

state is:

  • ok when every provider probe succeeds
  • partial when at least one probe succeeds and another fails
  • failed when every probe fails

A partial report is returned with 200 so callers can use the successful sources. If every source fails, the endpoint returns 502 and places the same secret-safe report in details. Unknown account IDs return 404. Accounts from other providers return 501 with an explicit not-implemented message.

Upstream payload fields named like credentials are redacted recursively. Provider profile/account sources can still contain non-secret identifying or subscription information. Because the management API itself has no authentication, do not expose it to untrusted networks without an authentication layer.

windows is an additive normalized projection used by the dashboard. Raw provider data remains in sources; malformed provider fields are ignored per window. Requests with usable normalized windows persist the latest snapshot for GET /api/accounts. Failed or unparseable refreshes retain the last successful windows as stale.

The server refreshes every supported account after listening and once per hour. Callers may still use this endpoint for an immediate refresh.

Example:

curl http://localhost:8080/api/accounts/uuid-here/quota

POST /api/accounts/:accountId/rate-limit/reset

Clear the selected account's local rate-limit gate and associated status, reset, and remaining metadata. This does not change upstream quota or the cached quota snapshot. A later provider response can immediately mark the account as rate limited again. Unknown account IDs return 404.

GET /api/accounts/:accountId/models

Fetch the live provider-native model catalog for one selected OAuth account. Like the quota endpoint, the account is addressed directly by its ccflare account ID; load balancing, paused state, and current inference rate-limit state do not affect which credentials are queried.

Supported providers:

  • codex — queries GET https://chatgpt.com/backend-api/codex/models?client_version=<version> once per known Codex CLI version (currently 0.145.0 and 0.144.1), mirroring how the real Codex CLI discovers its catalog
  • grok — queries the account base URL's authoritative GET /models catalog with the verified OAuth subject and official Grok Build client headers; an upstream failure returns no hardcoded catalog entries

All other providers return 501 with an explicit not-implemented message.

The response is tiered by client version, newest first. The newest tier keeps its full catalog. Every model+effort combo that a newer tier also advertises is culled from older tiers (culledCount records how many), so an older tier only lists models — or individual reasoning efforts — that require that older client version. Models known to exist but not advertised by the remote catalog (currently codex-auto-review) are appended to the newest successful tier with "hidden": true.

The handler refreshes missing, expired, expiry-less, or nearly expired OAuth credentials before querying. A fully unauthorized response also triggers one refresh-and-retry. Rotated tokens are persisted but are never included in the API response.

If the token endpoint reports invalid_grant or HTTP 401/403, the endpoint returns 401 with a clear instruction to sign that account in again. Temporary token endpoint and network failures remain upstream 502 errors.

Response:

{
  "account": {
    "id": "uuid-here",
    "name": "codex-main",
    "provider": "codex"
  },
  "state": "ok",
  "collectedAt": "2026-07-25T08:30:00.000Z",
  "versions": [
    {
      "clientVersion": "0.145.0",
      "state": "ok",
      "status": 200,
      "culledCount": 0,
      "models": [
        {
          "slug": "gpt-5.5",
          "displayName": "GPT-5.5",
          "defaultReasoningLevel": "medium",
          "supportedReasoningLevels": [
            { "effort": "low", "description": "Fastest responses" },
            { "effort": "medium" }
          ]
        },
        {
          "slug": "codex-auto-review",
          "displayName": "Codex Auto Review",
          "supportedReasoningLevels": [],
          "hidden": true
        }
      ]
    },
    {
      "clientVersion": "0.144.1",
      "state": "ok",
      "status": 200,
      "culledCount": 2,
      "models": [
        {
          "slug": "gpt-5.1-codex",
          "supportedReasoningLevels": [{ "effort": "medium" }]
        }
      ]
    }
  ]
}

state is ok when every version fetch succeeds, partial when at least one succeeds, and failed when every one fails. Partial reports return 200; fully failed reports return 502 with the secret-safe report in details. Unknown account IDs return 404.

The catalog changes only when OpenAI ships model or client gating changes. Poll no more often than every 15 minutes.

Example:

curl http://localhost:8080/api/accounts/uuid-here/models

Auth Flow

OAuth and auth endpoints are provider-scoped. The {provider} path segment determines which provider's OAuth flow is used (for example claude-code, codex, kimi, or grok).

POST /api/auth/{provider}/init

Initialize an OAuth flow for adding a new account.

Request:

{
  "name": "myaccount"
}

Response:

{
  "success": true,
  "message": "OAuth flow initiated for 'myaccount'",
  "data": {
    "authUrl": "https://claude.ai/oauth/authorize?...",
    "sessionId": "uuid-here",
    "provider": "claude-code"
  }
}

Example:

curl -X POST http://localhost:8080/api/auth/claude-code/init \
  -H "Content-Type: application/json" \
  -d '{"name": "myaccount"}'

POST /api/auth/{provider}/complete

Complete the OAuth flow after user authorization.

Request:

{
  "sessionId": "uuid-from-init-response",
  "code": "authorization-code-from-oauth"
}

Response:

{
  "success": true,
  "message": "Account 'myaccount' added successfully!",
  "data": {
    "provider": "claude-code"
  }
}

Example:

curl -X POST http://localhost:8080/api/auth/claude-code/complete \
  -H "Content-Type: application/json" \
  -d '{"sessionId": "uuid-here", "code": "auth-code"}'

GET /api/auth/session/{sessionId}/status

Check the status of an in-progress OAuth session.

Example:

curl http://localhost:8080/api/auth/session/uuid-here/status

GET /oauth/{provider}/callback

Browser redirect target for the OAuth flow. This is the callback URL that the OAuth provider redirects to after the user authorizes. Not called directly by API consumers.

Codex and Grok normally use a loopback listener owned by oauth-flow, allowing the stored session to complete automatically while dashboard clients continue polling status. Grok's redirect is http://127.0.0.1:1456/callback; it validates state plus the signed OIDC ID token and returns a small success or failure page.


Account Management

DELETE /api/accounts/:accountId

Remove an account.

Response:

{
  "success": true,
  "message": "Account 'account-name' removed successfully"
}

Example:

curl -X DELETE http://localhost:8080/api/accounts/uuid-here

PATCH /api/accounts/:accountId

Update an account (e.g., rename or change base_url).

Request:

{
  "name": "new-name",
  "base_url": "https://custom-endpoint.example.com"
}

Response:

{
  "success": true,
  "message": "Account updated"
}

Example:

curl -X PATCH http://localhost:8080/api/accounts/uuid-here \
  -H "Content-Type: application/json" \
  -d '{"name": "new-name"}'

POST /api/accounts/:accountId/rename

Rename an account.

Request:

{
  "name": "new-name"
}

Example:

curl -X POST http://localhost:8080/api/accounts/uuid-here/rename \
  -H "Content-Type: application/json" \
  -d '{"name": "new-name"}'

POST /api/accounts/:accountId/pause

Pause an account temporarily.

Response:

{
  "success": true,
  "message": "Account 'myaccount' paused"
}

Example:

curl -X POST http://localhost:8080/api/accounts/uuid-here/pause

POST /api/accounts/:accountId/resume

Resume a paused account.

Response:

{
  "success": true,
  "message": "Account 'myaccount' resumed"
}

Example:

curl -X POST http://localhost:8080/api/accounts/uuid-here/resume

Statistics

GET /api/stats

Get overall usage statistics.

Response:

{
  "totalRequests": 5000,
  "successRate": 98.5,
  "activeAccounts": 4,
  "avgResponseTime": 1250.5,
  "totalTokens": 1500000,
  "totalCostUsd": 125.50,
  "avgTokensPerSecond": null,
  "topModels": [
    {"model": "claude-3-opus-20240229", "count": 3000},
    {"model": "claude-3-sonnet-20240229", "count": 2000}
  ]
}

Example:

curl http://localhost:8080/api/stats

POST /api/stats/reset

Reset all usage statistics.

Response:

{
  "success": true,
  "message": "Statistics reset successfully"
}

Example:

curl -X POST http://localhost:8080/api/stats/reset

Request History

GET /api/requests

Get recent request summary.

Query Parameters:

  • limit - Number of requests to return (default: 50)

Response:

[
  {
    "id": "request-uuid",
    "timestamp": "2024-12-17T10:30:45.123Z",
    "method": "POST",
    "path": "/v1/anthropic/v1/messages",
    "accountUsed": "account1",
    "statusCode": 200,
    "success": true,
    "errorMessage": null,
    "responseTimeMs": 1234,
    "failoverAttempts": 0,
    "model": "claude-sonnet-4-20250514",
    "promptTokens": 50,
    "completionTokens": 100,
    "totalTokens": 150,
    "inputTokens": 50,
    "outputTokens": 100,
    "cacheReadInputTokens": 0,
    "cacheCreationInputTokens": 0,
    "costUsd": 0.0125,
    "agentUsed": null,
    "tokensPerSecond": null
  }
]

Example:

curl "http://localhost:8080/api/requests?limit=100"

GET /api/requests/:requestId/detail

Get detailed request information for one exact stored request ID. Request and response bodies are base64-encoded to handle binary data and special characters. Unknown IDs return 404. Known pending requests, WebSocket requests, and records with missing or malformed stored payloads return a valid metadata-only RequestPayload fallback.

Response:

{
  "id": "request-uuid",
  "request": {
    "headers": {...},
    "body": "base64-encoded-body"
  },
  "response": {
    "status": 200,
    "headers": {...},
    "body": "base64-encoded-body"
  },
  "meta": {
    "trace": {
      "timestamp": 1234567890,
      "method": "POST",
      "path": "/v1/anthropic/v1/messages"
    },
    "account": {
      "id": "uuid",
      "name": "account1"
    },
    "transport": {
      "success": true,
      "pending": false,
      "retry": 0
    }
  }
}

Example:

curl "http://localhost:8080/api/requests/request-uuid/detail"

GET /api/requests/:identifier/conversation

Return a stored conversation by exact request ID or by client session ID. Exact request IDs take precedence; otherwise ccflare resolves identifier to the most recent request whose client_session_id matches, including values supplied through x-ccflare-session-id.

The response depends on the resolved request transport:

  • HTTP requests return the existing application/json array of request payloads in response-chain ancestor order.
  • WebSocket requests return a finite application/x-ndjson snapshot containing one raw WebSocketTranscriptEntry per line, ordered by persisted chunk and frame sequence.

The WebSocket export flattens internal chunk boundaries while preserving lifecycle entries, direction, frame type, encoding, raw UTF-8 text, and base64 binary data. It has no total size cap and is streamed with bounded server memory. For an active connection, the response includes everything persisted when the export begins and then closes; use /transcript/stream to follow new frames live.

WebSocket responses include X-Ccflare-Conversation-Kind, X-Ccflare-Conversation-Active, and, when data exists, first/last frame sequence headers. A known WebSocket request with no persisted entries returns 200 with an empty body.

GET /api/requests/:requestId/transcript

Return persisted transcript chunks for one WebSocket request. Chunks contain provider-neutral ordered entries with direction, timestamp, text/binary frame type, encoding, and raw data. Provider-specific interpretation is performed by consumers when displayed.

Query parameters:

  • after — return entries after this frame sequence (default 0)
  • limit — maximum chunk rows to return (default 100, maximum 500)

The response includes transcript bounds, a continuation cursor, and whether the WebSocket request remains active.

GET /api/requests/:requestId/transcript/stream

Stream newly persisted chunks for one WebSocket request via SSE. Event IDs are the last frame sequence in each emitted chunk. Reconnects may use the standard Last-Event-ID header or an initial after query parameter. The endpoint replays persisted data before switching to live delivery and deduplicates by frame sequence.

GET /api/requests/stream

Stream metadata-only real-time request events via Server-Sent Events (SSE). The stream emits ingress, start, and completed summary events; it never includes stored request or response bodies. WebSocket connection start/final metadata appears here, while frame payloads use the request-scoped transcript stream.

Response: SSE stream with request events

Example:

curl -N http://localhost:8080/api/requests/stream

Configuration

GET /api/config

Get current configuration.

Response:

{
  "lbStrategy": "session",
  "port": 8080,
  "sessionDurationMs": 18000000
}

Example:

curl http://localhost:8080/api/config

GET /api/config/strategy

Get current load balancing strategy.

Response:

{
  "strategy": "session"
}

Example:

curl http://localhost:8080/api/config/strategy

POST /api/config/strategy

Update load balancing strategy.

Request:

{
  "strategy": "session"
}

Response:

{
  "success": true,
  "strategy": "session"
}

Available Strategies:

  • session - Session-based routing that maintains 5-hour sessions with individual accounts to avoid rate limits and account bans

⚠️ WARNING: Only the session strategy is supported. Other strategies have been removed as they can trigger Claude's anti-abuse systems.

Example:

curl -X POST http://localhost:8080/api/config/strategy \
  -H "Content-Type: application/json" \
  -d '{"strategy": "session"}'

GET /api/strategies

List all available load balancing strategies.

Response:

["session"]

Example:

curl http://localhost:8080/api/strategies

Analytics

GET /api/analytics

Get detailed analytics data.

Query Parameters:

  • range - Time range: 1h, 6h, 24h, 7d, 30d (default: 24h)
  • accounts - Filter by account names (comma-separated list)
  • models - Filter by model names (comma-separated list)
  • status - Filter by request status: all, success, error (default: all)
  • mode - Display mode: normal, cumulative (default: normal). Cumulative mode shows running totals over time
  • modelBreakdown - Include per-model time series data: true, false (default: false)

Response:

{
  "meta": {
    "range": "24h",
    "bucket": "1h",
    "cumulative": false
  },
  "totals": {
    "requests": 5000,
    "successRate": 98.5,
    "activeAccounts": 4,
    "avgResponseTime": 1250.5,
    "totalTokens": 1500000,
    "totalCostUsd": 125.50,
    "avgTokensPerSecond": null
  },
  "timeSeries": [
    {
      "ts": 1734430800000,
      "requests": 100,
      "tokens": 15000,
      "costUsd": 1.25,
      "successRate": 98,
      "errorRate": 2,
      "cacheHitRate": 15,
      "avgResponseTime": 1200,
      "avgTokensPerSecond": null
    }
  ],
  "tokenBreakdown": {
    "inputTokens": 500000,
    "cacheReadInputTokens": 100000,
    "cacheCreationInputTokens": 50000,
    "outputTokens": 850000
  },
  "modelDistribution": [
    {"model": "claude-3-opus-20240229", "count": 3000}
  ],
  "accountPerformance": [
    {"name": "account1", "requests": 2500, "successRate": 99}
  ],
  "costByModel": [
    {"model": "claude-3-opus-20240229", "costUsd": 100.50, "requests": 3000, "totalTokens": 1200000}
  ],
  "modelPerformance": [
    {
      "model": "claude-3-opus-20240229",
      "avgResponseTime": 1300,
      "p95ResponseTime": 2500,
      "errorRate": 1.5,
      "avgTokensPerSecond": null,
      "minTokensPerSecond": null,
      "maxTokensPerSecond": null
    }
  ]
}

Examples:

# Basic analytics for last 7 days
curl "http://localhost:8080/api/analytics?range=7d"

# Analytics filtered by specific accounts
curl "http://localhost:8080/api/analytics?range=24h&accounts=account1,account2"

# Analytics for specific models with success status only
curl "http://localhost:8080/api/analytics?range=24h&models=claude-3-opus-20240229,claude-3-sonnet-20240229&status=success"

# Combined filters
curl "http://localhost:8080/api/analytics?range=7d&accounts=premium1,premium2&models=claude-3-opus-20240229&status=error"

Maintenance

POST /api/maintenance/cleanup

Queue background data cleanup based on configured retention settings. Returns 202 Accepted immediately with data.status set to accepted or already_running. Returns 503 when the maintenance worker is unavailable.

Example:

curl -X POST http://localhost:8080/api/maintenance/cleanup

POST /api/maintenance/compact

Compact the database to reclaim disk space.

Example:

curl -X POST http://localhost:8080/api/maintenance/compact

Data Retention

GET /api/config/retention

Get current data retention settings.

Response:

{
  "payloadDays": 7,
  "requestDays": 30
}

Example:

curl http://localhost:8080/api/config/retention

POST /api/config/retention

Update data retention settings.

Request:

{
  "payloadDays": 14,
  "requestDays": 90
}

Example:

curl -X POST http://localhost:8080/api/config/retention \
  -H "Content-Type: application/json" \
  -d '{"payloadDays": 14, "requestDays": 90}'

Logs

GET /api/logs/stream

Stream real-time logs via Server-Sent Events (SSE).

Response: SSE stream with log events

Example:

curl -N http://localhost:8080/api/logs/stream

GET /api/logs/history

Get historical logs.

Response:

[
  {
    "timestamp": "2024-12-17T10:30:45.123Z",
    "level": "info",
    "component": "proxy",
    "message": "Request completed",
    "metadata": {...}
  }
]

Example:

curl http://localhost:8080/api/logs/history

Error Handling

All API errors follow a consistent format:

{
  "error": "Error message",
  "details": {
    // Optional additional error details
  }
}

Common Status Codes

  • 200 OK - Request successful
  • 400 Bad Request - Invalid request parameters
  • 404 Not Found - Resource not found
  • 429 Too Many Requests - Rate limited
  • 500 Internal Server Error - Server error
  • 502 Bad Gateway - Upstream provider error
  • 503 Service Unavailable - All accounts failed

Rate Limiting

When an account hits rate limits, ccflare automatically fails over to the next available account. If all accounts are rate limited, a 503 error is returned.

Rate limit information is included in account responses:

  • rateLimitStatus - Current status (e.g., "allowed", "allowed_warning", "rate_limited")
  • rateLimitReset - When the rate limit resets
  • rateLimitRemaining - Remaining requests (if available)

Streaming Responses

The proxy endpoints support streaming responses for compatible Claude API calls. When making a streaming request:

  1. Include "stream": true in your request body
  2. The response will be Content-Type: text/event-stream
  3. Each chunk is delivered as a Server-Sent Event

Streaming Response Capture: ccflare automatically captures streaming response bodies for analytics and debugging purposes:

  • Captured data is limited to CF_STREAM_BODY_MAX_BYTES (default: 256KB)
  • The capture process doesn't interfere with the client's stream
  • Captured bodies are stored base64-encoded in the request history
  • If the response exceeds the size limit, it's marked as truncated in metadata

Example:

curl -X POST http://localhost:8080/v1/anthropic/v1/messages \
  -H "Content-Type: application/json" \
  -H "anthropic-version: 2023-06-01" \
  -d '{
    "model": "claude-sonnet-4-20250514",
    "messages": [{"role": "user", "content": "Write a poem"}],
    "max_tokens": 100,
    "stream": true
  }'

Dashboard

A web dashboard is available at:

http://localhost:8080/          # Dashboard

The dashboard provides a visual interface for:

  • Monitoring account status and usage
  • Viewing real-time analytics
  • Managing configuration
  • Examining request history

Configuration

Environment Variables

ccflare can be configured using the following environment variables:

  • PORT - Server port (default: 8080)
  • LB_STRATEGY - Load balancing strategy (default: session)
  • SESSION_DURATION_MS - Session duration in milliseconds (default: 18000000 / 5 hours)
  • CLIENT_ID - OAuth client ID for Anthropic authentication (default: 9d1c250a-e61b-44d9-88ed-5944d1962f5e)
  • CF_STREAM_BODY_MAX_BYTES - Maximum bytes to capture from streaming responses (default: 262144 / 256KB)
  • RETRY_ATTEMPTS - Number of retry attempts for failed requests (default: 3)
  • RETRY_DELAY_MS - Initial delay between retries in milliseconds (default: 1000)
  • RETRY_BACKOFF - Exponential backoff multiplier for retries (default: 2)

Configuration File

In addition to environment variables, ccflare supports configuration through a JSON file. The config file location varies by platform:

  • macOS/Linux: ~/.config/ccflare/ccflare.json (or $XDG_CONFIG_HOME/ccflare/ccflare.json)
  • Windows: %LOCALAPPDATA%\ccflare\ccflare.json (or %APPDATA%\ccflare\ccflare.json)

Supported Configuration Keys:

{
  "lb_strategy": "session",
  "client_id": "your-oauth-client-id",
  "retry_attempts": 3,
  "retry_delay_ms": 1000,
  "retry_backoff": 2,
  "session_duration_ms": 18000000,
  "port": 8080,
  "stream_body_max_bytes": 262144
}

Note: Environment variables take precedence over config file settings.

Load Balancing Strategies

The following strategy is available:

  • session - Session-based routing that maintains 5-hour sessions with individual accounts

⚠️ WARNING: Only use the session strategy. Other strategies can trigger Claude's anti-abuse systems and result in account bans.

Notes

  1. No Authentication: The API endpoints do not require authentication. ccflare manages the OAuth tokens internally for proxying to Claude.

  2. Automatic Failover: When a request fails or an account is rate limited, ccflare automatically tries the next available account. If no accounts are available, requests are forwarded without authentication as a fallback.

  3. Token Refresh: Access tokens are automatically refreshed when they expire.

  4. Request Logging: All requests are logged with detailed metrics including tokens used, cost, and response times. Database writes are performed asynchronously to avoid blocking request processing.

  5. Session Affinity: The "session" strategy maintains sticky sessions for consistent routing within a time window.

  6. Rate Limit Tracking: Rate limit information is automatically extracted from responses and stored for each account, including reset times and remaining requests.

  7. Provider Filtering: Accounts are automatically filtered by provider when selecting for requests, ensuring compatibility.