{"openapi":"3.1.0","info":{"title":"zarr-passport-proxy","version":"0.1.0"},"paths":{"/version":{"get":{"summary":"Version","description":"Deployed build stamp — ``APP_GIT_SHA`` / ``APP_BUILD_TIME`` baked into the image\n(docker-compose build args; auto_update.sh stamps them). 'dev' when unset.","operationId":"version_version_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/":{"get":{"summary":"Root","description":"List available zarr stores (always reflects current disk state).\n\nDefault response carries the ``stores`` list **and** an ``agent_guide`` discovery\nblock (service description, a per-store guide URL, and the query/variables/openapi\nendpoints) so an agent given only the base URL isn't left with a bare list it can't\nact on. Ask for the standards-aligned catalog with ``Accept: application/ld+json`` or\n``?format=jsonld`` → a schema.org DataCatalog linking each store's Croissant sidecar.\n\nFiltered through `_visible_stores`: hosts with explicit patterns see\nonly matching stores; hosts without patterns see everything except\nwhat other hosts' patterns claim.  Live-disk behaviour preserved.","operationId":"root__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/llms.txt":{"get":{"summary":"Llms Txt","description":"LLM discovery file (the llmstxt.org convention): a plain-text pointer so an agent\ngiven only the base URL learns what the service is and where each store's full\n``agent_guide`` lives. Host-filtered, so a non-public store never appears here.","operationId":"llms_txt_llms_txt_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/icos_logo.svg":{"get":{"summary":"Icos Logo","description":"The ICOS logo for the HTML landing pages (served so the pages carry no inline\nblob); cached a day. Single-segment path, so it never collides with a store key.","operationId":"icos_logo_icos_logo_svg_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/favicon.ico":{"get":{"summary":"Favicon","description":"ICOS favicon for the HTML landing pages — the same icon the viewer apps use.\nBrowsers request /favicon.ico automatically; single-segment path, no store collision.","operationId":"favicon_favicon_ico_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/google2f93a3138681285e.html":{"get":{"summary":"Google Site Verification","description":"Google Search Console site-verification token (HTML-file method). Must remain\nserved for verification to stay valid — Google re-checks it periodically.","operationId":"google_site_verification_google2f93a3138681285e_html_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/robots.txt":{"get":{"summary":"Robots Txt","description":"Allow crawling and point crawlers at the sitemap — this is how Google Dataset\nSearch discovers the per-dataset landing pages without any inbound links.","operationId":"robots_txt_robots_txt_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/sitemap.xml":{"get":{"summary":"Sitemap Xml","description":"XML sitemap (sitemaps.org 0.9) of the crawlable pages — the root catalog and each\nvisible dataset's landing page — so a crawler reaches the schema.org Dataset markup.\nHost-filtered, so a non-public store is never listed; ``lastmod`` comes from the\nstore's date_modified/date_created when present.","operationId":"sitemap_xml_sitemap_xml_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/admin/rescan":{"post":{"summary":"Admin Rescan","description":"Force an immediate rescan of ZARR_STORE_DIR and return the deltas\nagainst the previously-known set.  Useful after dropping a new\nstore onto a long-running proxy without waiting for the periodic\nrefresh.\n\nAdmin-gated (Authorization: Bearer ADMIN_TOKEN) like the catalog mutators —\notherwise it would let anyone trigger a filesystem walk and read back the full\nstore list, including stores hidden from their Host by HOST_STORE_MAP.","operationId":"admin_rescan_admin_rescan_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/admin/log":{"get":{"summary":"Admin Log","description":"Recent application log (the in-process ring buffer), oldest→newest.\n\nAdmin-gated (Authorization: Bearer ADMIN_TOKEN) like /admin/rescan — proxy logs\ncan carry store paths and client detail, so they are never public. Lets ops read\nrecent errors over HTTP without shell access to the host; the viewers expose the\nsame buffer via their footer 'log' popup.","operationId":"admin_log_admin_log_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/variables":{"get":{"summary":"List Variables","description":"List catalogued ICOS variables visible from the requesting Host.\n\nEach record carries shortname, longname, unit, optional QC variable,\ndomain, I-ADOPT definition URL, ICOS variable type, and the zarr store /\ngroup that holds it.  Variables whose store is not visible to the caller's\nHost are omitted (same authorisation as the store listing).","operationId":"list_variables_variables_get","parameters":[{"name":"store","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by zarr store name","title":"Store"},"description":"Filter by zarr store name"},{"name":"domain","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by ENVRI domain","title":"Domain"},"description":"Filter by ENVRI domain"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Variable"},"title":"Response List Variables Variables Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"summary":"Add Variable","description":"Add a variable to the catalog (admin).  409 if the id already exists.","operationId":"add_variable_variables_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Variable"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Variable"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/variables/suggest":{"get":{"summary":"Suggest Variables","description":"Scan the Host-visible stores and propose catalog entries for variables\nnot yet catalogued, seeding domain / query coords / I-ADOPT / ICOS type\nfrom the store layout and a built-in map of well-known ENVRI variables.\n\nRead-only by default.  `?apply=true` requires the admin token and inserts\nthe suggestions into the catalog (existing entries are left untouched).","operationId":"suggest_variables_variables_suggest_get","parameters":[{"name":"apply","in":"query","required":false,"schema":{"type":"boolean","description":"Insert the suggestions into the catalog (admin)","default":false,"title":"Apply"},"description":"Insert the suggestions into the catalog (admin)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Variable"},"title":"Response Suggest Variables Variables Suggest Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/variables/{var_id}":{"get":{"summary":"Get Variable","description":"Return a single catalogued variable by id (404 if absent or its store\nis not visible to the caller's Host).","operationId":"get_variable_variables__var_id__get","parameters":[{"name":"var_id","in":"path","required":true,"schema":{"type":"string","title":"Var Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Variable"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"summary":"Update Variable","description":"Replace a catalogued variable by id (admin).  404 if it doesn't exist.","operationId":"update_variable_variables__var_id__put","parameters":[{"name":"var_id","in":"path","required":true,"schema":{"type":"string","title":"Var Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Variable"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Variable"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Delete Variable","description":"Delete a catalogued variable by id (admin).  404 if it doesn't exist.","operationId":"delete_variable_variables__var_id__delete","parameters":[{"name":"var_id","in":"path","required":true,"schema":{"type":"string","title":"Var Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/query":{"get":{"summary":"Query Variable","description":"Query one catalogued variable over a lat/lon box, time range, and\noptional height/depth window.  Streams matching observations as\nnewline-delimited JSON (one object per row); the final line is\n`{\"_passport\": {...}}` — a ROCrate data passport for exactly this query.\n\nWith `format=arrow` the result is returned as a single Apache Arrow IPC\nstream (zstd-compressed) instead — compact on the wire and zero-copy into a\nDataFrame — with the same passport carried in the schema metadata.\n\n`qc_max` drops failing rows; `apply_qc` instead keeps every row but\nreplaces values failing the recommended QC threshold (WOCE good ≤ 2,\noverridable via qc_max) with null.","operationId":"query_variable_query_get","parameters":[{"name":"id","in":"query","required":true,"schema":{"type":"string","description":"Catalogued variable id","title":"Id"},"description":"Catalogued variable id"},{"name":"lat_min","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lat Min"}},{"name":"lat_max","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lat Max"}},{"name":"lon_min","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lon Min"}},{"name":"lon_max","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lon Max"}},{"name":"start","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ISO start date/datetime (inclusive)","title":"Start"},"description":"ISO start date/datetime (inclusive)"},{"name":"end","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ISO end date/datetime (exclusive)","title":"End"},"description":"ISO end date/datetime (exclusive)"},{"name":"height_min","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Min height/depth (where supported)","title":"Height Min"},"description":"Min height/depth (where supported)"},{"name":"height_max","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Max height/depth (where supported)","title":"Height Max"},"description":"Max height/depth (where supported)"},{"name":"qc_max","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Drop rows whose QC flag exceeds this","title":"Qc Max"},"description":"Drop rows whose QC flag exceeds this"},{"name":"apply_qc","in":"query","required":false,"schema":{"type":"boolean","description":"Keep rows but null values failing the recommended QC threshold","default":false,"title":"Apply Qc"},"description":"Keep rows but null values failing the recommended QC threshold"},{"name":"source_doi_prefix","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Keep only obs whose cruise source DOI starts with this prefix — a by-network/provider filter, e.g. 10.18160 for ICOS (obs-table variables only)","title":"Source Doi Prefix"},"description":"Keep only obs whose cruise source DOI starts with this prefix — a by-network/provider filter, e.g. 10.18160 for ICOS (obs-table variables only)"},{"name":"reduce","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Server-side per-cruise thinning over the whole selection for map rendering (obs-table only): 'track' = Douglas-Peucker (path+extrema), 'stride' = uniform decimation, 'grid' = one obs per pos_tol-degree cell","title":"Reduce"},"description":"Server-side per-cruise thinning over the whole selection for map rendering (obs-table only): 'track' = Douglas-Peucker (path+extrema), 'stride' = uniform decimation, 'grid' = one obs per pos_tol-degree cell"},{"name":"pos_tol","in":"query","required":false,"schema":{"type":"number","description":"reduce=track/grid position tolerance (degrees) — DP corridor width, or grid cell size","default":4.0,"title":"Pos Tol"},"description":"reduce=track/grid position tolerance (degrees) — DP corridor width, or grid cell size"},{"name":"val_tol","in":"query","required":false,"schema":{"type":"number","description":"reduce=track value tolerance (variable unit)","default":16.0,"title":"Val Tol"},"description":"reduce=track value tolerance (variable unit)"},{"name":"max_rows","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Row cap (default QUERY_MAX_ROWS)","title":"Max Rows"},"description":"Row cap (default QUERY_MAX_ROWS)"},{"name":"format","in":"query","required":false,"schema":{"type":"string","description":"Response format: 'ndjson' (default), 'arrow' (zstd-compressed Apache Arrow IPC stream) or 'parquet' (zstd-compressed Apache Parquet file); for arrow/parquet the data passport rides in the schema metadata under 'data_passport'","default":"ndjson","title":"Format"},"description":"Response format: 'ndjson' (default), 'arrow' (zstd-compressed Apache Arrow IPC stream) or 'parquet' (zstd-compressed Apache Parquet file); for arrow/parquet the data passport rides in the schema metadata under 'data_passport'"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/summary":{"get":{"summary":"Summarize Variable","description":"Cheap size estimate for a selection — counts only, no row streaming.\nReturns n_obs / n_cells, n_cruises, lat/lon/time extent, and est_bytes, so a\nclient can show \"how big is my selection\" before downloading.","operationId":"summarize_variable_summary_get","parameters":[{"name":"id","in":"query","required":true,"schema":{"type":"string","description":"Catalogued variable id","title":"Id"},"description":"Catalogued variable id"},{"name":"lat_min","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lat Min"}},{"name":"lat_max","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lat Max"}},{"name":"lon_min","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lon Min"}},{"name":"lon_max","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lon Max"}},{"name":"start","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Start"}},{"name":"end","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"End"}},{"name":"qc_max","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Qc Max"}},{"name":"source_doi_prefix","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Doi Prefix"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{store_name}/session/close":{"post":{"summary":"Close Session","description":"Explicitly close the caller's session for *store_name* and mint a passport.\nAccepts an optional JSON body {\"queries\": [...]} with xarray selection\nsteps recorded client-side by datapassport_zarr.open_zarr().\nReturns {\"passport_pid\": \"hdl:11676/...\", \"passport_url\": \"https://...\"}.\nIf the session has no chunks (nothing was read), returns an empty result.","operationId":"close_session__store_name__session_close_post","parameters":[{"name":"store_name","in":"path","required":true,"schema":{"type":"string","title":"Store Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{store_name}/session/passport":{"get":{"summary":"Get Passport","description":"Return the passport PID for the caller's current or most-recently-closed\nsession for *store_name*.","operationId":"get_passport__store_name__session_passport_get","parameters":[{"name":"store_name","in":"path","required":true,"schema":{"type":"string","title":"Store Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{store_name}/":{"get":{"summary":"Store Root","description":"Serve root .zgroup for a store, or fsspec directory listing.","operationId":"store_root__store_name___get","parameters":[{"name":"store_name","in":"path","required":true,"schema":{"type":"string","title":"Store Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{store_name}/croissant":{"get":{"summary":"Get Croissant","description":"Serve a store's Croissant (MLCommons) JSON-LD sidecar from disk.\n\nDeclared before the catch-all key route so '/<store>/croissant' isn't\ntreated as a zarr key. 404s if the store is hidden from this Host or has\nno sidecar.","operationId":"get_croissant__store_name__croissant_get","parameters":[{"name":"store_name","in":"path","required":true,"schema":{"type":"string","title":"Store Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{store_name}/agent_guide":{"get":{"summary":"Get Agent Guide","description":"The store's machine-first access guide (open call, layout, QC keep-rule, query\nAPI, citation), lifted from its root ``.zattrs`` ``agent_guide``. Declared before\nthe catch-all key route so '/<store>/agent_guide' isn't served as a zarr key. 404s\nif the store is hidden from this Host or carries no guide.","operationId":"get_agent_guide__store_name__agent_guide_get","parameters":[{"name":"store_name","in":"path","required":true,"schema":{"type":"string","title":"Store Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/{store_name}/{key}":{"get":{"summary":"Serve Zarr Key","description":"Serve any zarr store key: metadata files or chunk arrays.\nChunk data is recorded in the session; metadata is served transparently.","operationId":"serve_zarr_key__store_name___key__get","parameters":[{"name":"store_name","in":"path","required":true,"schema":{"type":"string","title":"Store Name"}},{"name":"key","in":"path","required":true,"schema":{"type":"string","title":"Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"Variable":{"properties":{"id":{"type":"string","title":"Id","description":"Stable slug; defaults to '{store-stem}.{group}.{shortname}'.","default":""},"shortname":{"type":"string","title":"Shortname","description":"Zarr array name, e.g. 'fCO2'."},"longname":{"type":"string","title":"Longname","description":"Human-readable name.","default":""},"unit":{"type":"string","title":"Unit","description":"Physical unit, e.g. 'uatm'.","default":""},"quality_flag_variable":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Quality Flag Variable","description":"Companion QC array name, e.g. 'fCO2_QC'."},"domain":{"type":"string","enum":["ocean","atmosphere","ecosystem","land"],"title":"Domain","description":"ENVRI domain."},"iadopt_uri":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Iadopt Uri","description":"I-ADOPT variable-definition URL."},"icos_variable_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Icos Variable Type","description":"ICOS variable type / quantity kind."},"zarr_store":{"type":"string","title":"Zarr Store","description":"Store directory name, e.g. 'icos-socat.zarr'."},"group":{"type":"string","title":"Group","description":"Group holding the variable, e.g. '_obs'."},"query_kind":{"type":"string","enum":["obs_table","station_time","grid"],"title":"Query Kind","description":"How GET /query selects: flat obs table, (station,time), or grid.","default":"obs_table"},"time_coord":{"type":"string","title":"Time Coord","description":"Name of the time coordinate.","default":"time"},"lat_coord":{"type":"string","title":"Lat Coord","description":"Name of the latitude coordinate.","default":"lat"},"lon_coord":{"type":"string","title":"Lon Coord","description":"Name of the longitude coordinate.","default":"lon"},"height_coord":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Height Coord","description":"Coordinate for height/depth filtering, if any."}},"type":"object","required":["shortname","domain","zarr_store","group"],"title":"Variable","description":"One catalogued ICOS variable."}}}}