OData API
Base URL: https://odata.opteryx.app
Overview
OData service discovery, metadata, and dataset query endpoints for compatible clients and BI tools.
Endpoints
| Service | Docs |
|---|---|
Well Known Llmsget/.well-known/llms.txt |
View |
OData v4 Service Documentget/api/v4/ |
View |
OData v4 Service-wide EDMX Metadataget/api/v4/$metadata |
View |
Query dataset rowsget/api/v4/{workstream}/{collection}/{dataset} |
View |
Per-dataset OData EDMX metadataget/api/v4/{workstream}/{collection}/{dataset}/$metadata |
View |
Well Known Llms
Request: get/.well-known/llms.txt
Tags: service
Serve LLM directives file for automated agents.
Responses
- 200 — Successful Response (
text/plainstring)
OData v4 Service Document
Request: get/api/v4/
Tags: OData v4
Returns the OData v4 service document listing all accessible EntitySets grouped by workspace and collection.
Header Parameters
- authorization
string | null[header; optional]
Responses
- 200 — Service document with EntitySet list and access metadata (
application/jsonobject) - 401 — Missing or invalid authentication
- 422 — Validation Error (
application/jsonHTTPValidationError)
OData v4 Service-wide EDMX Metadata
Request: get/api/v4/$metadata
Tags: OData v4
Returns the complete OData v4 EDMX metadata document describing all EntityTypes and EntitySets accessible to the authenticated user.
Header Parameters
- authorization
string | null[header; optional]
Responses
- 200 — EDMX metadata document (XML) (
application/jsonobject) - 401 — Missing or invalid authentication
- 504 — Firestore unavailable; cannot enumerate datasets
- 422 — Validation Error (
application/jsonHTTPValidationError)
Query dataset rows
Request: get/api/v4/{workstream}/{collection}/{dataset}
Tags: OData v4
Retrieve data from a dataset with OData v4 query parameters ($filter, $select, $orderby, $top, $skip, $apply, $count). Returns paginated results with total count and nextLink for server-driven paging. The dataset segment may carry a @{label} version selector: dataset@current (the default, also what a bare dataset means), dataset@previous (the most recent version of the data before this one — maintenance snapshots such as compaction that changed no rows are skipped), dataset@{tag} (a named snapshot), or dataset@{snapshot_id} (a specific snapshot id). @current and @previous are resolved fresh on every page, so paging through them is not snapshot-isolated against concurrent writes; @{tag} and @{snapshot_id} are immutable and page consistently.
Path Parameters
- workstream
string[path; required] - collection
string[path; required] - dataset
string[path; required]
Query Parameters
- $filter
string | null[query; optional] OData $filter expression for row filtering. Operators: eq (equal), ne (not equal), lt/le/gt/ge (comparison), and/or/not (logical), contains/startswith/endswith (string), in_subnet (IPv4 CIDR containment). Case-sensitive. in_subnet(ip_column, 'cidr') is an Opteryx extension for IPv4-typed columns, e.g. in_subnet(src_addr, '192.168.4.0/24'); the PostgreSQL <<= operator is not valid OData syntax. Example: vendor eq 'Oracle' and price gt 100. Date/datetime literals must be unquoted per the OData v4 spec, e.g. shipped_date gt 2024-01-01 — a quoted date is compared as a string and raises a type-mismatch error. Date and time functions: now() (the query's wall clock, evaluated once per query so every row sees the same instant), year(), month(), day(), hour(), minute(), second() (each returns the named component of a date or timestamp as an integer, e.g. year(shipped_date) eq 2024), and date() (narrows a timestamp to its date part, e.g. date(created_at) eq 2024-01-01). The OData functions time(), mindatetime() and maxdatetime() are not implemented and are rejected with a message naming what to write instead. Rolling windows: combine now() with an ISO 8601 duration literal using add or sub, e.g. published_at ge now() sub duration'P30D' for the last 30 days. The duration syntax is duration'PnYnMnDTnHnMnS', optionally signed, e.g. duration'P1Y', duration'P18M', duration'PT12H', duration'-P7D'. Year and month durations are calendar-aware — duration'P1Y' means one calendar year and duration'P1M' one calendar month, so their length depends on the date they are applied to — while day, hour, minute and second durations are fixed spans (duration'P30D' is always exactly 30 × 24 hours). - $top
integer | null[query; optional] Limit result rows (0-25000, default 100). Value 0 with $count=true returns count only. Returns @odata.nextLink if result is truncated. - $skip
integer | null[query; optional] Skip N rows for pagination (server-driven). Requires $orderby: without a deterministic row order, paging duplicates some rows and drops others. Example: &$orderby=id asc&$skip=100 to fetch rows 101+. Combine with $top for paging. - $orderby
string | null[query; optional] Sort by column(s): 'col1 asc, col2 desc'. Default ascending. Example: &$orderby=created_date desc - $count
string | null[query; optional] Include total row count in response: 'true' or 'false' (default false). Use with $top=0 to get count only. - $select
string | null[query; optional] Select specific columns: 'col1,col2,col3' or '*' for all (default all). Reduces payload size. - $search
string | null[query; optional] Full-text search (not implemented; returns 501) - $apply
string | null[query; optional] Data aggregation: groupby((col), aggregate(amount with sum as Total, $count as Count)). Aggregates are written as '$count as Alias' or 'col withas Alias', where is one of sum, average, min, max -- that list is exhaustive, and function-call forms such as sum(amount) are not accepted. Transformations chain with '/', e.g. filter(x gt 1)/groupby((col), aggregate($count as Count)); a groupby with no aggregate deduplicates, so a distinct count is groupby((a,b))/groupby((a), aggregate($count as N)).
Header Parameters
- authorization
string | null[header; optional]
Responses
- 200 — Query succeeded; returns rows and pagination metadata (
application/jsonobject) - 400 — Invalid query: malformed $filter, unsupported $top value (not 0-25000), negative $skip, $skip without $orderby, invalid $count value, or invalid $apply expression. A malformed @{label} version selector also returns 400.
- 401 — Missing or invalid authentication (no bearer token or basic auth)
- 403 — Forbidden: authenticated but no permission for dataset
- 404 — Dataset not found, or the @{label} version selector names a tag, snapshot, or previous version that does not exist
- 501 — Unsupported query feature: $search or $expand not implemented
- 422 — Validation Error (
application/jsonHTTPValidationError)
Per-dataset OData EDMX metadata
Request: get/api/v4/{workstream}/{collection}/{dataset}/$metadata
Tags: OData v4
Returns OData $metadata (EDMX) for a single dataset, including column types and nullability, plus custom annotations carrying column statistics (Custom.Statistics.Min/Max, DistinctValueCount, NullCount, Distribution, and CIDR for IPv4 columns), the source type name (Custom.OriginalType, Custom.SourceType), the caller's access (Custom.Role, Custom.Policy), dataset and column descriptions (Custom.Description, Custom.LLMDescribed), current-snapshot metadata (Custom.Snapshot.Id/TotalRecords/TotalDataSize/CommitMessage/Author), physical sort order (Custom.SortOrder.Column/Direction), snapshot tags (Custom.Tags.Count and Custom.Tags, a Collection of Records with Name, SnapshotId and CreatedBy), and materialized-view state (Custom.MaterializedView.). Annotations are omitted where they do not apply to the dataset kind or are unavailable. The dataset segment may carry a @{label} version selector — dataset@current, dataset@previous, dataset@{tag}, or dataset@{snapshot_id} — and the Custom.Snapshot. and Custom.Tags annotations describe that version rather than the current one.
Path Parameters
- workstream
string[path; required] - collection
string[path; required] - dataset
string[path; required]
Header Parameters
- authorization
string | null[header; optional]
Responses
- 200 — EDMX metadata document returned as XML (
application/jsonobject) - 400 — Malformed @{label} version selector, or the dataset kind does not support snapshot versioning
- 401 — Missing or invalid authentication
- 403 — Forbidden: no permission to view dataset metadata
- 404 — Dataset not found in catalog, or the @{label} version selector names a tag, snapshot, or previous version that does not exist
- 422 — Validation Error (
application/jsonHTTPValidationError)