SDK Reference

Alpha

One client, two languages. The Bear Lumen SDK tracks AI cost with one call: hand it a raw provider response and it auto-detects the provider, extracts token usage, and reports the cost. Pick your language and every example below follows along.

Examples in

Installation & setup

Install the Node.js SDK:

npm install @bearlumen/node-sdk

Construct a client with your API key. The key is required: the SDK does not read an environment variable for you, so pass it in explicitly.

TypeScript
import { BearLumen } from '@bearlumen/node-sdk';

// apiKey is required — the SDK does NOT read an env var for you, so pass it in.
const bear = new BearLumen({
  apiKey: process.env.BEAR_LUMEN_API_KEY!,
  // environment: 'staging',          // optional: targets api.staging.bearlumen.com
  // baseUrl: 'https://api.bearlumen.com',  // optional: overrides environment
  // timeout: 30000,                   // optional: ms (default 30000)
});

Confirm connectivity with a quick ping:

TypeScript
const { ok, organizationId } = await bear.ping();
console.log(ok, organizationId);

Tracking usage

track() is the one method most integrations need. Pass it a provider response and it auto-detects OpenAI, Anthropic, Bedrock, Gemini, Mistral, or Ollama, extracts the token usage, and queues a usage event for background delivery.

MethodDescription
bear.track(response, options?)Auto-detect a provider response and record token usage
bear.track(stream, options?)Wrap a streaming response; await .result for final usage
bear.track(null, { model, ... })Manually track a non-LLM service or pre-calculated cost
bear.flush()Flush queued events without stopping the worker
bear.shutdown()Flush queued events and stop the background worker (call before exit)
bear.ping()Verify connectivity and API key

Track a response

TypeScript
import OpenAI from 'openai';
const openai = new OpenAI();

const response = await openai.chat.completions.create({
  model: 'gpt-4o',
  messages: [{ role: 'user', content: 'Hello!' }],
});

// Hand the raw provider response to Bear Lumen — it auto-detects the provider,
// extracts token usage, and queues a usage event for background delivery.
const result = bear.track(response);
console.log(result.model, result.inputTokens, result.outputTokens);

Track a streaming response

For streams, track() returns a pass-through wrapper. Iterate it normally, then await its .result for the final usage once the stream is fully consumed.

TypeScript
// Streaming: track() returns a pass-through wrapper. Iterate as normal,
// then await .result for the final usage once the stream is consumed.
const stream = bear.track(response, { model: 'anthropic.claude-3-5-sonnet' });
for await (const chunk of stream) {
  // chunks pass through unchanged
}
const result = await stream.result;
console.log(result.inputTokens, result.outputTokens);

Track manually

No LLM response to hand over? Track non-token services (text-to-speech, images, GPU seconds) or a pre-calculated cost by passing null with explicit options. A model is required in this form.

TypeScript
import { Provider } from '@bearlumen/node-sdk';

// No LLM response? Track non-token services (TTS, images, GPU seconds) or a
// pre-calculated cost by passing null with explicit options. model is required.
bear.track(null, {
  model: 'eleven_multilingual_v2',
  provider: Provider.ELEVENLABS,
  feature: 'narration',
  units: { characters: 1500 },
});

Flush before exit

Flush before exit

track() batches events in the background. Call shutdown() (or flush()) before your process exits, or queued events are lost.
TypeScript
// track() batches events in the background, so flush before the process exits
// or queued events are lost.
await bear.shutdown(); // flushes the queue and stops the background worker
// or, to flush without stopping: await bear.flush();

Querying usage

The usage resource is read-only: it queries the events you have already tracked. Writes happen through track() above, not here.

MethodDescription
usage.events(params)Paginated usage events in a date range (read-only)
usage.summary(params)High-level totals for a date range
usage.aggregation(params)Usage aggregated by metric name

List events

TypeScript
const page = await bear.usage.events({
  startDate: '2026-01-01',
  endDate: '2026-01-31',
  limit: 100,        // optional (default 100, max 1000)
  offset: 0,         // optional
});
for (const e of page.events) console.log(e.model, e.inputTokens);

Summary

TypeScript
const s = await bear.usage.summary({ startDate: '2026-01-01', endDate: '2026-01-31' });
console.log(s.totalEvents, s.totalInputTokens, s.totalOutputTokens);

Cost analysis

Break cost down by model, provider, feature, agent, or workflow, pull trends and period-over-period summaries, or scope any query to a single end user.

MethodDescription
costs.byModel(params)Cost grouped by model
costs.byProvider(params)Cost grouped by provider
costs.byFeature(params)Cost grouped by feature label
costs.byAgent(params)Cost grouped by agent
costs.byWorkflow(params)Cost grouped by workflow
costs.trend(params)Org-level cost trend time series
costs.summary(params?)Cost with period-over-period comparison
costs.detailedByModel(params)Per-model breakdown with token counts
costs.detailedByProvider(params)Per-provider breakdown with token counts
costs.detailedByEndUser(params)Per-end-user breakdown with token counts
costs.forUser(externalId)Scope cost queries to one end user (chainable)

Cost by model

TypeScript
const byModel = await bear.costs.byModel({ startDate: '2026-01-01', endDate: '2026-01-31' });
for (const item of byModel.items) {
  console.log(item.attributionValue, item.totalCost, item.percentOfTotal);
}
console.log('Total:', byModel.totalCost);

Scope to one end user

TypeScript
// Scope any cost query to one end user by external id.
const user = bear.costs.forUser('user_123');
const summary = await user.summary({ startDate: '2026-01-01', endDate: '2026-01-31' });
const byModel = await user.byModel({ startDate: '2026-01-01', endDate: '2026-01-31' });

Attribution & custom dimensions

Attribute cost to any dimension you tag events with (team, customer, environment), list the agents and workflows that have data, and inspect sessions. The dimensions resource works with your configured custom dimensions.

MethodDescription
attribution.byDimension(params)Cost by an arbitrary tagged dimension
attribution.dimensionValues(params)Unique values for a dimension
attribution.dimensionKeys(params)Dimension keys with data in the range
attribution.timeSeries(params)Cost time series by dimension
attribution.agents(params)List agents with data in the range
attribution.workflows(params)List workflows with data in the range
attribution.sessions(params)Session cost breakdown (paginated)
attribution.sessionComparison(params)Compare cost across session types
attribution.sessionDetail(sessionId)Detailed breakdown for one session

Cost by a custom dimension

TypeScript
// Break cost down by any custom dimension you tagged events with.
const result = await bear.attribution.byDimension({
  dimension: 'team',
  startDate: '2026-01-01',
  endDate: '2026-01-31',
});
for (const item of result.items) console.log(item.attributionValue, item.totalCost);

// List the agents / workflows that have data in a range:
const { agents } = await bear.attribution.agents({ startDate: '2026-01-01', endDate: '2026-01-31' });

Custom dimensions

MethodDescription
dimensions.definitions()List configured custom dimensions
dimensions.costBreakdown(params)Cost broken down by a dimension key
dimensions.costTrend(params)Cost trend for a dimension
dimensions.numericSummary(params)Aggregate a numeric dimension (avg/sum/...)
dimensions.numericTrend(params)Numeric dimension trend over time

Margins & insights

If you report revenue to Bear Lumen, the margin and insight resources turn cost into profitability: margin by period, by end user, and over time.

MethodDescription
margins.summary(params)Revenue vs cost margin for a range
margins.byEndUser(params)Margin broken down per end user
margins.trend(params)Margin trend over time
insights.summary(params)Cost/usage insights with distributions

Margin summary

TypeScript
const result = await bear.margins.summary({ startDate: '2026-01-01', endDate: '2026-01-31' });
console.log(result.summary.marginPercent);

const byUser = await bear.margins.byEndUser({ startDate: '2026-01-01', endDate: '2026-01-31' });
for (const u of byUser.endUsers) console.log(u.endUserName, u.marginPercent);

Insights

TypeScript
const result = await bear.insights.summary({
  start: '2026-01-01',
  end: '2026-01-31',
  include: ['distributions'],
  limit: 10,
});
console.log(result.totals);

Error handling

The Node SDK throws a single BearLumenApiError; branch on its code (for example rate_limit_exceeded). Every error carries a correlationId to include in support tickets.

TypeScript
import { BearLumen, BearLumenApiError } from '@bearlumen/node-sdk';

try {
  await bear.margins.summary({ startDate: '2026-01-01', endDate: '2026-01-31' });
} catch (error) {
  if (error instanceof BearLumenApiError) {
    if (error.code === 'rate_limit_exceeded') {
      console.error('Rate limited, retry after', error.retryAfter, 'seconds');
    }
    console.error('Error', error.code, error.message);
    console.error('Request ID:', error.correlationId); // include in support tickets
  }
}

Requirements

  • Node.js >= 18.0.0
  • Package @bearlumen/node-sdk (written in TypeScript, full type definitions included)