Start with install notes or jump straight into the API.

API

Snapshots

Snapshots are materialized facet histograms for a namespace. They carry facet listings in values[].v and facet counts in values[].n, stored durably in S3 and mirrored into Aerospike for the latest body.

Use POST /snapshots to materialize a field now. Use history and body routes to read the durable chronology written by the consistency watcher.

Routes

RouteMethodBehavior
POST /v2/namespaces/{ns}/snapshotsPOSTCreate an on-demand snapshot job for one field.
GET /v2/namespaces/{ns}/snapshot-jobsGETList in-memory snapshot jobs.
GET /v2/namespaces/{ns}/snapshot-jobs/{id}GETRead one snapshot job.
GET /v2/namespaces/{ns}/historyGETNewest-first durable snapshot history.
GET /v2/namespaces/{ns}/snapshots/{sha}GETFull snapshot body by full SHA or 7-char prefix.
GET /v2/activity/snapshotsGETCross-namespace snapshot-write activity stream.

Create a snapshot job

POST /v2/namespaces/products/snapshots
Content-Type: application/json

{
  "field": "category",
  "source": "auto",
  "filters": ["brand", "Eq", "Acme"],
  "page_size": 1000
}

Valid sources are auto, stored, cache, and origin.

SourceReads fromNotes
autoStored snapshot when possible, otherwise cache/origin policyDefault. Stored snapshots only support unfiltered configured fields.
storedLatest S3 snapshot body, with Aerospike mirror as a cacheFastest path for configured facet fields.
cacheAerospike document cacheSupports filters the cache can evaluate.
originTurbopuffer paginated scanAuthoritative. Persists the computed snapshot body to S3.

The response is 202 Accepted:

{
  "id": "snapshot-job-uuid",
  "namespace": "products",
  "field": "category",
  "source": "auto",
  "status": "running",
  "progress": 0,
  "documents_scanned": 0,
  "created_at": "2026-05-26T10:00:00Z"
}

Poll the job:

GET /v2/namespaces/products/snapshot-jobs/snapshot-job-uuid

Completed jobs include sha when a body was materialized:

{
  "id": "snapshot-job-uuid",
  "namespace": "products",
  "field": "category",
  "source": "origin",
  "status": "completed",
  "documents_scanned": 12844,
  "sha": "3f9e8b21",
  "stable_as_of": 1747300000123
}

History

GET /v2/namespaces/products/history?limit=20
[
  {"watermark_ms": 1747300000123, "sha": "3f9e8b21..."},
  {"watermark_ms": 1747299600045, "sha": "a1c5b09f..."}
]
Query paramDefaultPurpose
limit50Maximum entries returned. Capped at 500.
beforenoneReturn entries older than this SHA. 7-char prefixes are accepted.

The history endpoint lists S3 keys only; it does not read every snapshot body.

Snapshot body

GET /v2/namespaces/products/snapshots/3f9e8b2
{
  "namespace": "products",
  "watermark_ms": 1747300000123,
  "sha": "3f9e8b21",
  "fields": [
    {
      "name": "category",
      "values": [
        {"v": "books", "n": 1240},
        {"v": "electronics", "n": 873}
      ]
    }
  ],
  "fields_skipped": [
    {
      "name": "tags",
      "reason": "exceeded_cap",
      "distinct_observed": 247000,
      "cap": 10000
    }
  ]
}

fields[].values[].v is the facet listing. fields[].values[].n is the facet count. Fields present in fields[] are complete. Fields above the 10,000 distinct-value cap are listed in fields_skipped[] instead of being partially materialized.

Activity

GET /v2/activity/snapshots?since=1747200000000&limit=50
Query paramRequiredPurpose
sinceyesEpoch-ms lower bound on ts_ms.
limitnoCap 500, default 50.
namespacenoExact namespace filter.
cursornoPagination cursor from next_cursor.

Activity is snapshot lifecycle only. Search history and clickstream events have separate feeds.