"use client"; import Link from "next/link"; import { ExternalLink } from "lucide-react"; import { Banner, Card, PageHeader } from "@/components/ui"; const BAR_COLUMNS: [string, string, string][] = [ ["instrument_id", "string", "Stable id, e.g. firstrate:stock:AAPL"], ["symbol_as_reported", "string", "Ticker as delivered by the vendor at that date"], ["venue", "string?", "Exchange / venue when known"], ["asset_class", "string", "stock, etf, index, crypto, fx, futures"], ["interval", "string", "1m, 5m, 1d"], ["timestamp_utc", "timestamp[us, UTC]", "Bar OPEN instant, UTC"], ["session_date", "date", "US trading session (America/New_York)"], ["open / high / low / close", "float64", "Raw (as traded) prices"], ["volume", "float64", "Shares/contracts; zero-volume bars are absent"], ["currency", "string", "ISO 4217 (USD)"], ["trade_count", "int32?", "When supplied by the vendor"], ["vwap", "float64?", "When supplied by the vendor"], ["adjustment_type", "string", "Always raw in storage"], ["source_id", "string", "Source / product that produced the row"], ["ingested_at", "timestamp[us, UTC]", "Load instant"], ["quality_flags", "list", "e.g. ohlc_inconsistent, price_jump, outside_session"], ["revision_id", "int32", "Increments when the vendor re-delivers a bar"], ]; export default function DocsPage() { return ( <> Swagger UI OpenAPI JSON } />

FinData OS is a private, research-grade financial data lakehouse. It ingests vendor files (FirstRate Data intraday bars, corporate actions and fundamentals; SEC EDGAR when configured) into an immutable Parquet lake with a Postgres catalog, versions every dataset, checks quality at load time, and serves the result through one HTTP API that this console, the Python SDK and ad-hoc SQL all share. One writer (the ingest worker) owns the lake; the API is read-only except for job control, keys and settings.

  • Curated layer: Parquet files per dataset, base files plus delta appends, compacted into new versions.
  • Raw layer: vendor archives kept for re-processing (hash-verified).
  • Catalog: datasets, versions, files, coverage per (symbol, session), instruments, corporate actions, jobs, exports, audit.
Timestamp convention
Every bar is stamped at its open: the 1-minute bar labelled 13:30:00Z covers 13:30:00 → 13:30:59.999 UTC.
Storage timezone
timestamp_utc is UTC. session_date is the US trading session in America/New_York; it is the key for coverage and expected-bar counts.
Session span
Bars are retained for the extended session 04:00 – 20:00 ET; regular hours are 09:30 – 16:00 ET. Completeness = bars ÷ expected regular-hours bars, capped at 100 %.
Zero-volume bars
Minutes without a trade are absent, not stored as zero rows. A gap is not necessarily a vendor outage — check the coverage page.
Adjustments
Stored prices are raw. split and split_div are computed at query time from the corporate-actions table (ex-date based, backward factor), so a new split re-adjusts history without rewriting files. The API echoes adjustment_notes explaining what was applied.
Versioning
Each dataset has a current_version with a snapshot id. Exports pin the version at submission; GET /market/bars?version= can read an earlier one.
Quality flags
Rows are never silently dropped; suspicious bars carry quality_flags and are also recorded as anomalies.
{BAR_COLUMNS.map(([c, t, m]) => ( ))}
Column Arrow type Meaning
{c} {t} {m}

The authoritative schema is served by GET /api/v1/catalog/schema/bars. In the SQL playground each dataset is a DuckDB view named after its id with dots replaced by underscores, e.g. market_bars_stock_1m_raw.

  • raw — prices as traded; volumes as reported. Use for microstructure work and when you join your own actions.
  • split — prices divided and volumes multiplied by the cumulative split factor of all splits with ex-date after the bar.
  • split_div — additionally applies the cash-dividend backward factor (1 − D / Pclose, prev). Total-return style; not suitable for tick-size studies.

Every fact carries available_at (= filing date + 1 day 00:00 America/New_York, a conservative knowability instant) and observed_at (when this platform first saw the value). A request with as_of returns only facts with available_at ≤ as_of; among revisions, the first observed value is used unless a later revision was observed before as_of. The response counts facts_hidden_by_as_of so you can tell how much of the record you are not seeing.

FirstRate Data — private use only, no redistribution.
  • Raw bars, exports, SQL results and tables derived row-for-row from them may be used by the subscriber only. They may not be published, shared, re-hosted or served through a public API.
  • Aggregated results (charts, statistics, model outputs) may be published with attribution to FirstRate Data.
  • SEC EDGAR content is U.S. public domain; the SEC fair-access policy (declared User-Agent, request rate) applies to retrieval.
  • API keys are personal. Every download, export and query is written to the audit log with the principal and request id.

All endpoints live under /api/v1. Authenticate with the console session (cookie + X-CSRF-Token on writes) or with an API key: Authorization: Bearer fd_…. Errors are JSON: {`{"error":{"code","message","request_id"}}`}.

{`export FINDATA_URL="https://findata.spboucher.ai"
export FINDATA_API_KEY="fd_xxx.yyy"

# health + catalog
curl -s -H "Authorization: Bearer $FINDATA_API_KEY" "$FINDATA_URL/api/v1/health" | jq .status
curl -s -H "Authorization: Bearer $FINDATA_API_KEY" "$FINDATA_URL/api/v1/catalog/datasets" | jq '.data[].id'

# one week of 1-minute bars, split-adjusted, as CSV (≤ 31 days per call for 1m)
curl -s -H "Authorization: Bearer $FINDATA_API_KEY" \\
  "$FINDATA_URL/api/v1/market/bars?symbol=AAPL&interval=1m&start=2026-10-20&end=2026-10-24&adjustment=split&format=csv&limit=10000" -o aapl.csv

# bigger ranges: async export → poll → download
curl -s -X POST -H "Authorization: Bearer $FINDATA_API_KEY" -H "Content-Type: application/json" \\
  -d '{"dataset_id":"market_bars.stock.1m.raw","symbols":["AAPL","MSFT"],"start":"2024-01-01","end":"2026-10-30","format":"parquet"}' \\
  "$FINDATA_URL/api/v1/exports"
# → {"id":"…","status":"queued","poll":"/api/v1/exports/…"}; when status=ready: GET /api/v1/exports/{id}/download

# point-in-time fundamentals
curl -s -H "Authorization: Bearer $FINDATA_API_KEY" \\
  "$FINDATA_URL/api/v1/fundamentals/AAPL?as_of=2025-01-01T00:00:00Z&metrics=rev,net_inc&period_type=q"

# read-only SQL (DuckDB)
curl -s -X POST -H "Authorization: Bearer $FINDATA_API_KEY" -H "Content-Type: application/json" \\
  -d '{"sql":"SELECT session_date, sum(volume) v FROM market_bars_stock_1m_raw WHERE symbol_as_reported='"'"'AAPL'"'"' GROUP BY 1 ORDER BY 1 DESC LIMIT 5","max_rows":100}' \\
  "$FINDATA_URL/api/v1/query"`}

Install from the repo (packages/python-sdk): pip install -e packages/python-sdk. The client pages through Arrow IPC automatically.

{`from findata_sdk import FinData

fd = FinData("https://findata.spboucher.ai", api_key="fd_xxx.yyy")   # or FINDATA_URL / FINDATA_API_KEY env vars

bars = fd.bars("AAPL", "1m", "2026-10-26", "2026-10-30", adjustment="split")   # pyarrow.Table, all pages
df = bars.to_pandas()                                                           # or .to_polars()

path = fd.export(["AAPL", "MSFT"], "2024-01-01", "2026-10-30", format="parquet")  # waits, downloads, returns local path

facts = fd.fundamentals("AAPL", as_of="2025-01-01T00:00:00Z", metrics=["rev", "net_inc"])
print(fd.datasets()[0]["id"], fd.health()["status"])`}
  • GET /market/bars: span ≤ 31 days for 1m, 186 days for 5m, 3 660 days for 1d; ≤ 10 000 rows per page (cursor pagination). HTTP 413 range_too_large otherwise → use{" "} Exports .
  • Exports: ≤ 500 symbols, ≤ 12 years, 3 concurrent per principal, files expire after ~72 h.
  • SQL: one read-only statement, server-side timeout, ≤ 100 000 rows; the console displays at most 1 000 rows (download the CSV for the rest).
  • Rate limit per key/session (default 600 requests/min, HTTP 429 with Retry-After).
  • Fundamentals revision history starts at first ingestion. Values observed before the platform existed are a single revision (proxy for “as originally filed”); true as-filed history for older periods is not reconstructed.
  • SEC EDGAR is “pending configuration” until a fair-access User-Agent is set on the server (SEC_EDGAR_USER_AGENT). Until then the dataset is listed but empty.
  • Unsupported: tick data, quotes/NBBO, order-book depth, options chains. Those datasets appear as unsupported in the catalog on purpose so nobody plans on them.
  • Vendor files arrive with a lag (typically next day); the overview shows vendor lag and days since last session per dataset.
  • The console is a static bundle served by the API; it needs JavaScript and a modern browser. No telemetry, no third-party assets.
); }