The Expat Living Italy data API

One typed core, three surfaces: a REST API with an OpenAPI 3.1 spec, a remote MCP server, and an agent-readable layer. All three read the same data as the site itself — no upstream call happens in a request path, and every value carries its source, vintage and extraction date. Missing data comes back asnull with a reason, never a zero or an imputed average.

REST

Base URL: https://www.expatliving.it/api/v1. Spec: /api/v1/openapi.json (OpenAPI 3.1, importable unmodified as a Custom GPT Action).

curl https://www.expatliving.it/api/v1/comuni/075029
curl https://www.expatliving.it/api/v1/datasets

Anonymous, no key required. Responses are cached for a day at the edge — the data changes on an ETL run, not per request.

MCP

Streamable HTTP at https://www.expatliving.it/api/v1/mcp. Read-only, no auth. One tool today — get_comune — generated from the same schema as the REST endpoint above, so the two can never drift apart.

{
  "mcpServers": {
    "expatliving-data": {
      "url": "https://www.expatliving.it/api/v1/mcp"
    }
  }
}

Paste that into Claude Desktop's or Claude Code's MCP config, or any client that speaks Streamable HTTP MCP.

Agent-readable layer

/llms.txt — what this site is, what it holds, and where the API and MCP endpoints are.

What's servable today

GET /v1/comuni/{istatCode} and GET /v1/datasets. The full build order — search/filter, province and nationality endpoints, tax eligibility, JSON twins on every page, JSON-LD, and bulk snapshots — is tracked in docs/data-api-brief.md.