Skip to content

Discovery

The API is self-describing: everything you need to query a dataset — its endpoint, columns, types, row count, even a sample row — is available at runtime. Build against discovery and your integration keeps working as datasets are added.

List datasets

GET /v1/datasets
GET /v1/datasets?domain=transport

Standard paginated envelope of dataset summaries: slug, domain, title, description, update_frequency, source organization, updated_at, and endpoint — the serving path, so you can go straight from the list to the data without building URLs.

?domain= narrows the list to one domain; an unknown domain is a 422 listing the valid ones. Like the data endpoints, the list is strict: any other unrecognized parameter is a 422 (for full-text search use /v1/search?q=).

Inspect one dataset

GET /v1/datasets/{id}
curl -H "Authorization: Bearer $API_KEY" "https://api.canovix.ro/v1/datasets/vehicle_registry"

The detail response adds everything a client needs:

Field Meaning
endpoint The serving path — /v1/transport/vehicle_registry
export_endpoint The bulk export path
available_filters Columns you may filter on
sortable_fields / selectable_fields Columns valid in ?sort= / ?fields=
row_schema Column → type map ({"county": "string", "vehicle_count": "integer", ...})
row_count Current number of rows
sample One real row, so you can see actual values
latest_ingestion Provenance of the newest successful ingestion run

latest_ingestion is the full provenance record:

{
  "version": 3,
  "source_url": "https://data.gov.ro/dataset/.../parc-auto-la-31.12.2023.csv",
  "source_file": "parc-auto-la-31.12.2023.csv",
  "checksum": "a193925c0d27...",
  "pipeline_version": "0.1.0+91b1917980c5",
  "rows_imported": 382667,
  "rows_failed": 0,
  "imported_at": "2026-07-20T18:55:12Z",
  "duration_ms": 6520,
  "rows_per_sec": 95666
}

Use version / imported_at to detect refreshes, and source_url + checksum when you need to cite or audit exactly which upstream file the rows came from.

Generic client pattern

Discovery makes a dataset-agnostic client trivial:

def fetch(client: httpx.Client, dataset_id: str, **filters) -> list[dict]:
    detail = client.get(f"/v1/datasets/{dataset_id}").json()
    unknown = set(filters) - set(detail["available_filters"])
    if unknown:
        raise ValueError(f"{dataset_id} has no columns {unknown}")
    return client.get(detail["endpoint"], params=filters).json()["data"]

rows = fetch(client, "physicians", county="CLUJ")
async function fetchDataset(datasetId, filters = {}) {
  const headers = { Authorization: `Bearer ${API_KEY}` };
  const detail = await (
    await fetch(`${BASE}/v1/datasets/${datasetId}`, { headers })
  ).json();
  const params = new URLSearchParams(filters);
  const page = await (
    await fetch(`${BASE}${detail.endpoint}?${params}`, { headers })
  ).json();
  return page.items;
}

OpenAPI

The same information is available statically: /openapi.json (and Swagger UI at /docs) documents every dataset endpoint with its real per-column response schema — generated from the same configuration that drives the ingestion pipeline. Use it for codegen or Postman import.