JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 15
  • Score
    100M100P100Q81672F
  • License MIT

Fetch monthly OpenAI and Anthropic API spend from provider Usage APIs. CLI + Slack/Discord webhook helpers included. Read-only admin keys, zero dependencies.

Package Exports

  • capped-cost
  • capped-cost/webhook

Readme

capped-cost

Fetch monthly OpenAI and Anthropic API spend. Library, CLI, and webhook alerts. Zero runtime dependencies.

npm install capped-cost

Built alongside Capped — a Chrome extension that watches your OpenAI and Anthropic spend and alerts you at 80/100/150% of a monthly cap. If you want the budgeting + alerting without writing the cron yourself, try the extension. If you want to build something custom, this package is the primitive.

What you get

  • LibraryfetchOpenAICost, fetchAnthropicCost, fetchAllCosts. Normalized output, cents everywhere.
  • CLIcapped-cost binary. Cron-friendly exit codes. JSON or human-readable.
  • Webhook helpers — Slack + Discord, auto-detected. postCostAlert + checkAndAlert for one-shot cron alerts.

~6 KB gzipped. Zero runtime deps. Works on Node 18+, Bun, Deno, browsers, Chrome extensions.


1. Library

OpenAI only

import { fetchOpenAICost } from "capped-cost";

const result = await fetchOpenAICost(process.env.OPENAI_ADMIN_KEY!);

if ("error" in result) {
  console.error(result.error);
} else {
  console.log(`Month to date: $${(result.totalCents / 100).toFixed(2)}`);
  for (const [day, cents] of result.dailyCents) {
    console.log(`  ${day}: $${(cents / 100).toFixed(2)}`);
  }
}

Anthropic only

import { fetchAnthropicCost } from "capped-cost";
// same shape as fetchOpenAICost

Both providers in parallel

import { fetchAllCosts } from "capped-cost";

const { totalCents, dailyCents, providers } = await fetchAllCosts({
  openai: process.env.OPENAI_ADMIN_KEY,
  anthropic: process.env.ANTHROPIC_ADMIN_KEY,
});

console.log(`Combined month to date: $${(totalCents / 100).toFixed(2)}`);

2. CLI

npm install -g capped-cost
# Minimum
export OPENAI_ADMIN_KEY=sk-admin-...
export ANTHROPIC_ADMIN_KEY=...
capped-cost

# With a cap; exits 2 when month-to-date >= 80% of $100
capped-cost --cap=100

# Strict: alert when at 50% of cap
capped-cost --cap=100 --threshold=0.5

# JSON output
capped-cost --json | jq '.totalUsd'

# Include per-day breakdown
capped-cost --daily

Exit codes

Code Meaning
0 Under threshold (or no cap set)
1 Config or API error
2 At or above threshold

Cron example

Check every hour, alert Slack if over cap:

0 * * * * capped-cost --cap=100 || curl -X POST \
  -H 'Content-Type: application/json' \
  -d '{"text":"AI spend alert — check the usage dashboard"}' \
  "$SLACK_WEBHOOK_URL"

For a cleaner alert pipeline, use the webhook module below.


3. Webhook helpers

Post a formatted alert to Slack or Discord. Provider auto-detected from URL.

One-shot check + alert

import { checkAndAlert } from "capped-cost/webhook";

const result = await checkAndAlert({
  keys: {
    openai: process.env.OPENAI_ADMIN_KEY,
    anthropic: process.env.ANTHROPIC_ADMIN_KEY,
  },
  capUsd: 100,
  threshold: 0.8,                    // optional, default 0.8
  webhookUrl: process.env.SLACK_WEBHOOK_URL!,
  label: "production",               // optional; appears in alert text
});

console.log(`Total: $${result.totalUsd.toFixed(2)} (${(result.pct * 100).toFixed(0)}%)`);
if (result.alerted) {
  console.log(result.webhookResult?.ok ? "alerted" : `alert failed: ${result.webhookResult?.error}`);
}

Lower-level primitives

import { postCostAlert, formatAlertMessage } from "capped-cost/webhook";

// Just format, don't send — drop into your own pipeline
const text = formatAlertMessage({
  totalUsd: 87.23,
  capUsd: 100,
  threshold: 0.8,
  label: "production",
});
// → "⚠️ AI spend alert (production)\nMonth-to-date: $87.23 / $100.00 cap — 87% used\nThreshold: 80%"

// Or send directly
await postCostAlert(
  { url: process.env.SLACK_WEBHOOK_URL! },
  { totalUsd: 87.23, capUsd: 100, threshold: 0.8, label: "production" }
);

Complete 10-line cron job

// budget-check.ts — run from cron
import { checkAndAlert } from "capped-cost/webhook";

const r = await checkAndAlert({
  keys: {
    openai: process.env.OPENAI_ADMIN_KEY,
    anthropic: process.env.ANTHROPIC_ADMIN_KEY,
  },
  capUsd: Number(process.env.CAP_USD || 100),
  webhookUrl: process.env.SLACK_WEBHOOK_URL!,
});

if (r.alerted && !r.webhookResult?.ok) process.exit(1);

Admin keys

Both providers require an Organization Admin Key — different from a standard API key. Admin keys can read usage but cannot make model calls or spend money.

Store admin keys the same way you store any production secret. capped-cost does not proxy, log, or transmit them anywhere outside the direct call to the provider.


API reference

// Library
fetchOpenAICost(adminKey: string, options?: FetchOptions)
  => Promise<CostResult | CostError>

fetchAnthropicCost(adminKey: string, options?: FetchOptions)
  => Promise<CostResult | CostError>

fetchAllCosts(
  keys: { openai?: string; anthropic?: string },
  options?: FetchOptions
) => Promise<CombinedCostResult>

// Webhook (import from "capped-cost/webhook")
checkAndAlert(options: CheckAndAlertOptions) => Promise<CheckAndAlertResult>
postCostAlert(target, payload) => Promise<{ ok: boolean; status?: number; error?: string }>
formatAlertMessage(payload: AlertPayload) => string

// Types
interface CostResult { dailyCents: Map<string, number>; totalCents: number; }
interface CostError { error: string; }
interface FetchOptions { fetch?: typeof globalThis.fetch; signal?: AbortSignal; }

Runtime support

  • Node 18+ (native fetch)
  • Bun
  • Deno
  • Every modern browser (CORS permitting)
  • Chrome extensions (service workers + content scripts)

Roadmap

  • Gemini adapter (via Google Cloud Billing API) — #2
  • AWS Bedrock adapter (via Cost Explorer) — #3
  • Rate-limit metrics output (requests/day + tokens/day) — #1

PRs welcome. Gemini and Bedrock each need provider-specific auth flows that would break the zero-deps promise of this package — if built, they'll likely ship as separate companion packages (capped-cost-gemini, capped-cost-bedrock) so this core stays lean.


License

MIT.