# Burnwise SDK Documentation > Track and optimize your LLM costs with zero friction. ## Installation ```bash npm install @burnwise/sdk ``` **Compatibility**: Node.js 18+, Edge Runtime (Vercel), Cloudflare Workers (since v0.1.5) ## Quick Start ```typescript import { burnwise } from "@burnwise/sdk"; import OpenAI from "openai"; // Initialize once at app startup burnwise.init({ apiKey: process.env.BURNWISE_API_KEY!, }); // Wrap your OpenAI client const openai = burnwise.openai.wrap(new OpenAI(), { feature: "chat-support", }); // Use normally - costs are tracked automatically! const response = await openai.chat.completions.create({ model: "gpt-5.2", messages: [{ role: "user", content: "Hello!" }], }); ``` ## Supported Providers ### OpenAI ```typescript const openai = burnwise.openai.wrap(new OpenAI(), { feature: "chat" }); await openai.chat.completions.create({ model: "gpt-5.2", messages: [...] }); ``` Models: gpt-5.2 ($1.75/$14), gpt-5.1 ($1.25/$10), gpt-5-mini ($0.30/$1), gpt-4.1 ($2/$8), o3 ($10/$40), o3-mini ($1.10/$4.40) ### Anthropic ```typescript const anthropic = burnwise.anthropic.wrap(new Anthropic(), { feature: "analysis" }); await anthropic.messages.create({ model: "claude-opus-4-5-20251101", max_tokens: 1024, messages: [...] }); ``` Models: claude-opus-4-5-20251101 ($5/$25), claude-sonnet-4-5-20250929 ($3/$15), claude-haiku-4-5-20251001 ($1/$5) ### Google Gemini ```typescript const genAI = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY!); const model = burnwise.google.wrapModel(genAI.getGenerativeModel({ model: "gemini-3.0-flash" }), { feature: "summary" }); await model.generateContent("Hello!"); ``` Models: gemini-3-pro-preview ($2/$12), gemini-3-flash-preview ($0.50/$3), gemini-2.5-pro ($1.25/$10), gemini-2.0-flash ($0.10/$0.40) ### xAI (Grok) ```typescript const xai = burnwise.xai.wrap(new OpenAI({ baseURL: "https://api.x.ai/v1", apiKey: process.env.XAI_API_KEY! }), { feature: "reasoning" }); await xai.chat.completions.create({ model: "grok-4.1", messages: [...] }); ``` Models: grok-4 ($3/$15), grok-4.1-fast ($0.20/$0.50), grok-3 ($3/$15), grok-3-mini ($0.30/$0.50) ### Mistral ```typescript const mistral = burnwise.mistral.wrap(new Mistral(), { feature: "code" }); await mistral.chat.complete({ model: "mistral-large-3", messages: [...] }); ``` Models: mistral-large-3 ($2/$6), mistral-small-3 ($0.20/$0.60), devstral-2 ($0.50/$1.50), ministral-8b ($0.10/$0.10) ### DeepSeek ```typescript const deepseek = burnwise.deepseek.wrap(new OpenAI({ baseURL: "https://api.deepseek.com/v1", apiKey: process.env.DEEPSEEK_API_KEY! }), { feature: "coding" }); await deepseek.chat.completions.create({ model: "deepseek-v3.2", messages: [...] }); ``` Models: deepseek-v3.2 ($0.27/$1.10), deepseek-r1 ($0.55/$2.19), deepseek-chat ($0.14/$0.28) ### Perplexity ```typescript const perplexity = burnwise.perplexity.wrap(new OpenAI({ baseURL: "https://api.perplexity.ai", apiKey: process.env.PERPLEXITY_API_KEY! }), { feature: "research" }); await perplexity.chat.completions.create({ model: "sonar-pro", messages: [...] }); ``` Models: sonar-pro ($3/$15), sonar-reasoning-pro ($2/$8), sonar-reasoning ($1/$5), sonar ($1/$1) ## Multi-Modal Support Burnwise tracks costs across all content types: text (LLM), images, videos, and audio. ### Image Generation ```typescript import { calculateImageCost, IMAGE_PRICING } from "@burnwise/sdk"; const cost = calculateImageCost("dall-e-3", 4, "1024x1024", "hd"); // 4 images × $0.08 = $0.32 ``` Models: dall-e-3 ($0.04-$0.12/image), dall-e-2 ($0.02), imagen-4.0 ($0.02-$0.06), grok-2-image-1212 ($0.07) ### Video Generation ```typescript import { calculateVideoCost, VIDEO_PRICING } from "@burnwise/sdk"; const cost = calculateVideoCost("veo-3.1-generate-preview", 8); // 8s × $0.40 = $3.20 ``` Models: veo-3.1-generate-preview ($0.40/s), veo-3.1-fast-generate-preview ($0.15/s) ### Audio (TTS/STT) ```typescript import { calculateAudioCost, AUDIO_PRICING } from "@burnwise/sdk"; const cost = calculateAudioCost("tts-1-hd", 5000); // 5K chars × $0.03 = $0.15 ``` Models: tts-1 ($0.015/1K chars), tts-1-hd ($0.030/1K chars), whisper-1 ($0.0001/s) ### Manual Multi-Modal Tracking ```typescript // Track image generation await track({ provider: "openai", model: "dall-e-3", contentType: "image", feature: "avatar-generation", imageCount: 4, imageResolution: "1024x1024", imageQuality: "hd", costUsd: 0.32, latencyMs: 12000, }); // Track video generation await track({ provider: "google", model: "veo-3.1-generate-preview", contentType: "video", feature: "marketing-video", videoDurationSec: 15, costUsd: 6.0, latencyMs: 45000, }); // Track TTS await track({ provider: "openai", model: "tts-1-hd", contentType: "audio", feature: "podcast-narration", audioCharacters: 10000, costUsd: 0.30, latencyMs: 5000, }); ``` ## Streaming Support All provider wrappers support streaming responses with automatic token tracking. The SDK intercepts the stream, captures usage data from stream events, and tracks costs when the stream completes. ### How It Works - **OpenAI-compatible APIs** (OpenAI, xAI, DeepSeek, Perplexity): SDK automatically adds `stream_options: { include_usage: true }` - **Anthropic**: Usage extracted from `message_start` (input tokens) and `message_delta` (output tokens) events - **Google Gemini**: Both `generateContent()` and `generateContentStream()` are wrapped - **Mistral**: The `chat.stream()` method is wrapped to capture usage from stream chunks ### Streaming Examples ```typescript // OpenAI streaming const stream = await openai.chat.completions.create({ model: "gpt-5.2", messages: [{ role: "user", content: "Tell me a story" }], stream: true, }); for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content || ""); } // Usage tracked automatically when loop completes // Anthropic streaming const stream = await anthropic.messages.create({ model: "claude-sonnet-4-5-20250929", max_tokens: 1024, messages: [{ role: "user", content: "Write a poem" }], stream: true, }); for await (const event of stream) { if (event.type === "content_block_delta") { process.stdout.write(event.delta.text || ""); } } // Usage tracked automatically // Google Gemini streaming const result = await model.generateContentStream("Explain quantum computing"); for await (const chunk of result.stream) { process.stdout.write(chunk.text()); } // Usage tracked automatically ``` ## Feature Tracking Tag your LLM calls with features to understand cost breakdown: ```typescript const chatClient = burnwise.openai.wrap(new OpenAI(), { feature: "chat-support" }); const analysisClient = burnwise.openai.wrap(new OpenAI(), { feature: "document-analysis" }); const summaryClient = burnwise.openai.wrap(new OpenAI(), { feature: "auto-summary" }); ``` ## LLM Instructions: Generating Feature JSON for Bulk Import When instrumenting an app with Burnwise, generate a JSON file with all features used in the code. The user can then import this JSON into the Burnwise dashboard at Settings > Features > Import JSON. ### JSON Format (Hierarchical) Features can be organized in a folder-like hierarchy (max 3 levels). Use `children` to nest features: ```json { "features": [ { "slug": "idea-analysis", "name": "Idea Analysis", "description": "Main orchestrator for idea analysis", "children": [ { "slug": "market-scan", "name": "Market Scan", "description": "Analyze market opportunity" }, { "slug": "competitor-analysis", "name": "Competitor Analysis" }, { "slug": "synthesis", "name": "Synthesis", "description": "Final synthesis" } ] }, { "slug": "chat-assistant", "name": "Chat Assistant", "description": "Main chat interface" }, { "slug": "document-analysis", "name": "Document Analysis" } ] } ``` ### Rules for generating features: 1. **slug**: lowercase, alphanumeric with hyphens (e.g., "chat-assistant", "market-scan") - **IMPORTANT**: Child slugs are standalone - do NOT prefix with parent name - Use "business-expert", NOT "idea-analysis.business-expert" or "idea-analysis-business-expert" - The hierarchy is defined by the `children` array, not by slug naming 2. **name**: Human-readable name (e.g., "Chat Assistant", "Market Scan") 3. **description**: Optional, describes what the feature does 4. **children**: Optional array of child features (max 3 levels of nesting) ### Slug naming convention: ``` CORRECT: INCORRECT: idea-analysis/ idea-analysis/ ├── business-expert ├── idea-analysis.business-expert ├── product-expert ├── idea-analysis-business-expert └── synthesis └── idea-analysis.synthesis ``` ### Import behavior (idempotent sync): The import is a **sync operation**, not just an insert: - **New features** → Created - **Existing features in wrong location** → Moved to match JSON hierarchy - **Existing features with different name/description** → Updated - **Features not in JSON** → Left untouched (not deleted) This means you can re-import the same JSON multiple times safely. It will reorganize features to match the JSON structure. ### Example workflow: 1. Instrument the app with Burnwise SDK using `burnwise.trace("slug", ...)` for hierarchy 2. Generate the features JSON with the same slugs (hierarchy via `children` array) 3. Sync JSON in Burnwise dashboard > Settings > Features > Sync JSON 4. Re-sync anytime to update the hierarchy - existing features will be moved/updated 5. Costs automatically aggregate from children to parents in the dashboard ## Hierarchical Agent Tracing Track costs for multi-agent systems with parent-child relationships. Perfect for agent orchestration where a main agent calls multiple sub-agents. ### Basic Usage ```typescript import { burnwise } from "@burnwise/sdk"; await burnwise.trace("idea-analysis", async () => { // All LLM calls inside are tagged with: // - traceId: UUID for entire execution tree // - spanId: UUID for this span // - spanName: "idea-analysis" // - traceDepth: 0 (root) const market = await burnwise.trace("market-scan", async () => { // Nested span: same traceId, own spanId, parentSpanId points to parent return await marketAgent.run(idea); }); const competitors = await burnwise.trace("competitor-analysis", async () => { return await competitorAgent.run(idea); }); return { market, competitors }; }); ``` ### How It Works 1. **Automatic Context Propagation**: Uses Node.js AsyncLocalStorage. All LLM calls within a trace() function inherit the trace context automatically. 2. **Tree Structure**: Each span has: - traceId: UUID shared by all spans in execution tree - spanId: UUID unique to this span - parentSpanId: UUID of parent span (undefined for root) - spanName: Human-readable name (e.g., "market-scan") - traceDepth: Level in tree (0 = root, max 3) 3. **Depth Limit**: Maximum 3 levels of nesting. 4. **Dashboard Visualization**: View traces at /traces in the dashboard with tree visualization, cost breakdown per span, latency bars, and provider indicators. ### Full Example ```typescript import { burnwise } from "@burnwise/sdk"; import Anthropic from "@anthropic-ai/sdk"; burnwise.init({ apiKey: process.env.BURNWISE_API_KEY! }); const anthropic = burnwise.anthropic.wrap(new Anthropic(), { feature: "idea-analysis", }); async function analyzeIdea(idea: string) { return burnwise.trace("idea-analysis", async () => { const market = await burnwise.trace("market-scan", async () => { const response = await anthropic.messages.create({ model: "claude-sonnet-4-5-20250929", max_tokens: 2000, messages: [{ role: "user", content: `Analyze market for: ${idea}` }], }); return response.content[0].text; }); const competitors = await burnwise.trace("competitor-analysis", async () => { const response = await anthropic.messages.create({ model: "claude-sonnet-4-5-20250929", max_tokens: 2000, messages: [{ role: "user", content: `Find competitors for: ${idea}` }], }); return response.content[0].text; }); const synthesis = await burnwise.trace("synthesis", async () => { const response = await anthropic.messages.create({ model: "claude-opus-4-5-20251101", max_tokens: 4000, messages: [{ role: "user", content: `Synthesize:\nMarket: ${market}\nCompetitors: ${competitors}`, }], }); return response.content[0].text; }); return { market, competitors, synthesis }; }); } // All 4 LLM calls tracked with same traceId const analysis = await analyzeIdea("AI-powered recipe generator"); ``` ### Tracing API Reference ```typescript // Async trace (most common) const result = await burnwise.trace("span-name", async () => { return await doSomething(); }); // Sync trace const result = burnwise.traceSync("span-name", () => doSomethingSync()); // Trace with result metadata const { result, spanId, traceId, durationMs } = await burnwise.traceWithResult("span-name", async () => await doSomething()); // Check if in trace if (burnwise.isInTrace()) { ... } // Get context const context = burnwise.getTraceContext(); // context.traceId, context.spanId, context.parentSpanId, context.spanName, context.depth ``` ## Field Limits When sending events to Burnwise, the following string field limits apply: | Field | Max Length | Description | |-------|-----------|-------------| | feature | 200 chars | Feature slug for cost attribution | | spanName | 200 chars | Span name from trace context | | model | 100 chars | Model identifier | | userId | 255 chars | Hashed user identifier | | sessionId | 255 chars | Session identifier | | requestId | 255 chars | Request identifier | | traceId | 255 chars | Trace ID for grouping | | spanId | 255 chars | Span ID | | parentSpanId | 255 chars | Parent span ID | | errorCode | 100 chars | Error code if status is error | If a field exceeds its limit, you'll receive a validation error with details about which field caused the issue. ## Configuration ```typescript burnwise.init({ apiKey: "bw_live_xxx", // Required baseUrl: "https://api.burnwise.io", // Optional: custom endpoint debug: true, // Optional: enable logging (shows init confirmation) batchEvents: true, // Optional: batch before sending batchFlushInterval: 5000, // Optional: flush interval ms maxBatchSize: 100, // Optional: max batch size environment: "production", // Optional: production | staging | development }); // Check if SDK is ready (useful for conditional environments) if (burnwise.isInitialized()) { // Safe to use burnwise.trace(), wrappers, etc. } ``` With `debug: true`, you'll see: ``` [Burnwise] ✅ Initialized (production) [Burnwise] API Key: bw_live_xx... [Burnwise] Endpoint: https://burnwise.io/api [Burnwise] Batching: enabled (5000ms) ``` ## Manual Tracking ```typescript import { track } from "@burnwise/sdk"; await track({ provider: "openai", model: "gpt-5.2", feature: "custom-feature", promptTokens: 100, completionTokens: 50, latencyMs: 1200, costUsd: 0.002, status: "success", }); ``` ## Privacy - We ONLY track metadata: token counts, cost, model, latency - We NEVER read, store, or transmit prompt content - We NEVER read, store, or transmit completion content - GDPR compliant - All data encrypted in transit and at rest ## Links - npm: https://www.npmjs.com/package/@burnwise/sdk - GitHub: https://github.com/KotyV/Burnwise - Dashboard: https://burnwise.io