Changes to the Bear Lumen API and official SDKs. Endpoints, SDK methods, and breaking changes, newest first.
Node 0.13.0 / Python 0.11.0
Relative date windows and one-line setup
New Features
+Every dated read method accepts a relative window: lastDays (Node) or last_days (Python), as an alternative to an explicit startDate / endDate pair
+BearLumen.init() / getBearLumen() (Node) and bearlumen.init() / bearlumen.get_client() (Python) give you a process-global client, so you configure once at startup instead of threading an instance through your call graph
+Both read the BEARLUMEN_API_KEY environment variable when no key is passed
Improvements
*Relative windows resolve client-side and end tomorrow, so an event you tracked seconds ago is always inside the window you just asked for
*A dated read method called with no window now throws before the request leaves your process, naming both accepted forms
*The wire contract is unchanged. Explicit date ranges keep working exactly as before
*Python 0.11.0 is the first non-alpha release of the bearlumen package
Node 0.12.0 / Python 0.10.0a1
Span budgets and cross-process tracing
New Features
+Span budgets: declare budget: { usd, onExceeded } (Node) or budget={"usd": ..., "on_exceeded": ...} (Python) on a span, and every provider call inside it is checked before it executes. Budgets nest, so a child span debits every enclosing cap
+New BudgetExceededError, exported from both SDKs, carrying the cap, the spend so far, and the span name. It surfaces to your code like any other provider error rather than being swallowed into telemetry
+The non-blocking alternative is onExceeded: "flag" (Node) or on_exceeded="flag" (Python): the breach stamps metadata on subsequent events and calls continue
+traceContext() / trace_context() returns the active span as a W3C trace context carrier, and the parent span option resumes a trace from it, so a queue, worker, or webhook continues the caller trace
+New GET /rate-cards/estimation-table returns effective per-model rates, which the SDKs refresh into their bundled price table for budget estimation
Improvements
*Carriers are standard W3C traceparent and tracestate, so OpenTelemetry-instrumented transports carry them natively
*Budget estimates are client-side and deliberately conservative. The billing-grade cost ledger stays server-side
*Carrier bytes are cross-checked between the two SDKs by a shared fixture, so a trace started in Python resumes in Node
Node 0.11.0 / Python 0.9.0a1
Spans, outcomes, and cost per unit of value
New Features
+Unit-of-work spans: withSpan() and traced() (Node), bear.span() as a decorator or context manager (Python). Every tracked call inside a span, at any async depth, shares one session and links to its caller, so the full call tree reconstructs
+Outcomes: declare outcome on the span that produces a unit of value and every cost event inside carries it, with one zero-cost terminal event recording whether the unit completed or failed
+setAttribute() / set_attribute() adds a metadata label to the running span, applying forward to events tracked from that point on
+costs.byOutcome() / costs.by_outcome() reads unit economics back: completed, failed, and unresolved units side by side with cost per completed unit
+New GET /attribution-data/by-outcome and GET /attribution-data/sessions/{sessionId}/tree back the outcome and call-tree reads
Improvements
*Span context is async-local per client instance, so parallel branches never cross-wire and two clients in one process stay isolated
*Context is captured at call time, so a response that settles after its span exits still attributes to the span that issued it
*cost_per_completed_unit is null when nothing completed, never zero as a fallback, so an empty period is distinguishable from a free one
*A failing outcome rethrows your original error unchanged, and the cost already spent stays attributed
Node 0.10.0 / Python 0.8.0a1
Automatic tracking for provider clients
New Features
+wrap(): wrap an OpenAI or Anthropic client once and every call through it is tracked automatically, with no per-call tracking code
+Streaming is supported through wrapped clients. Iterate the chunks as normal and usage is recorded on consumption
+First-class session and span fields on track(): sessionId, sessionType, spanId, parentSpanId in Node, and session_id, session_type, span_id, parent_span_id in Python. They are sent as top-level wire fields rather than by metadata convention
+Auto-detection for OpenAI Embeddings and Responses API payloads, so those calls record real models and token counts instead of unknown
Improvements
*A wrapped client is transparent: identical arguments, untouched responses, and provider errors that pass through unmodified. Tracking failures are routed to your onError callback and never mask a provider error
*Session and span fields are validated at the call site, because a server-side rejection would otherwise drop the event silently during a background flush
*Wrapping an already-wrapped client is a no-op, and an unrecognized client shape throws an error listing what is supported
MCP Server 0.1.0 / CLI 0.1.0
MCP server and command-line interface
New Features
+@bearlumen/mcp-server exposes 15 read-only tools across costs, margins, insights, usage, and attribution, over stdio for any MCP client including Claude Desktop, Cursor, and Claude Code
+@bearlumen/cli brings the same surface to the terminal as the bearlumen command, with human-readable tables by default and --json for piping into tools like jq
+Both authenticate with the BEAR_LUMEN_API_KEY environment variable, with BEAR_LUMEN_BASE_URL to point at a non-production host
+The MCP server ships SKILL.md, an agent-facing reference for each tool, the date conventions, and common workflows
Improvements
*The command surface is one-to-one with the MCP tool surface, so a script and an agent see identical data
*Both are thin read-only wrappers over @bearlumen/node-sdk, inheriting its request signing and response parsing so they stay in lockstep with the public API
Node 0.9.0
The Node SDK is now isomorphic
Breaking Changes
!Minimum Node.js version is now 20. Request signing and event ID generation moved from node:crypto to WebCrypto, which Node exposes globally from version 19. Node 18 reached end of life in April 2025
New Features
+The SDK now bundles cleanly for browsers and edge runtimes including Cloudflare Workers, Deno, and Bun, in addition to Node
Improvements
*HMAC request signing is byte-identical to previous versions, verified against the backend canonical test vectors
Node 0.8.0 / Python 0.7.0a1
The environment option is removed
Breaking Changes
!The environment config option is gone from both SDKs. Production is the default. To point an SDK at a non-default API, set baseUrl (Node) or base_url (Python) explicitly, keeping the /v1 suffix. Remove any environment argument when upgrading
Node 0.7.0 / Python 0.6.0a1
snake_case response bodies, and the Python SDK on PyPI
Breaking Changes
!Response fields are snake_case in both SDKs, returned exactly as the API sends them with no client-side casing transform. Read result.total_cost rather than result.totalCost, point.period_start rather than point.periodStart, and so on across cost, margin, insights, dimension, attribution, and usage responses
!The usage-event ingestion contract was renamed: sdk_event_id is now idempotency_key, the wire field cost is now cost_override, and the flat experiment_id and variant pair is now a single nested experiment object with both fields required when present
New Features
+First PyPI release of the bearlumen package, with sync and async clients at parity
Improvements
*Client-synthesized types stay camelCase in Node by design: config, track options, query parameters, and the error envelope
*The costOverride input option keeps its camelCase spelling. Only the wire field name changed
*A contract test in each SDK fails the build if a camelCase field ever leaks onto the wire
API 2025-10-18
Public API and official SDKs
New Features
+Stable REST API under /v1 (dated version 2025-10-18)
+Cost, margin, usage, attribution, insights, and dimension endpoints