publicdata.au publicdata.au on GitHub

For agents

Everything here is meant to be read by a program first. There are no keys and no accounts, and no data file needs JavaScript. Files have no download limit, and the query API's limit is set out below.

Start with one of these

  • /api/v1/datasets/<slug>/rows filters, selects, orders and pages any dataset. For example /api/v1/datasets/au-road-deaths/rows?year=eq.2025&state=eq.QLD. /api/v1/datasets/<slug>/aggregate counts, sums, averages, minimums and maximums by group. For example ?group=state&metric=count&year=eq.2025. Without a version the API answers from the newest version, and that answer changes when the publisher releases again. Put versions/<date>/ before rows or aggregate for an answer from that version alone. Every version with a table can be queried, and /api/v1/datasets/<slug>/versions lists them. A query on a version the database does not hold is read from its Parquet file, and one that would read too much of it is refused with DuckDB SQL that answers it from the file. Each filter is field=operator.value in the query string, and every filter must match. A number or date field compares as a number or date, and a text field compares as text. Values are case-sensitive, except that like and ilike ignore case in the ASCII letters A to Z. Prefix not. to negate a filter, as not.eq.value. Operators: eq.value, neq.value, gt.value, gte.value, lt.value, lte.value, like.*text*, ilike.*text*, in.(a,b,c), is.null. Every JSON answer carries the version, licence and attribution. CSV and NDJSON answers carry them in response headers. /openapi.json describes every path, and each dataset's /d/<slug>/openapi.json lists its fields as parameters. The API allows 60 requests in 10 seconds from one address. Above that it answers 429 for 10 seconds with a Retry-After header, a RateLimit-Policy header and a JSON body that gives the limit. Every API answer carries the same RateLimit-Policy. A client should wait the Retry-After seconds, or read the files, which have no limit.
  • /catalogue/publishers.json lists every publisher on Australia's government portals with its page and counts. Each publisher page has a catalogue.json of the datasets it lists, with licence, formats and the portal URL.
  • /llms.txt lists every dataset with its latest download URLs. /llms-full.txt adds the field list for each.
  • /.well-known/ard.json is the Agentic Resource Discovery manifest. It lists the MCP server, an agent skill at /skills/publicdata-au/SKILL.md, a bundle of the catalogues and the API description, and a bundle for each dataset that holds its files and the server that queries it, with representative queries for each. The same document is at /.well-known/ai-catalog.json, and /.well-known/api-catalog lists the APIs as RFC 9727 asks.
  • /catalog.json is a DCAT catalogue in JSON-LD, one record per live dataset with a distribution per format.
  • /openapi.json is an OpenAPI 3.1 document for every public path, with the dataset slugs as an enum. Load it into any client generator or an agent's tool list.
  • /backlog.json is every register entry with its status, licence and the reason if it is blocked. /api/v1/votes has the current vote counts.

Pages have Markdown twins

Every page but an embed has a twin. Add index.md to any page URL, or follow the rel="alternate" type="text/markdown" link in its head. The twin has the same facts as the page in plain Markdown with front matter. A page URL asked for with Accept: text/markdown answers with its twin, except a dated version's page and an embed, which always answer in HTML. A path such as /about.md or /about/index.html.md is redirected to the twin.

Per dataset

  • /d/<slug>/datapackage.json is a Frictionless data package pointing at the latest version.
  • /d/<slug>/schema.json is a Table Schema. Types are string, integer, number, boolean, date and datetime. Beside each version, schema.sql is the same as a CREATE TABLE and data.csv-metadata.json is W3C CSV on the Web metadata.
  • /d/<slug>/fields.json lists each queryable field with its type, the publisher's description, its range and the values it holds when it has few. The MCP server offers it as a resource.
  • /d/<slug>/versions.json lists every version with its date, row count, source hash and URL.
  • /d/<slug>/changes.json summarises each consecutive diff. /d/<slug>/diff/<a>..<b>.json compares two consecutive versions by key.
  • /d/<slug>/latest/data.<format> redirects with a 302 to the newest dated version. Follow redirects. A table the publisher resends whole, or a feed of what is current, serves its newest read at the same path with a five-minute cache instead, and lists every read's changes in /d/<slug>/changes/index.json.
  • /d/<slug>/v/<date>/data.<format> keeps its content and is cached for a year. Formats: csv, csv.gz, ndjson, parquet and duckdb on every version, with xlsx, json and sqlite while the table is within their size limits. A dataset with coordinates or shapes adds gpkg, geo.parquet for points and geojson within its size limit, and a boundary layer adds pmtiles vector tiles. Versions whose manifest has no caps field were fetched before the size limits and also carry arrow. A version page says why a format is not there. Byte ranges are offered on Parquet, DuckDB, SQLite, Arrow, Excel, GeoPackage, PMTiles, csv.gz and the publisher's file. CSV, NDJSON, JSON and GeoJSON are sent whole, gzipped when the client accepts it, so a reader that scans lazily or seeks, such as polars scan_csv or fsspec, should read data.parquet or data.csv.gz.
  • /d/<slug>/v/<date>/by/<field>/<value>.json is a smaller file for one value of a partition field. by/<field>/index.json lists them.
  • /d/<slug>/v/<date>/SHA256SUMS lists the SHA-256 of every file in the version, each under the name it downloads as, such as <slug>_<date>.csv. Run sha256sum -c --ignore-missing SHA256SUMS beside the files (shasum -a 256 -c --ignore-missing SHA256SUMS on a Mac), or save them with curl -OJ so the names match. Each list carries a GitHub artifact attestation from the deploy that wrote it, which gh attestation verify SHA256SUMS --repo National-Digital/publicdata.au --source-ref refs/heads/main checks.

Inside every data file

JSON, NDJSON, GeoJSON, Parquet and SQLite each carry a publicdata header with the publisher, licence, attribution string, a cite string, version, source URL and source SHA-256. The CSV has no room for a header, so read manifest.json beside it.

When you show the data to a person

Use the publisher's attribution string, which the licence requires. Then say the file came from publicdata.au and link to the version URL, which we ask for. The cite string in the header does both in one sentence, and each dataset page has the same sentence as HTML, Markdown and BibTeX.

MCP server

https://publicdata.au/mcp is a remote MCP server over Streamable HTTP with the same tools, defined in the same place, so a tool added to the pages is added here too. It needs no key and no account. Its row tools and the query API answer every version through one query path, so a tool's answer and the query URL it cites give the same rows. A query that would read too much of a file is refused with DuckDB SQL that answers it from the file. It also has search and fetch, the two tools ChatGPT's deep research and company knowledge call by name, which run search_datasets and read a dataset's record in the shapes those features expect. The row tools are held to the query API's limit of 60 queries in 10 seconds from one address, and each call is two queries because it also counts the matching rows. Add it to Claude Code with claude mcp add --transport http publicdata https://publicdata.au/mcp, add the URL in Claude as a custom connector, connect the publicdata.au plugin in ChatGPT, or give it to any client that connects to remote MCP servers. Each dataset with a table is also a resource at https://publicdata.au/d/<slug>/fields.json, which lists its fields with their types, the publisher's descriptions, their ranges and the values they hold, so an agent can read a dataset's shape before it writes a query. It also offers the prompts ask_dataset and find_data, and suggests dataset slugs as a client types one. It is listed in Claude's connector directory, ChatGPT's plugin directory, Glama and Smithery.

Add to VS Code · Add to Cursor · /mcp/server-card describes the server for directories.

search_datasets Search datasets
Find the slug of a served dataset. Start here for any question about Australian government data, since the other tools read only the datasets this finds.
get_dataset Read a dataset
Read a served dataset's data package and full version history: licence, attribution, whole-table files and the version dates diff_versions and the version parameter take. It carries no rows. To answer from the rows use query_rows or count_rows, and for field names use list_fields.
list_fields List a dataset's fields
List a served dataset's fields, with their types, descriptions, ranges and values, before querying it. Call it before query_rows or count_rows unless you already know the exact names and values, because where matches values exactly and an unknown field is an error. It also names the key fields diff_versions compares on and the partition fields list_partitions accepts.
list_partitions List partition files
List the download files that split a served dataset's newest version by one field, such as one file per year. Use it to hand someone a slice of the data as a file. It gives file links and no rows, so to answer a question use query_rows or count_rows instead, and for the whole table as one file use get_dataset. field must be one of the partition_by fields that list_fields names, and any other field returns a 404 error. Every value comes back in one answer, with no paging. The call costs nothing against the rate limit.
query_rows Query rows
Read individual rows of a served dataset, filtered across the whole table. For totals and breakdowns use count_rows, and for files use get_dataset or list_partitions.
count_rows Count and sum rows
Count, sum, average, minimum or maximum rows of a served dataset across the whole table, grouped by up to three fields. For the rows themselves use query_rows.
diff_versions Compare versions
Compare two consecutive versions of a served dataset row by row on its key fields, to see what a publisher changed between releases. from and to must be adjacent dates in the version history from get_dataset, older first. Any other pair returns a 404 error, so step through a longer span one pair at a time. A dataset with no key, which list_fields shows as an empty key, gets row counts only, and a dataset with one version has nothing to compare. One answer holds the counts of rows added, removed, changed and unchanged, the keys of the rows added, removed and changed, and up to ten changed rows with their old and new values. The call costs nothing against the rate limit.
search_catalogue Search government portals
Search every dataset listed on Australia's government portals, including the many publicdata.au does not serve yet. Its records describe data held elsewhere, which cannot be queried here.
list_backlog List the build backlog
List the datasets people have asked publicdata.au to build, most votes first. Use it to see what is wanted or under way, or to check that a vote counted.
upvote_dataset Vote for a dataset
Add one anonymous vote for a government dataset that publicdata.au does not serve yet, so it is built sooner. To read a served dataset use search_datasets, and to see the votes so far use list_backlog.
Find served datasets by keyword and return each one's id, title and citation URL, in the shape ChatGPT deep research and company knowledge call search with.
fetch Fetch a dataset record
Read one served dataset's record as text to quote and cite: its summary, publisher, licence, attribution string, newest version and the URL of that version. It is the fetch that ChatGPT deep research and company knowledge call, with an id from search.

In the browser

Pages register WebMCP tools through navigator.modelContext when the browser exposes it. The row tools call the query API, so their filters, counts and sums cover the whole table of any version and an agent can answer a question about the data without leaving the page. On a dataset page they default to that dataset and describe each of its fields with the publisher's own wording and the values it holds. The search form and the backlog form carry declarative WebMCP annotations as well. Without any of it, the URLs above do the same work.

The tools are search_datasets, get_dataset, list_fields, list_partitions, query_rows, count_rows, diff_versions, search_catalogue, list_backlog and upvote_dataset.

Robots

/robots.txt allows every crawler, including AI crawlers, everywhere except /api/. Its Content-Signal line, in the contentsignals.org syntax, says yes to search indexing and to AI answers that read the site and no to AI training. That preference leaves each dataset's licence as it is, and the licence governs what you may do with the data. /sitemap.xml is a sitemap index with one sitemap per government and one for the other pages.