Read API

All read endpoints live under /api/v1 and require a Bearer token with at least the read scope.

Authorization: Bearer <api-key>

Entity history

GET /api/v1/collections/{collection}/entities/{entityId}/history

Returns a paginated list of events for an entity, newest-first by default.

Query parameters

Parameter Type Default Description
from RFC3339 Return events received at or after this time
to RFC3339 Return events received before or at this time
author_id string Filter to events from this author
op string Filter by operation: create, update, or delete
path string Filter to events that touch this field path
source string Filter by source system identifier
limit integer 100 Page size (1–1,000)
cursor string Opaque pagination token from a previous next_cursor
order_by string version Sort key: version, ts_source, or ts_received
order string desc asc or desc
format string native Diff format: native or json-patch (RFC 6902)

Response (200):

{
  "entity_id": "deal-1",
  "next_cursor": "eyJ2IjoxMH0=",
  "events": [
    {
      "version": 4,
      "op": "update",
      "ts_received": "2026-06-02T09:00:01Z",
      "ts_stored":   "2026-06-02T09:00:01Z",
      "ts_source":   "2026-06-02T09:00:00Z",
      "author_id":   "user-42",
      "source":      "crm-backend",
      "integrity": {
        "hash":      "sha256:9f86d0...",
        "prev_hash": "sha256:2c2640..."
      },
      "changes": [
        {"path": "amount", "op": "change", "old": 5000, "new": 7500},
        {"path": "stage",  "op": "change", "old": "prospect", "new": "qualified"}
      ]
    }
  ]
}

The integrity field is present only when the hash_chain plugin is enabled for the collection.

Pagination: Pass the next_cursor value as the cursor parameter. When next_cursor is null, you have reached the last page.


Current state

GET /api/v1/collections/{collection}/entities/{entityId}/state

Returns the entity’s current materialized state.

Response (200):

{
  "entity_id": "deal-1",
  "version": 4,
  "ts": "2026-06-02T09:00:01Z",
  "deleted": false,
  "state": {
    "title": "Acme Corp",
    "amount": 7500,
    "stage": "qualified"
  }
}

Returns 404 if the entity has never been written (or has been purged).


Point-in-time state

GET /api/v1/collections/{collection}/entities/{entityId}/state?version=3
GET /api/v1/collections/{collection}/entities/{entityId}/state?ts=2026-05-01T00:00:00Z

Reconstruct the entity’s state at a specific version or timestamp. Letopis uses the nearest snapshot plus a tail replay.

Parameter Type Description
version integer Reconstruct state at this exact version
ts RFC3339 Reconstruct state at the latest version received before or at this time

Verify hash chain

GET /api/v1/collections/{collection}/entities/{entityId}/verify

Verifies the SHA-256 hash chain for the entity (requires hash_chain plugin to be enabled for the collection). Returns the first divergence if any, or {"ok": true} if the chain is intact.


List collections

GET /api/v1/collections

Returns a list of collections in the tenant’s database, with config and stats.


List entities in a collection

GET /api/v1/collections/{collection}/entities

Returns a paginated list of entity IDs in the collection.

Query parameters: limit (default 100, max 1,000), cursor, order_by (entity_id or ts), order (asc or desc).


Business flows

GET /api/v1/flows/{flowId}

Returns the full causal DAG for a business flow: all activities and their caused_by links. Activities are sorted topologically.

{
  "flow_id": "flow-deal-onboarding",
  "activities": [
    {
      "activity_id": "act-111",
      "collection": "crm.deals",
      "entity_id": "deal-1",
      "version": 2,
      "step": "qualification",
      "caused_by": []
    },
    {
      "activity_id": "act-222",
      "collection": "crm.tasks",
      "entity_id": "task-99",
      "version": 1,
      "step": "follow-up",
      "caused_by": [{"activity_id": "act-111"}]
    }
  ]
}

Dead-letter queue

GET /api/v1/dlq

Returns failed webhook deliveries. Each entry includes the original event, the target URL, the last error, and the retry count. Entries can be replayed or deleted via the Admin API.