State reads
The low-latency read surface — five endpoints, all served from the state and ledger stores (never a database query per request):
| Endpoint | Returns |
|---|---|
GET /slots/{slot}/entities/{type}/{id}/state | one entity's embedding + scores + freshness |
POST /slots/{slot}/scores:batch | up to 1,000 entities in one call |
GET /entities/{type}/{id}/events | the entity's event timeline (newest first, cursor-paginated) |
GET /entities?type=…&id_prefix=… | entity lookup with first/last-seen and event counts |
GET /entities/presence?type=…&id_prefix=… | entity lookup over recorded history and current scores |
The quickstart's final step is a worked state read with output.
The freshness contract
Every scored response carries a freshness object — all four fields,
always:
{
"freshness": {
"event_cursor": { "timestamp": "2025-04-25T13:46:00Z", "event_id": "ord-000009" },
"computed_at": "2026-07-08T21:46:58Z",
"bundle_id": "bnd_01kx1v5gd74hxnrg7pfxv7jdcx",
"model_fingerprint": "5320b447…"
}
}
In Phase 1 states are batch-refreshed, so freshness is what makes staleness
visible and honest: event_cursor is the last event this state
incorporates; computed_at is when it was written; bundle_id and
model_fingerprint identify exactly which model produced it. Alert on
event_cursor age, not on hope.
Batch reads
scores:batch takes up to 1,000 entity ids and answers from one batched
storage read. Per-entity misses come back as typed not_found entries in
position — a missing entity never fails the batch. Use include to
select embedding, scores, or both; embedding_encoding=base64 returns
the raw float32 bytes when JSON float arrays are too heavy.
Timelines and lookup
Timelines serve the raw canonical events (plus received_at and
source_id envelope fields only) — useful for debugging "why does this
user score this way" by looking at exactly what the model saw. Lookup
(GET /entities) finds ids by exact match or prefix with first/last-seen
timestamps and event counts.
Entities ingested in batch can have current scores without a recorded
lifetime summary. GET /entities/presence takes the same type plus id
or id_prefix and returns every entity that has a lifetime summary, current
scores in a deployment slot, or both: each item carries the optional
summary and the served_slots that hold its scores, in the same id order.
Without a summary, first/last-seen and event counts are unknown, not zero.
An empty data page means the id has neither.
All reads are metered as state_reads and rate-limited per key
(X-RateLimit-* headers on every response).