Skip to main content

Snapshot API

The Snapshot API lets you query the current state of any join or window via a simple HTTP GET request. It solves the “cold start” problem: when a dashboard loads, it can fetch a snapshot of current results immediately instead of waiting for the next SSE event.

Endpoint

GET /snapshot
Available on any SSE sink’s HTTP server (the same address as /subscribe).

Query Parameters

ParamRequiredDefaultDescription
joinyesJoin or window name, or * for all.
fromnoStart time (RFC 3339 or Unix seconds).
tononowEnd time (RFC 3339 or Unix seconds).
limitno10000Max rows per join/window.
keysnoComma-separated key filter.

Examples

Fetch all results

curl http://localhost:9100/snapshot?join=* | jq

Fetch a specific join

curl http://localhost:9100/snapshot?join=order-user-join | jq

Filter by keys

curl "http://localhost:9100/snapshot?join=order-user-join&keys=order_123,order_456" | jq

Time-range query

curl "http://localhost:9100/snapshot?join=order-user-join&from=2026-02-22T00:00:00Z" | jq

Response Format

The response is a JSON array of JoinResult objects — identical to SSE event payloads:
[
  {
    "query": "order-user-join",
    "key": "order_123",
    "rows": [
      {
        "order_id": "order_123",
        "amount": 45.00,
        "customer_name": "Alice"
      }
    ],
    "emit_at": "2026-02-22T10:00:00Z"
  }
]

Status Codes

CodeMeaning
200Success (may be an empty array)
400Invalid parameters
500Query execution failed
503Storage not ready (engine initializing)

Frontend Integration

Snapshot + SSE Pattern

The recommended pattern is to fetch a snapshot for initial state, then open an SSE stream for live updates:
async function connect() {
  const baseUrl = 'http://localhost:9100';

  // Hydrate current state
  try {
    const res = await fetch(`${baseUrl}/snapshot?join=*`);
    const results = await res.json();
    for (const result of results) {
      handleJoinResult(result);
    }
  } catch (e) {
    console.warn('Snapshot failed, will populate from SSE:', e);
  }

  // Then open SSE for live updates
  const es = new EventSource(`${baseUrl}/subscribe?join=*`);
  es.addEventListener('join_result', (event) => {
    handleJoinResult(JSON.parse(event.data));
  });
}

Replay Alternative

Instead of a separate fetch, add ?replay=true to the SSE URL:
const es = new EventSource('http://localhost:9100/subscribe?join=*&replay=true');
With replay, the server emits current results as SSE events (with "_replay": true) before switching to live streaming. The replay_complete event signals when initial hydration is done:
event: join_result
data: {"query":"...", "_replay": true, ...}

event: replay_complete
data: {"join":"*","count":42}

event: join_result
data: {"query":"...", ...}   ← live from here

Archive Queries

When the from parameter extends beyond the retention window (data has been compacted to Parquet), the snapshot handler automatically queries the archive federator if tiered storage is enabled. This means a single /snapshot request can transparently query data across:
  • Hot SQLite (recent data)
  • Warm local Parquet files (days old)
  • Cold cloud Parquet files (weeks/months old)

Configuration

The snapshot endpoint is enabled by default on any SSE sink. Optional tuning:
sinks:
  - name: dashboard
    type: sse
    config:
      addr: ":9100"
      snapshot:
        enabled: true
        default_limit: 10000
        timeout: 10s
        replay: true