Public hosted querying
Purpose
TCKDB can be queried as a hosted scientific information system.
Users query by chemistry and scientific constraints. TCKDB returns thermochemistry, kinetics, calculations, geometries, provenance, review state, and stable public refs for follow-up reads.
This guide is the entry point for that public surface. It is deliberately framing-neutral: TCKDB is not an ARC cache, not an RMG helper, and not workflow-tool-specific. Workflow tools and producer adapters are downstream consumers of the same public API documented here.
Companion documents:
- scientific_query_cookbook.md — recipe-style examples.
- workflow_tool_scientific_reads.md — integration patterns for workflow tools.
- internal_ids_visibility_policy.md — policy for integer-ID exposure.
- deployment_modes.md — the three TCKDB deployment modes (local/offline, self-hosted online, hosted/community) and where this public surface fits.
What is publicly queryable
| Surface | Endpoint |
|---|---|
| species search | GET /scientific/species/search |
| reaction search | GET\|POST /scientific/reactions/search |
| thermo search | GET\|POST /scientific/thermo/search |
| kinetics search | GET\|POST /scientific/kinetics/search |
| species-calculation search | GET\|POST /scientific/species-calculations/search |
| geometry detail | GET /scientific/geometries/{geometry_handle} |
| species-entry thermo | GET /scientific/species-entries/{species_entry_handle}/thermo |
| reaction-entry kinetics | GET /scientific/reaction-entries/{reaction_entry_handle}/kinetics |
| reaction-entry full provenance | GET /scientific/reaction-entries/{reaction_entry_handle}/full |
All paths are relative to the deployment's /api/v1 base URL.
API key behavior
- An API key is optional for public scientific reads when the deployment allows anonymous reads.
- An API key is required for uploads, writes, admin, and moderation
endpoints. The Python client raises
TCKDBAuthenticationErrorclient-side before sending if a key is not configured. - If an API key is provided for reads, the client forwards it as the
X-API-Keyheader. Hosted deployments may use authenticated reads for higher quotas, attribution, or per-user analytics.
Anonymous CLI call:
python clients/python/examples/query_cookbook.py \
--base-url http://127.0.0.1:8010/api/v1 \
--smiles "O" \
--recipe thermo
Authenticated CLI call (same recipe, attributed):
python clients/python/examples/query_cookbook.py \
--base-url http://127.0.0.1:8010/api/v1 \
--api-key "$TCKDB_API_KEY" \
--smiles "O" \
--recipe thermo
Public refs and follow-up reads
*_ref fields are the public handles for hosted querying:
spc_...— speciesspe_...— species entry (charge/multiplicity/electronic-state realization)rxn_...— chemical reactionrxe_...— reaction entrygeom_...— geometrycalc_...— calculationlot_...— level of theorythm_...— thermo recordkin_...— kinetics record
Integer *_id fields are internal/debug compatibility fields. They
are hidden by default and must not appear in client code, scripts, or
public examples. See the Internal IDs section below.
Refs chain naturally:
thermo = client.search_thermo(smiles="O", collapse="first")
species_entry_ref = thermo["records"][0]["species"]["species_entry_ref"]
detail = client.get_species_thermo(
species_entry_ref, # ref accepted as the handle
temperature_min=300,
temperature_max=2000,
)
The same pattern works with get_reaction_kinetics(reaction_entry_ref, …),
get_reaction_full(reaction_entry_ref), and
get_geometry(geometry_ref).
Common query patterns
Thermo by species:
client.search_thermo(
smiles="O",
temperature_min=300,
temperature_max=2000,
collapse="first",
include=["provenance", "review"],
)
Kinetics by reactants/products:
client.search_kinetics(
reactants=["C", "[OH]"],
products=["[CH3]", "O"],
temperature_min=500,
temperature_max=2000,
pressure_bar=1.0,
include=["provenance", "review"],
)
pressure_bar is an applicability filter, not an annotation: finite-pressure
queries exclude high-pressure-limit records, require an exact match for an
apparent-at-pressure fit, and require the requested pressure to lie inside a
PLOG or Chebyshev domain. Returned records explain the match in
pressure_coverage. The deprecated pressure alias is accepted for one
release and conflicts with pressure_bar are rejected.
Lowest single-point energy for one species entry at one level of theory:
client.search_species_calculations(
species_entry_ref="spe_...",
level_of_theory_ref="lot_...",
calculation_type="sp",
ranking="lowest_energy",
collapse="first",
limit=1,
include=["provenance"],
)
Both refs are required because raw electronic energies are only rankable within an explicitly comparable species-entry/level-of-theory set.
When reaction_path_degeneracy is present, inspect its explicit convention.
already_applied gives include/apply flags true/false; not_applied gives
false/true; unknown gives null/null, so a consumer must not guess. Legacy
rows are unknown. TCKDB does not transform stored Arrhenius, PLOG, falloff,
or Chebyshev coefficients when serving them.
Optimized geometry for a species:
calcs = client.search_species_calculations(
smiles="O",
calculation_type="opt",
include=["geometry", "provenance"],
)
geom_ref = calcs["records"][0]["geometry"]["primary_output_geometry_ref"]
Geometry coordinates by geom_ref:
client.get_geometry(geom_ref, include=["provenance"])
Python client quick start
from tckdb_client import TCKDBClient
# Anonymous — public scientific reads only.
client = TCKDBClient(base_url="http://127.0.0.1:8010/api/v1")
thermo = client.search_thermo(
smiles="O",
temperature_min=300,
temperature_max=2000,
collapse="first",
include=["provenance", "review"],
)
When the deployment requires authentication, or when you want
attributed reads, pass an api_key:
client = TCKDBClient(
base_url="http://127.0.0.1:8010/api/v1",
api_key=api_key,
)
Uploads, moderation, and admin endpoints always require an API key;
see clients/python/README.md
for the full matrix.
CLI examples
Two ready-to-run example scripts ship with the client:
scientific_reads.py— one-shot section-filterable read demo.query_cookbook.py— recipe-driven walkthrough that mirrorsscientific_query_cookbook.md.
Thermo only:
python clients/python/examples/scientific_reads.py \
--base-url http://127.0.0.1:8010/api/v1 \
--smiles "O" \
--only thermo \
--json
OPT calculations plus geometry coordinates:
python clients/python/examples/scientific_reads.py \
--base-url http://127.0.0.1:8010/api/v1 \
--smiles "O" \
--only calculations,geometry \
--calculation-type opt \
--json
Both scripts accept --api-key but neither requires it for scientific
reads.
Geometry coordinates
Geometry coordinates are not embedded in calculation-search responses. That keeps search payloads small and lets the geometry detail endpoint serve coordinates with their own provenance block.
The contract:
species-calculations/searchreturnsgeometry_refhandles (input_geometry_ref,primary_output_geometry_ref,output_geometry_refs, …).GET /scientific/geometries/{geometry_handle}returnssymbols,coords,xyz_text, plus aprovenanceblock listing the calculations that produced or consumed the geometry.
Where to find the ref:
- SP calculations typically expose an
input_geometry_ref— they consume a geometry rather than produce one. - OPT calculations expose
primary_output_geometry_refwhen the optimized geometry was persisted;input_geometry_refis the starting structure. - Freq calculations point at the geometry whose Hessian was evaluated.
include= parameter
include= accepts a comma-separated token list on every
scientific read endpoint. That is the documented public form:
GET /scientific/species/search?smiles=O&include=provenance,review
The Python client takes include=["provenance", "review"] and
serializes it into the same comma-separated query value. Repeated
include= query parameters are still parsed for HTTP client
compatibility (?include=a&include=b) but the comma-separated form
is canonical — that is what OpenAPI, the docs, and the client emit.
Tokens are trimmed of surrounding whitespace, empty entries are
dropped, and duplicates are deduplicated server-side.
include=all expands to every legal token for the endpoint except
internal_ids. Unknown tokens — or tokens known but illegal for
that endpoint — return 422.
Internal IDs
Internal integer IDs (species_id, species_entry_id, geom_id, etc.)
are hidden by default. They are compatibility/debug fields, not part of
the public hosted querying contract.
To opt in to integer IDs:
- The client must request
include=["internal_ids"](orinclude=["internal_ids", …]alongside other tokens). Bothinclude=all,internal_idsandinclude=all&include=internal_idsproduce the same resolved set. - The deployment must set
ALLOW_PUBLIC_INTERNAL_IDS=true. Public deployments leave thisfalse. include=["all"]does not includeinternal_ids. The opt-in is intentional.
Public documentation, examples, and integrations should always use
*_ref handles. See the
internal-ids visibility policy
for the full contract.
Abuse-control expectations
Hosted deployments enforce application-level rate limits and query caps. The full policy lives in public_read_abuse_controls.md. In short:
- Anonymous reads are rate-limited per client IP; authenticated
reads have a larger, separate budget keyed by API-key or session
fingerprint. A rejected request returns HTTP 429 with the stable
code
rate_limit_exceeded. limitis clamped toPUBLIC_MAX_LIMIT(default 200),offsettoPUBLIC_MAX_OFFSET(default 10 000). Exceeding values get HTTP 422 withlimit_too_large/offset_too_largein thedetailfield./scientific/geometries/{handle}refuses geometries with more thanMAX_GEOMETRY_ATOMS_PUBLICatoms (default 500;geometry_too_large)./scientific/reaction-entries/{handle}/fullcaps expanded sub-arrays atMAX_FULL_CALCULATIONS_PUBLICetc. (default 100 each;query_too_expensive)./scientific/reactions/searchrequires at least one chemistry or ref filter (missing_reaction_search_filter).- CORS is not permissive by default; deployments must set
CORS_ALLOW_ORIGINSto an explicit list to enable browser cross-origin calls. - Login and register are throttled per IP with their own buckets so credential stuffing and account spam are rejected with 429 before saturating the DB.
Anonymous-friendly client reads are not themselves an abuse-control mechanism. The client only decides whether it requires a key before sending; limits and shaping are server-side. The reverse-proxy / CDN should still layer in coarser per-IP rate limits, body-size caps, and statement timeouts as described in the spec.
Deployments behind a reverse proxy must configure
TRUSTED_PROXY_HEADER correctly (see the "Trusted-proxy header"
section of the abuse-control spec) — otherwise per-IP buckets either
collapse onto a shared transport peer or, worse, become trivially
spoofable.
The public scientific API is /api/v1/scientific/*. Legacy
non-scientific read routes (/api/v1/thermo, /api/v1/kinetics,
/api/v1/species, ...) require authentication by default in hosted
deployments via LEGACY_READS_REQUIRE_AUTH. Use the scientific
surface for anonymous public reads.
Known non-blocking follow-ups
Surfaced by the real-data usability audit and tracked here so consumers know what to expect. None block public hosted querying.
- Software release version normalization — ORCA records currently
report
software_release.version = "ORCA 6.0.0"(software name prefix included). Upload-side polish; reads return what was stored. - NASA temperature-bound review — some NASA polynomial records use
t_low = 10 K, which is unusually wide. Producers should review fit ranges; consumers should checkt_low/t_highagainst their intended use before extrapolating. - Upload-side TS-opt provenance link persistence — some
TS-backed kinetics records have
ts_opt_calculation_ref = Nonebecause the upload pipeline did not persist the TS-opt → calculation link. The read API surfaces what was uploaded; the fix is upload-side denormalization.
Related documentation
- scientific_query_cookbook.md — recipe walkthrough.
- workflow_tool_scientific_reads.md — workflow-tool integration patterns.
- scientific_read_demo_data.md — demo data setup.
clients/python/README.md— client install, configure, auth matrix.- internal_ids_visibility_policy.md — internal-IDs contract.