# Bulk export — the archive and its records as datasets

**Since:** 2026-10-31. **Code:** `lib/archive/export.ts`. **Routes:** `GET /api/v1/archive/export?record=&day=[&after=][&limit=]` (NDJSON), `GET /api/v1/archive/export/manifest` (JSON). **Page:** `/data` (schema.org `DataCatalog` of the same records). **Access:** an identified caller — API key or session (`lib/auth/public-api.ts`) — one quota call per page.

## Why

The record's value to an integrator — a Foundry data connection, a reinsurer's data team, a researcher — is as a dataset they can load beside their own with provenance intact. The per-row endpoints answer one question each. This answers "everything the archive holds for that feed on that day", in the form every data tool reads, with the table's own columns, nothing renamed and nothing dropped.

## Records

| `record` | Table | Day column | Doc |
|---|---|---|---|
| `as-issued-products` | `as_issued_products` | `received_at` | `docs/as-issued-archive.md` |
| `as-issued-polls` | `as_issued_polls` | `fetched_at` | `docs/as-issued-archive.md` |
| `warning-exposures` | `warning_exposures` | `received_at` | `docs/warning-exposure.md` |
| `footprint-exposures` | `footprint_exposures` | `received_at` | `docs/footprint-exposure.md` |
| `reference-evaluations` | `reference_evaluations` | `received_at` | `docs/reference-determinations.md` |
| `reference-determinations` | `reference_determinations` | `received_at` | `docs/reference-determinations.md` |
| `event-outcomes` | `event_outcomes` | `computed_at` | `docs/event-outcomes.md` |
| `observed-footprints` | `observed_footprints` | `ingested_at` | `docs/event-outcomes.md` |
| `source-health-events` | `source_health_events` | `recorded_at` | `docs/source-availability.md` |
| `digests` | `determination_log_digests` | `period_start` | `docs/digest-anchoring.md` |

## Paging

Pages are ordered by the primary key and continued with `after=<the X-Next-After header>`. A page ends at `limit` rows (default 200, at most 500) or at 3 MB of NDJSON, whichever comes first — Vercel caps a function's response body at 4.5 MB and an NHC bundle row alone can be a megabyte — and always carries at least one row, so a client never spins on an empty page. The records are append-only or keyed by id, so a cursor is stable under appends. Headers: `X-Record`, `X-Rows`, `X-Next-After` (absent on the last page), and the quota headers.

```
curl -H "Authorization: Bearer cs_live_…" \
  "https://calchis.com/api/v1/archive/export?record=warning-exposures&day=2026-10-30" > warning-exposures-2026-10-30.ndjson
```

A full day of the archive bodies is several pages; a loader walks `X-Next-After` until it is absent.

## What it is not

Nothing exported here is backfilled: the as-issued records begin 2026-10-28, and the historical tables (IBTrACS, Storm Events, NFIP, declarations, the NHC advisory archive) are separate and are not served by this surface. The export is read-only and carries the same columns the public per-row endpoints do; the difference is the shape and the key, not the data.
