# Integration quickstart — loading and verifying the record

**For:** a data team evaluating Calchis (a Foundry connection, a reinsurer's data group, a researcher). **Time:** about an hour to a first table. **Needs:** a free account and its API key (`/settings/api-keys`), `curl`, Python 3.

Every endpoint below is documented in the OpenAPI file at `/docs/openapi.yaml`; every record's method is a document at `/docs/<name>.md`, listed on `/api-docs` and `/data`.

## 1. See what exists

```bash
curl -s -H "Authorization: Bearer $CALCHIS_KEY" https://calchis.com/api/v1/archive/export/manifest | python3 -m json.tool
```

The manifest names the ten records, with the row count and the first and last timestamp of each. The `record=` values are the keys. Nothing listed is backfilled: the as-issued archive begins 2026-10-28, and the manifest's `first` is the proof.

## 2. Load a day of one record

Pages are ordered by primary key and continued with the `X-Next-After` header; a page ends at 500 rows or 3 MB, whichever first. Walk until the header is absent.

```python
import json, os, sys, urllib.request

BASE = "https://calchis.com/api/v1/archive/export"
KEY = os.environ["CALCHIS_KEY"]

def export(record: str, day: str):
    """Yield every row of `record` received on UTC day `day` (YYYY-MM-DD)."""
    after = None
    while True:
        url = f"{BASE}?record={record}&day={day}&limit=500" + (f"&after={after}" if after else "")
        req = urllib.request.Request(url, headers={"Authorization": f"Bearer {KEY}"})
        with urllib.request.urlopen(req) as r:
            for line in r:
                yield json.loads(line)
            after = r.headers.get("X-Next-After")
        if not after:
            return

rows = list(export("warning-exposures", "2026-11-05"))
print(len(rows), "rows;", "columns:", sorted(rows[0]) if rows else "none")
```

Each line is the table's own columns, nothing renamed. Timestamps are UTC ISO 8601; geometry is GeoJSON where a column carries it. Every page is one call against the daily quota (free 100, Analyst 10,000, Team and Agency 100,000), so a day of the largest record (`as-issued-products`, several pages) fits a free key and a month of everything fits Analyst.

To load a span: loop the day from the manifest's `first` to today. The records are append-only or keyed by id, so re-running a day is idempotent on your side if you upsert by `id`.

## 3. Verify a body against the archive — and against the public ledger

Every row of `as-issued-products` carries `content_hash`, the SHA-256 of the body as received. Anyone holding the body can recompute it:

```python
import hashlib, json

def content_hash(row):
    if row["content_type"] == "json":
        canon = json.dumps(row["content"], sort_keys=True, separators=(",", ":"), ensure_ascii=False)
        return hashlib.sha256(canon.encode()).hexdigest()
    return hashlib.sha256(row["content_text"].encode()).hexdigest()

assert content_hash(row) == row["content_hash"]
```

(`JSON.stringify` with keys sorted at every level and no whitespace; `canonicalJson()` in `lib/archive/as-issued.ts` is the reference. Non-ASCII is emitted as the character, not an escape.)

Then ask the archive what it holds for that hash, with no key:

```bash
curl -s https://calchis.com/api/v1/archive/products/<content_hash> | python3 -c 'import json,sys; d=json.load(sys.stdin); print(d["source"], d["received_at"], d["sealed"]["status"])'
```

Or let one script do all of it, from a hash or a body file, against the public endpoints only (no key, no database):

```bash
git clone <this repository> && cd calchis && npm install
node --import tsx scripts/verify-archive-seal.ts <content_hash | path-to-body.json>
```

It recomputes the body's hash, verifies the Merkle inclusion proof against the sealed root with the log's own leaf and node rules, recomputes the anchored statement and message, and prints the block the root was confirmed in — or says `not_sealed` and exits 2 for a body received today.

`sealed` (since 2026-11-06) is the body's place in the daily Merkle digest: `status`, the `entry` (`aip1-<hash>`), the period, the root, the inclusion `proof`, and the root's `anchor` — its independent timestamp through OpenTimestamps, confirmed against a Bitcoin block. A body received today reads `not_sealed` until tomorrow's digest. To check the proof yourself: leaves are SHA-256 over `0x00 || utf8(entry)`, internal nodes SHA-256 over `0x01 || left || right`, an odd node promoted unchanged; the anchor's `.ots` file is served by `/api/v1/determinations/anchors?period=<period_start>&format=ots` and verifies with the reference `ots` tool against any node. What a confirmed anchor proves: the body existed before the block's time. What it does not: that the product was correct, or the minute it arrived.

## 4. Cite a month of the revision record

```bash
curl -s "https://calchis.com/api/v1/verification/revisions/extract?month=2026-10&format=csv" -o revisions-2026-10.csv
sha256sum revisions-2026-10.csv
```

The extract's id is `cre1-` + that SHA-256, sealed into the digest the day it was frozen (the 8th of the following month). The citation line is `calchis-revision-extract/1 <month> revision-record-1 revision-extract-1 <sha256> <rows>`; the JSON form of the same endpoint carries `sealed` with the proof and anchor.

## 5. What to do with it

- **Join to your own events** by `event_id` (outcomes, footprints) or by the warning's `warning_key` (VTEC office.phenomenon.significance.etn.year) across its versions.
- **Price a first-report term** from the revision record: per threshold, the share of first reports within 0.3 that ended on the other side.
- **Audit the platform's listening** from `as-issued-polls` and `/api/v1/archive/continuity?month=`: every read, including the quiet ones; a gap says only that Calchis did not read.

## What this is not

Not a feed of the agencies' current state — that is the agencies'. Not a model: the exposure figures are 2020 Census housing under a polygon, the determinations are a fixed public catalog read on receipt, and the loss figures elsewhere on the platform are modeled and say so. Not backfillable: a day that was not recorded is not in the record, and the continuity endpoint is where that is admitted.
