Metrics and cost
Both are instruments, not numbers we ask you to take on faith.
In-process counters
# per-route latency percentiles over this process's recent requests
curl -H "Authorization: Bearer $SODAMEM_API_KEY" localhost:8000/v1/metrics
# cumulative LLM token spend, split by ingest vs answer
curl -H "Authorization: Bearer $SODAMEM_API_KEY" localhost:8000/v1/usageBoth are in-process and reset on restart. They are counters for "what is this deployment doing right now", not a billing record.
/v1/metrics returns a routes map of {count, min, …, max} per route. /v1/usage returns by_operation and a total.
Prometheus
For anything that has to outlive a restart, scrape instead:
curl -H "Authorization: Bearer $SODAMEM_API_KEY" localhost:8000/metricsIt exposes request counts (a true monotonic counter, not the latency ring), duration quantiles in seconds, and cumulative LLM tokens per operation. It sits behind the same API key as everything else, so a scrape config needs a bearer_token:
scrape_configs:
- job_name: sodamem
authorization:
type: Bearer
credentials: <SODAMEM_API_KEY>
static_configs:
- targets: ['sodamem:8000']Routes with no traffic are absent rather than reported as zero, because a zero reads as "this is instantaneous" or "this is free".
Why there is no OpenTelemetry exporter
OTel earns its cost on distributed tracing. This is one process. Scraping covers the actual need at zero added dependencies.
Why we publish no headline latency number
It depends on hardware, store size, embedder and concurrency to a degree that makes a single figure close to meaningless. Measure it on your own deployment with /v1/metrics.
Reading cost
/v1/usage splits ingest from answer deliberately:
- ingest is output-token heavy — extraction writes facts
- answer is input-heavy — the planner reads retrieved evidence
A single total hides the only comparison worth making. And the cheap retrieval tier contributes nothing to either number, because it makes no model call at all — see Retrieval tiers.
Maintenance costs tokens too
Entity profiles are rebuilt on demand, never on a timer — SodaMem ships no scheduler, because when to spend those tokens is a deployment decision:
curl -X POST localhost:8000/v1/maintenance/dream \
-H "Authorization: Bearer $SODAMEM_API_KEY" -H "Content-Type: application/json" \
-d '{"user_id":"u1","async_mode":true}'Idempotent, resumable, and safe to overlap: a second call while one is running returns status:"already_running" and does nothing. The response carries remaining_stale, so a cron entry that just runs every hour converges without anyone having to pick a batch size.

