Skip to content

Getting Started

This walks you from a built binary to your first time-travel query in about ten minutes.

1. Run the server

# Create a data directory and an API key (prints the plaintext key ONCE)
telha api-key create --tenant <tenant-uuid> --org <org-uuid> --data-dir ./data

# Start serving
telha serve --data-dir ./data --rest-addr 127.0.0.1:8080

Notes:

  • On Windows dev machines the release binary currently needs C:\msys64\mingw64\bin on PATH (packaging work in PR-084 removes this).
  • Configuration layers: defaults, then telha.toml, then TELHA_* environment variables (double underscore nests sections: TELHA_GRPC__TOKEN_KEY=...), then flags.
  • To enable gRPC and MCP, set grpc.token_key to a 64-hex secret. Gotcha: the value must contain at least one letter (an all-digit value is parsed as an integer by the config layer).
  • Health probes: GET /healthz (liveness) and GET /readyz (readiness).

2. Write your first records

Everything is authenticated with the x-api-key header. Create a record with a validity interval and a relationship in one call:

curl -s -X POST http://127.0.0.1:8080/v1/records \
  -H "x-api-key: $TELHA_API_KEY" -H "content-type: application/json" \
  -d '{
    "records": [{
      "label": "CONTRACT_VERSION",
      "properties": { "number": "C-1042", "clause": "Net 30", "riskScore": 2 },
      "validTime": { "start": "2026-01-01T00:00:00Z" }
    }]
  }'

The response returns the record's logical id. Update it later with new properties: Telha appends a new version and closes the old one's transaction time. Nothing is edited in place.

3. Read it back, three ways

# Current state
curl -s http://127.0.0.1:8080/v1/records/<id> -H "x-api-key: $KEY"

# Full version history (paginated)
curl -s http://127.0.0.1:8080/v1/records/<id>/history -H "x-api-key: $KEY"

# Query with time travel: what did we BELIEVE on Feb 1 about what was TRUE on Jan 15?
curl -s -X POST http://127.0.0.1:8080/v1/query \
  -H "x-api-key: $KEY" -H "content-type: application/json" \
  -d '{
    "find": "CONTRACT_VERSION",
    "where": { "number": { "$eq": "C-1042" } },
    "atValidTime": "2026-01-15T00:00:00Z",
    "atTxTime":    "2026-02-01T00:00:00Z"
  }'

That last call is the heart of the product: two independent time axes. atValidTime asks about the world; atTxTime asks about what Telha knew at that moment. Corrections made after Feb 1 are invisible to it, exactly as an auditor would require.

4. Ingest a document

curl -s -X POST http://127.0.0.1:8080/v1/ingest \
  -H "x-api-key: $KEY" -H "content-type: application/json" \
  -d '{ "name": "supplier-review.pdf", "format": "docling", "contentBase64": "<...>" }'
# → { "jobId": "...", "status": "queued" }   poll GET /v1/ingest/<jobId>

Formats: docling (PDF/DOCX/PPTX), tabular (CSV/XLSX), web (URL crawl), email (.eml/.msg), code, and json (structured records, applied synchronously with no worker round-trip). Document formats need at least one Python worker running: python -m workers_common.run docling_worker pointed at the server's gRPC address with a worker token (telha api-key worker-token --worker-id w1).

5. Use an SDK instead

import { TelhaClient } from "@telha/sdk";
const telha = new TelhaClient({ url: "http://127.0.0.1:8080", apiKey: process.env.TELHA_API_KEY });
const rows = await telha.query({ find: "CONTRACT_VERSION", where: { number: { $eq: "C-1042" } } });
from telha import TelhaClient
t = TelhaClient(url="http://127.0.0.1:8080", api_key=os.environ["TELHA_API_KEY"])
rows = t.query(find="CONTRACT_VERSION", where={"number": {"$eq": "C-1042"}})

Where to go next