record()
Signature and every parameter of capsera.record(), for logging spend from an LLM client the SDK does not patch.
record() writes a usage event for a call the SDK did not intercept: a
proprietary wrapper, a raw HTTP request, or a provider with no patch yet.
See Manual record for when this is the right tool and what it cannot know.
record()
capsera.record(
*,
input_tokens: int,
output_tokens: int,
model: str,
provider: str,
cost_usd: float | None = None,
agent_id: str | None = None,
task_type: str | None = None,
session_id: str | None = None,
customer_id: str | None = None,
cost_center: str | None = None,
cache_read_tokens: int = 0,
cache_write_tokens: int = 0,
latency_ms: int = 0,
gateway: str | None = None,
) -> None
Every argument is keyword-only. Returns None.
Required
| Parameter | Notes |
|---|---|
input_tokens | Prompt tokens consumed. |
output_tokens | Completion tokens generated. |
model | The provider's own model identifier, such as claude-sonnet-4-6. Pricing lookup depends on it. |
provider | "anthropic", "openai", "google", and so on. |
Cost
| Parameter | Default | Notes |
|---|---|---|
cost_usd | None | Pass the exact figure if you have it. Left unset, cost is computed from the built-in pricing catalogue in decimal arithmetic. |
A model the catalogue does not recognise does not fail the call: lookup falls
back to a generic estimate and logs a warning, so a typo in model becomes a
plausible-looking but wrong cost rather than a crash. Watch the log the first
time you record a new model. See Cost and
pricing.
Attribution
| Parameter | Notes |
|---|---|
agent_id | Overrides the enclosing scope. Falls back to the scope, then init(agent_name=…), then "unknown". |
task_type | Overrides the enclosing scope. |
customer_id | Overrides the enclosing scope. |
cost_center | Overrides the enclosing scope. |
session_id | Overrides the scope, which overrides the ambient set_session() value. |
There is deliberately no team_id or env parameter. team_id comes from the
enclosing scope, env from init().
Optional metadata
| Parameter | Default | Notes |
|---|---|---|
cache_read_tokens | 0 | Prompt-cache reads, priced at the cache rate. |
cache_write_tokens | 0 | Prompt-cache writes. |
latency_ms | 0 | End-to-end latency. |
gateway | None | The gateway the call rode through. Falls back to init(gateway=…). Added in 0.4.0. |
capsera.record(
input_tokens=1_200,
output_tokens=340,
model="claude-sonnet-4-6",
provider="anthropic",
agent_id="legacy_pipeline",
latency_ms=880,
)
Before init()
record() called before init() logs a warning and drops the event. There is no
queue to hold it and no configuration to attribute it with, so it cannot be
buffered — call init() at startup, not lazily on first use.
What it does not do
record() is a write. It does not consult budgets, so a blocking budget cannot
stop a call you record yourself, and it does not route, since the call has
already happened. Enforcement only exists on the intercepted path.