Skip to main content

Quota Services

The quota service provides a unified interface for fetching usage quotas and limits from various AI providers through CLIProxyAPI.

Overview

All quota methods:
  • Use the generic /v0/management/api-call endpoint
  • Require an authIndex parameter (references an auth file)
  • Return provider-specific quota models
  • Handle errors gracefully with error messages
Implementation: src/services/api/quota.service.ts

API Reference

fetchClaude

Fetches usage quota for Claude (Anthropic). Signature:
fetchClaude(authIndex: string): Promise<ClaudeQuotaResult>
authIndex
string
required
Index of the Claude auth file (e.g., "0", "1")
models
QuotaModel[]
Array of model quotas
email
string
User email associated with the account (optional)
error
string
Error message if the request failed
Types:
interface QuotaModel {
  name: string;        // Model name
  percentage: number;  // Usage percentage (0-100)
  resetTime?: string;  // When quota resets
  displayValue?: string; // Formatted display value
}

interface ClaudeQuotaResult {
  models: QuotaModel[];
  email?: string;
  error?: string;
}
Example:
import { quotaApi } from '@/services/api/quota.service';

const result = await quotaApi.fetchClaude('0');

if (result.error) {
  console.error('Failed to fetch quota:', result.error);
} else {
  result.models.forEach(model => {
    console.log(`${model.name}: ${model.percentage}% used`);
  });
}
Endpoint: GET https://api.anthropic.com/v1/usage Implementation: src/services/api/quota.service.ts:56

fetchAntigravity

Fetches usage quota for Antigravity (Mistral/Le Chat). Signature:
fetchAntigravity(authIndex: string): Promise<AntigravityQuotaResult>
authIndex
string
required
Index of the Antigravity auth file
models
QuotaModel[]
Array of model quotas
error
string
Error message if the request failed
Types:
interface AntigravityQuotaResult {
  models: QuotaModel[];
  error?: string;
}
Example:
const result = await quotaApi.fetchAntigravity('0');

if (result.models.length > 0) {
  console.log('Antigravity models:', result.models);
}
Behavior: Tries multiple quota URLs until one succeeds. Implementation: src/services/api/quota.service.ts:79

fetchCodex

Fetches usage quota for OpenAI/ChatGPT (Codex). Signature:
fetchCodex(authIndex: string, accountId?: string): Promise<CodexQuotaResult>
authIndex
string
required
Index of the OpenAI auth file
accountId
string
Optional ChatGPT account ID for team/organization accounts
plan
string
Subscription plan name (e.g., “ChatGPT Plus”, “ChatGPT Team”)
limits
Array
Array of usage limits with name, percentage, and reset time
error
string
Error message if the request failed
Types:
interface CodexQuotaResult {
  plan?: string;
  limits: Array<{
    name: string;
    percentage: number;
    resetTime?: string;
  }>;
  error?: string;
}
Example:
const result = await quotaApi.fetchCodex('0');

console.log('Plan:', result.plan);
result.limits.forEach(limit => {
  console.log(`${limit.name}: ${limit.percentage}% used`);
  if (limit.resetTime) {
    console.log(`Resets at: ${limit.resetTime}`);
  }
});

// With account ID for team accounts
const teamResult = await quotaApi.fetchCodex('0', 'org-abc123');
Endpoint: GET https://chatgpt.com/backend-api/usage Implementation: src/services/api/quota.service.ts:107

fetchGeminiCli

Fetches usage quota for Google Gemini (CLI/API Key based). Signature:
fetchGeminiCli(authIndex: string, projectId: string): Promise<GeminiCliQuotaResult>
authIndex
string
required
Index of the Gemini API key auth file
projectId
string
required
Google Cloud project ID
buckets
Array
Array of quota buckets with model ID, percentage, and reset time
error
string
Error message if the request failed
Types:
interface GeminiCliQuotaResult {
  buckets: Array<{
    modelId: string;
    percentage: number;
    resetTime?: string;
  }>;
  error?: string;
}
Example:
const result = await quotaApi.fetchGeminiCli('0', 'my-gcp-project');

result.buckets.forEach(bucket => {
  console.log(`Model ${bucket.modelId}: ${bucket.percentage}% used`);
});
Implementation: src/services/api/quota.service.ts:131

fetchKiro

Fetches usage quota for Kiro (DeepSeek/Siliconflow). Signature:
fetchKiro(authIndex: string): Promise<KiroQuotaResult>
authIndex
string
required
Index of the Kiro auth file
models
QuotaModel[]
Array of model quotas
plan
string
Subscription plan name or “Suspended” if account is suspended
email
string
User email (optional)
tokenExpiresAt
string
Token expiration timestamp (optional)
error
string
Error message if the request failed
Types:
interface KiroQuotaResult {
  models: QuotaModel[];
  plan?: string;
  email?: string;
  tokenExpiresAt?: string;
  error?: string;
}
Example:
const result = await quotaApi.fetchKiro('0');

if (result.plan === 'Suspended') {
  console.warn('Account is suspended!');
} else {
  console.log('Plan:', result.plan);
  console.log('Models:', result.models);
}
Special behavior: Returns a special suspended state for HTTP 403 with formatted reason. Implementation: src/services/api/quota.service.ts:151

fetchCopilot

Fetches entitlement status for GitHub Copilot. Signature:
fetchCopilot(authIndex: string): Promise<CopilotQuotaResult>
authIndex
string
required
Index of the GitHub Copilot auth file
models
QuotaModel[]
Array of available models/features
plan
string
Subscription plan (e.g., “Copilot Individual”, “Copilot Business”)
username
string
GitHub username (optional)
error
string
Error message if the request failed
Types:
interface CopilotQuotaResult {
  models: QuotaModel[];
  plan?: string;
  username?: string;
  error?: string;
}
Example:
const result = await quotaApi.fetchCopilot('0');

if (result.error) {
  console.error('No Copilot subscription:', result.error);
} else {
  console.log('Plan:', result.plan);
  console.log('User:', result.username);
  console.log('Available models:', result.models);
}
Endpoint: GET https://api.github.com/copilot_internal/v2/token Implementation: src/services/api/quota.service.ts:180

Error Handling

All quota methods handle errors gracefully: Common error scenarios:
  • 401/403: “Token invalid or expired”
  • 429: “Rate limit exceeded”
  • Network errors: Original error message
  • Long errors: Truncated to 100 characters
Error formatting:
const result = await quotaApi.fetchClaude('0');

if (result.error) {
  // Error messages are user-friendly and concise
  if (result.error.includes('Token invalid')) {
    // Re-authenticate
  } else if (result.error.includes('Rate limit')) {
    // Wait and retry
  }
}
Implementation: src/services/api/quota.service.ts:34

Usage Patterns

Polling for Updates

const pollQuota = async (authIndex: string) => {
  const result = await quotaApi.fetchClaude(authIndex);
  
  if (!result.error) {
    updateUI(result.models);
  }
  
  // Poll every 5 minutes
  setTimeout(() => pollQuota(authIndex), 5 * 60 * 1000);
};

Multi-Provider Fetching

const fetchAllQuotas = async (authFiles: AuthFile[]) => {
  const results = await Promise.allSettled(
    authFiles.map(file => {
      const authIndex = file.fileId;
      
      switch (file.provider) {
        case 'claude':
          return quotaApi.fetchClaude(authIndex);
        case 'openai':
          return quotaApi.fetchCodex(authIndex);
        case 'gemini':
          return quotaApi.fetchGeminiCli(authIndex, 'project-id');
        default:
          return Promise.resolve({ models: [], error: 'Unknown provider' });
      }
    })
  );
  
  return results;
};

Retry Logic

const fetchWithRetry = async (
  fetchFn: () => Promise<any>,
  maxRetries = 3
) => {
  for (let i = 0; i < maxRetries; i++) {
    const result = await fetchFn();
    
    if (!result.error || !result.error.includes('Rate limit')) {
      return result;
    }
    
    // Exponential backoff
    await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, i)));
  }
};

Type Definitions

Full type definitions from src/types/quota.ts:
interface QuotaModel {
  name: string;
  percentage: number;
  resetTime?: string;
  displayValue?: string;
}

interface AntigravityQuotaResult {
  models: QuotaModel[];
  error?: string;
}

interface ClaudeQuotaResult {
  models: QuotaModel[];
  email?: string;
  error?: string;
}

interface CodexQuotaResult {
  plan?: string;
  limits: Array<{ name: string; percentage: number; resetTime?: string }>;
  error?: string;
}

interface GeminiCliQuotaResult {
  buckets: Array<{ modelId: string; percentage: number; resetTime?: string }>;
  error?: string;
}

interface KiroQuotaResult {
  models: QuotaModel[];
  plan?: string;
  email?: string;
  tokenExpiresAt?: string;
  error?: string;
}

interface CopilotQuotaResult {
  models: QuotaModel[];
  plan?: string;
  username?: string;
  error?: string;
}

Build docs developers (and LLMs) love