SDK Reference
AlphaOne 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.
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.
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:
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.
| Method | Description |
|---|---|
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
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.
// 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.
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.// 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.
| Method | Description |
|---|---|
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
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
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.
| Method | Description |
|---|---|
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
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
// 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.
| Method | Description |
|---|---|
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
// 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
| Method | Description |
|---|---|
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.
| Method | Description |
|---|---|
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
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
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.
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)