Skip to content

AI Cost Map docs

AI Cost Map records the token counts of each AI call with a feature label and prices them on the server, so you see the AI cost of each feature. A customer label and revenue are optional extras for the Customers screen. The SDK is TypeScript only in v1 and runs on Node 18+ and the Vercel Edge runtime.

Set up with your coding agent

Copy the prompt and paste it into Claude Code, Cursor, Codex or any coding agent in your repository. The agent installs the SDK, proposes a feature tree for you to approve, wraps your AI clients, labels every call and checks the coverage.

Then add your API key from Setup.

The first step of the prompt is npx aicostmap init. It installs the SDK, writes .claude/skills/aicostmap/SKILL.md, adds a section to AGENTS.md and an entry to .env.example. The Agent Skill tells the agent to:

  1. Find all AI call sites and client constructors.
  2. Propose a feature tree, for example posts.generate and posts.refine.tone, and ask you to approve it.
  3. Wrap each client where it is constructed.
  4. Add scope() at entry points: route handlers, server actions, queue jobs and cron jobs.
  5. Find where the customer id is known (the Stripe cus_… id is best) and add it to the scope.
  6. Run npx aicostmap verify until it reports full coverage.

Manual setup

  1. Install the SDK

    npm install aicostmap
  2. Add your API key

    Create a key in Setup. Each key belongs to one project environment.

    .env.local
    AICOSTMAP_API_KEY=acm_live_…
  3. Wrap your AI clients

    wrap() returns a client with the same type. It reads the usage object of each response and sends it in background batches. It never blocks or throws.

    lib/ai.tsTypeScript
    // lib/ai.ts
    import { AICostMap } from "aicostmap";
    import Anthropic from "@anthropic-ai/sdk";
    import OpenAI from "openai";
    
    export const acm = new AICostMap({
      apiKey: process.env.AICOSTMAP_API_KEY,
      environment: process.env.VERCEL_ENV ?? "development",
    });
    
    export const anthropic = acm.wrap(new Anthropic());
    export const openai = acm.wrap(new OpenAI());
  4. Label features and customers

    Wrap each entry point in scope(). Every AI call inside the scope gets its labels.

    route.tsTypeScript
    // app/api/posts/generate/route.ts
    import { acm, anthropic } from "@/lib/ai";
    
    export async function POST(req: Request) {
      const { text, customerId } = await req.json();
      return acm.scope({ feature: "posts.generate", customerId }, async () => {
        const msg = await anthropic.messages.create({
          model: "claude-sonnet-5-5",
          max_tokens: 512,
          messages: [{ role: "user", content: text }],
        });
        return Response.json(msg);
      });
    }
  5. Check coverage

    npx aicostmap verify

    The command lists unwrapped clients and call sites with no scope. Add --ci to fail the build when something is not covered.

Features and customers

  • feature is a dot path, for example posts.generate or posts.refine.tone. The dashboard builds a tree from it. Use lowercase letters, digits, _ and -, max 6 levels.
  • customerId (optional) is your customer. Use the Stripe customer id (cus_…) when you can: revenue then matches with no extra work.
  • tags are free key-value filters, max 10 keys.
  • Calls with no feature show as untagged.

To override the labels for one call, pass a aicostmap key in the request options. The SDK removes it before it calls the provider.

await openai.chat.completions.create(
  { model: "gpt-6.1-sol", messages },
  { aicostmap: { feature: "posts.refine.tone" } }, // per-call label, removed before the provider call
);

Vercel AI SDK and manual tracking

AI SDK middlewareTypeScript
import { wrapLanguageModel } from "ai";
import { openai } from "@ai-sdk/openai";
import { acm } from "@/lib/ai";

const model = wrapLanguageModel({
  model: openai("gpt-6.1-sol"),
  middleware: acm.aiSdkMiddleware(),
});

For a provider with no adapter, send the counts yourself:

track()TypeScript
acm.track({
  provider: "self-hosted",
  model: "acme-ft-classifier",
  usage: { inputTokens: 900, outputTokens: 8 },
  feature: "users.rate",
});

Revenue (optional)

Cost per feature needs no revenue. The Customers screen can also show AI margin per customer (revenue − AI cost) when you connect revenue per customer per month. There are three sources:

  • Stripe restricted key with read access to customers, subscriptions and invoices only. Monthly revenue = paid invoices in the month, converted to USD at the invoice date rate.
  • Revenue API (Pro and Team):
curl -X POST https://aicostmap.com/api/v1/revenue \
  -H "Authorization: Bearer $AICOSTMAP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"customerId":"cus_123","amount":199,"currency":"USD","periodStart":"2026-10-01","periodEnd":"2026-10-31"}'
  • CSV upload in Setup (Pro and Team):
revenue.csv
customer_id,month,amount,currency
cus_Q4f8ZpL2,2026-09,199.00,USD
team-orchid,2026-09,2400.00,USD

Customers match in this order: (1) customerId equals the Stripe cus_… id, (2) the Stripe customer metadata key aicostmap_id, (3) a manual mapping in Setup.

What the SDK sends

Provider, model, token counts by type, labels, status, latency and an event id. Never prompts, outputs, tool data or keys. See the example payload. For AI agents and crawlers, a plain text summary is at /llms.txt.