Cosmo Docs
Server

Metering Module

Token usage tracking and quota enforcement

The Metering module tracks LLM token consumption and enforces per-user daily quotas. Source: packages/server/src/modules/metering/.

REST Endpoints

All endpoints are prefixed with /api/v1/metering and require ClerkAuthGuard.

MethodPathDescription
GET/metering/orgOrg-level usage for billing period
GET/metering/userUser's usage for the current billing period
GET/metering/quotaUser's current quota status
DELETE/metering/resetReset today's usage records (debug only)

Metering Service (services/metering.service.ts)

recordLLMUsage(params)

Called by ChatService after every LLM response. Parameters:

FieldTypeDescription
orgIdstringOrganisation
userIdstringUser who made the request
modelstringModel ID (e.g. claude-sonnet-4-20250514)
inputTokensnumberPrompt tokens
outputTokensnumberCompletion tokens
metadataJSON?Extra context (session ID, workspace, etc.)

Cost is calculated based on model pricing from @cosmohq/core.

checkQuota(orgId, userId?)

Returns the current quota status. Called by QuotaGuard before every chat request.

Response:

{
  allowed: boolean;
  usedTokens: number;
  limitTokens: number;
  percentage: number;  // 0–100
  plan: Plan;
}

Orgs whose plan has tokensPerUserPerDay === -1 always return allowed: true (unlimited quota). Note: the ENTERPRISE plan currently has a fixed daily limit of 10M tokens, same as PREMIUM.

getOrgUsageSummary(orgId)

Aggregates token usage for the org across the current billing period:

{
  totalInputTokens: number;
  totalOutputTokens: number;
  totalTokens: number;
  totalCostUsd: number;
  byModel: { model: string; tokens: number; cost: number }[];
  byUser: { userId: string; tokens: number; cost: number }[];
}

getUserUsageSummary(orgId, userId)

Today's usage for the requesting user:

{
  usedTokens: number;
  limitTokens: number;
  percentage: number;
  inputTokens: number;
  outputTokens: number;
  costUsd: number;
}

resetDailyUsage(orgId, userId?)

Deletes all UsageRecord rows for today. If userId is provided, deletes only that user's records. Used for debug/testing.

Quota Limits by Plan

PlanDaily Token Limit (per user)
NO_PLAN0 (blocked)
FREE1,000,000
STANDARD2,000,000
PREMIUM10,000,000
ENTERPRISE10,000,000

Quotas reset at midnight UTC each day (records are scoped by date in the query).

Usage Record Schema

FieldTypeDescription
idstringPrimary key
orgIdstringOrganisation
userIdstringUser
typeUsageType enumUsage category (LLM_CHAT, LLM_AGENT, etc.)
inputTokensintInput tokens
outputTokensintOutput tokens
modelstring?Model ID (nullable)
costUsdDecimalCost in USD
metadataJSON?Extra context
createdAtDateTimeUsage timestamp (used for date filtering)

QuotaGuard

packages/server/src/common/guards/quota.guard.ts is applied to POST /api/v1/chat:

  1. Calls MeteringService.checkQuota(orgId, userId).
  2. If allowed: false, throws ForbiddenExceptionHTTP 403 with the quota status payload.
  3. If allowed: true, the request proceeds to the chat handler.