Optional. Stays in your browser (localStorage), never sent to us, and carries across pages. The static examples keep showing ak_your_key for everyone else.
Quickstart
# 1. Register (free tier, 500 calls/month). Key is returned and emailed.
curl -X POST https://api.ausdata.io/v1/register \
-H 'Content-Type: application/json' \
-d '{"email":"you@example.com"}'
# 2. Confirm it works
curl -H 'Authorization: Bearer ak_your_key' https://api.ausdata.io/v1/whoami
# 3. Latest headline inflation, flat and citable
curl -H 'Authorization: Bearer ak_your_key' \
https://api.ausdata.io/v1/series/AU.CPI.YOY/latest # pip install httpx (or: pip install ausdata-sdk for the typed client)
import httpx
BASE = "https://api.ausdata.io"
# 1. Register (free tier, 500 calls/month). Key is returned and emailed.
key = httpx.post(f"{BASE}/v1/register",
json={"email": "you@example.com"}).json()["api_key"]
auth = {"Authorization": "Bearer ak_your_key"}
# 2. Confirm it works
httpx.get(f"{BASE}/v1/whoami", headers=auth).raise_for_status()
# 3. Latest headline inflation, flat and citable
latest = httpx.get(f"{BASE}/v1/series/AU.CPI.YOY/latest", headers=auth).json()
print(latest["value"], latest["units"], latest["period"]) // Node 18+ has fetch built in. No dependencies.
const BASE = "https://api.ausdata.io";
// 1. Register (free tier, 500 calls/month). Key is returned and emailed.
const reg = await fetch(`${BASE}/v1/register`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email: "you@example.com" }),
}).then((r) => r.json());
const auth = { Authorization: "Bearer ak_your_key" };
// 2. Confirm it works
await fetch(`${BASE}/v1/whoami`, { headers: auth });
// 3. Latest headline inflation, flat and citable
const latest = await fetch(
`${BASE}/v1/series/AU.CPI.YOY/latest`, { headers: auth }
).then((r) => r.json());
console.log(latest.value, latest.units, latest.period); Returns from the final call. The /latest route is flat (no envelope), purpose-built for a single citable value:
{
"series_id": "AU.CPI.YOY",
"title": "Consumer Price Index, Annual Change (Headline Inflation), Australia",
"date": "2026-03-31",
"period": "2026-Q1",
"value": 4.0,
"units": "Percent",
"units_short": "%",
"frequency": "quarterly",
"source_name": "ABS Consumer Price Index (6401.0)",
"stale": false,
"attribution": [
{
"name": "Australian Bureau of Statistics",
"url": "https://www.abs.gov.au",
"attribution": "Based on Australian Bureau of Statistics data, licensed under CC-BY 4.0."
}
],
"citation": "Consumer Price Index, Annual Change (Headline Inflation), Australia (2026-Q1): 4.0 Percent. Source: ABS Consumer Price Index (6401.0), via ausdata.io"
} Each response also carries last_updated, realtime_start, and realtime_end timestamps that move with each fetch, so they are omitted above. The value and period are the real published vintage at time of capture.
Authentication
Send your key as a Bearer token. It starts with ak_.
Authorization: Bearer ak_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx It is Authorization: Bearer ak_..., not an X-API-Key header. Get a key with POST /v1/register.
Tiers and limits
| Tier | Price | Monthly calls |
|---|---|---|
| Free | $0 | 500 |
| Analyst | $29/mo | 10,000 |
| Embed | $99/mo | 100,000 |
| Enterprise | Custom | Custom |
Per-minute limit: 100 req/min per key. Every authed response carries X-Quota-Limit, X-Quota-Used, and X-Quota-Remaining headers. A 429 includes Retry-After.
Response envelope
Every authed JSON response uses one shape: { data, meta, links }. The meta object carries sources (with attribution), period, row_count, stale, retrieved_at, and server_version. Two exceptions: /v1/series/{id}/latest returns the value flat, and /v1/weather/{location} uses a weather shape.
Canonical series
Stable, citable IDs that resolve to a flat {date, value} series, FRED-style. Browse them at GET /v1/series.
GET /v1/series/AU.CPI.YOY?start=2015-Q1&end=2024-Q4&units=pc1
GET /v1/series/AU.CPI.YOY/latest # single flat value + citation
GET /v1/series/AU.CPI.YOY/observations # FRED-compatible alias
GET /v1/series/multi?ids=AU.CPI.YOY,AU.WAGES.YOY,AU.CASHRATE Units transforms (FRED-compatible): lin, chg, ch1, pch, pc1, pca, cch, cca, log. Params: start, end, limit, offset, sort_order, units, format (json or csv).
Raw data and discovery
GET /v1/data/{source}/{dataset_id}?start=2015-Q1 # raw passthrough
GET /v1/datasets # all sources + counts
GET /v1/search-datasets?q=unemployment # cross-source search
GET /v1/describe/abs/CPI # schema + filters
GET /v1/releases?days_ahead=30 # publication calendar Charts and embedding
Every series renders as an SVG. To embed in a public page, mint a chart-only embed token, never your ak_ key.
GET /v1/account/embed-token # returns emb_...
<img src="https://api.ausdata.io/v1/series/AU.CPI.YOY/chart.svg?key=emb_..."> Reliability contract
The API returns current data, or it fails clearly. It never serves an older vintage as the current answer. Government data is published with natural lag (CPI is quarterly, ATO lags about two years), and the latest published vintage is the reliable answer. If a source is momentarily unavailable and the only cache would be a genuinely outdated vintage, the API returns 503 with Retry-After. Build one retry on 503 into your client.
Errors
Every 4xx/5xx uses { error, message, hint, detail }. Branch on the stable error slug.
| Status | error | Meaning |
|---|---|---|
| 401 | unauthorized | Missing or invalid key |
| 403 | forbidden | Wrong credential type or tier-gated route |
| 404 | not_found | Unknown source/dataset/series (carries a "did you mean") |
| 422 | validation_error | Bad parameters |
| 429 | rate_limit_exceeded | Per-minute or monthly cap; obey Retry-After |
| 503 | service_unavailable | Source warming/unavailable; retry per Retry-After |
Client libraries
- Python:
pip install ausdata-sdk - Node CLI:
npm install -g ausdata-cli - MCP server (for Claude Desktop and agents):
npm install -g ausdata-mcp
No SDK for your language? The API is plain HTTP; call it with curl, fetch, httpx, httr2, or net/http.
Agents and MCP
The whole API is exposed as an MCP server, so Claude Desktop and other MCP clients can call it directly. No install step: npx fetches and runs it. Add this to your claude_desktop_config.json and restart Claude Desktop.
{
"mcpServers": {
"ausdata": {
"command": "npx",
"args": ["-y", "ausdata-mcp"],
"env": { "AUSDATA_API_KEY": "ak_your_key" }
}
}
} Paste your key above and this block picks it up too. The agent then calls the same routes documented here, with the same envelope and the same attribution on every response.