Every API here is available over the APIs.io API and to AI agents over MCP.
{
"openapi": "3.0.3",
"info": {
"title": "cityparity REST API",
"version": "0.1.0",
"description": "Cost-of-living and quality-of-life comparison endpoints. Same compute as the MCP server at /mcp; this surface is for non-MCP clients (web apps, scripts, integrations). All responses are JSON with shape { ok, data } on success or { ok: false, error, message } on failure.",
"contact": {
"url": "https://cityparity.com/contact/"
},
"license": {
"name": "MIT"
}
},
"servers": [
{
"url": "https://mcp.cityparity.com",
"description": "Production"
},
{
"url": "http://localhost:8788",
"description": "Local dev (wrangler)"
}
],
"tags": [
{
"name": "cities",
"description": "Discovery and per-city profiles"
},
{
"name": "comparison",
"description": "Cross-city scenario math"
},
{
"name": "ranking",
"description": "Quality-of-life ranking"
},
{
"name": "safety-net",
"description": "Family + healthcare safety-net data"
}
],
"paths": {
"/api/v1/cities": {
"get": {
"tags": [
"cities"
],
"summary": "List all supported cities",
"description": "Returns city slugs grouped by country.",
"parameters": [
{
"name": "country",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "Optional case-insensitive country filter (e.g. \"Norway\", \"United States\")."
}
],
"responses": {
"200": {
"$ref": "#/components/responses/Ok"
},
"400": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/cities/{slug}": {
"get": {
"tags": [
"cities"
],
"summary": "Get a city profile",
"description": "Tax shape, headline costs, safety-net values, inbound regime presence, data year range.",
"parameters": [
{
"$ref": "#/components/parameters/slug"
}
],
"responses": {
"200": {
"$ref": "#/components/responses/Ok"
},
"400": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/cities/{slug}/inbound-regime": {
"get": {
"tags": [
"cities"
],
"summary": "Get inbound-worker tax regime for a city",
"description": "Returns regime details for cities in countries with modeled regimes (Italy, Portugal, Belgium, Poland, Greece); returns regime: null otherwise.",
"parameters": [
{
"$ref": "#/components/parameters/slug"
}
],
"responses": {
"200": {
"$ref": "#/components/responses/Ok"
},
"400": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/compare": {
"post": {
"tags": [
"comparison"
],
"summary": "Compare two cities for a household scenario",
"description": "Returns take-home pay, full cost breakdown, equivalent target salary, lifestyle deltas, quality score. RSU income is not a parameter; treated as source-only.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CompareRequest"
}
}
}
},
"responses": {
"200": {
"$ref": "#/components/responses/Ok"
},
"400": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/rank": {
"post": {
"tags": [
"ranking"
],
"summary": "Rank cities by composite quality-of-life score",
"description": "Five-dimensional composite score (financial, healthcare, vacation, childcare, safety_net) with customizable weights and filters. Same scenario applied uniformly across cities.",
"requestBody": {
"required": false,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RankRequest"
}
}
}
},
"responses": {
"200": {
"$ref": "#/components/responses/Ok"
},
"400": {
"$ref": "#/components/responses/Error"
}
}
}
},
"/api/v1/safety-net": {
"post": {
"tags": [
"safety-net"
],
"summary": "Get safety-net values for N cities",
"description": "Parental leave, vacation, public holidays, universal healthcare flag, plus the safety_net dimension score (0-100).",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SafetyNetRequest"
}
}
}
},
"responses": {
"200": {
"$ref": "#/components/responses/Ok"
},
"400": {
"$ref": "#/components/responses/Error"
}
}
}
}
},
"components": {
"parameters": {
"slug": {
"name": "slug",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "City slug (e.g. \"nyc\", \"oslo\"). Discover slugs via GET /api/v1/cities."
}
},
"responses": {
"Ok": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Success"
}
}
}
},
"Error": {
"description": "Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
},
"schemas": {
"Success": {
"type": "object",
"required": [
"ok",
"data"
],
"properties": {
"ok": {
"type": "boolean",
"const": true
},
"data": {
"type": "object",
"additionalProperties": true
}
}
},
"Error": {
"type": "object",
"required": [
"ok",
"error",
"message"
],
"properties": {
"ok": {
"type": "boolean",
"const": false
},
"error": {
"type": "string",
"enum": [
"tool_error",
"validation_error",
"bad_json",
"not_found",
"rate_limited"
]
},
"message": {
"type": "string"
},
"hints": {
"type": "array",
"items": {
"type": "string"
}
},
"issues": {
"type": "array",
"items": {
"type": "object",
"properties": {
"path": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
}
}
},
"CompareRequest": {
"type": "object",
"required": [
"source_city",
"target_city",
"gross_salary"
],
"properties": {
"source_city": {
"type": "string",
"description": "City slug for the current city."
},
"target_city": {
"type": "string",
"description": "City slug for the destination city."
},
"gross_salary": {
"type": "number",
"exclusiveMinimum": 0,
"description": "User's annual gross salary in the SOURCE city's local currency."
},
"household": {
"type": "object",
"properties": {
"has_partner": {
"type": "boolean"
},
"partner_gross_salary": {
"type": "number",
"minimum": 0,
"description": "In source-city currency. Required when has_partner=true."
},
"partner_works_in_source": {
"type": "boolean",
"description": "Required when has_partner=true; cityparity does not silently default this."
},
"partner_works_in_target": {
"type": "boolean",
"description": "Required when has_partner=true."
},
"kids_ages": {
"type": "array",
"items": {
"type": "integer",
"minimum": 0,
"maximum": 25
}
}
}
},
"living": {
"type": "object",
"properties": {
"housing_mode": {
"type": "string",
"enum": [
"rent",
"own",
"own_outright"
]
},
"bedrooms": {
"type": "integer",
"minimum": 0,
"maximum": 5
},
"lifestyle": {
"type": "string",
"enum": [
"frugal",
"typical",
"generous"
]
}
}
},
"advanced": {
"type": "object",
"properties": {
"retirement_contrib_pct": {
"type": "number",
"minimum": 0,
"maximum": 50
},
"age_bracket": {
"type": "string",
"enum": [
"18-24",
"25-34",
"35-44",
"45-54",
"55-64"
]
},
"trips_home_per_year": {
"type": "integer",
"minimum": 0,
"maximum": 12
},
"source_transit_choice": {
"type": "string",
"enum": [
"car",
"transit"
]
},
"target_transit_choice": {
"type": "string",
"enum": [
"car",
"transit"
]
},
"apply_inbound_regime": {
"type": "boolean"
}
}
},
"score_weights": {
"$ref": "#/components/schemas/ScoreWeights"
}
}
},
"RankRequest": {
"type": "object",
"properties": {
"weights": {
"$ref": "#/components/schemas/ScoreWeights"
},
"filter": {
"type": "object",
"properties": {
"country": {
"type": "string"
},
"countries": {
"type": "array",
"items": {
"type": "string"
}
},
"region": {
"type": "string",
"enum": [
"europe",
"asia",
"north_america",
"south_america",
"oceania"
]
},
"has_universal_healthcare": {
"type": "boolean"
},
"include_cities": {
"type": "array",
"items": {
"type": "string"
}
},
"exclude_cities": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"scenario": {
"type": "object",
"properties": {
"gross_salary_usd": {
"type": "number",
"exclusiveMinimum": 0
},
"has_partner": {
"type": "boolean"
},
"partner_gross_salary_usd": {
"type": "number",
"minimum": 0
},
"kids_ages": {
"type": "array",
"items": {
"type": "integer",
"minimum": 0,
"maximum": 25
}
},
"bedrooms": {
"type": "integer",
"minimum": 0,
"maximum": 5
},
"housing_mode": {
"type": "string",
"enum": [
"rent",
"own",
"own_outright"
]
},
"lifestyle": {
"type": "string",
"enum": [
"frugal",
"typical",
"generous"
]
}
}
},
"limit": {
"type": "integer",
"minimum": 1,
"maximum": 50,
"default": 10
}
}
},
"SafetyNetRequest": {
"type": "object",
"required": [
"cities"
],
"properties": {
"cities": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"maxItems": 20,
"description": "Array of city slugs."
}
}
},
"ScoreWeights": {
"type": "object",
"description": "Override composite-score weights. Defaults: financial 30, healthcare 20, vacation 15, childcare 15, safety_net 20.",
"properties": {
"financial": {
"type": "number",
"minimum": 0,
"maximum": 100
},
"healthcare": {
"type": "number",
"minimum": 0,
"maximum": 100
},
"vacation": {
"type": "number",
"minimum": 0,
"maximum": 100
},
"childcare": {
"type": "number",
"minimum": 0,
"maximum": 100
},
"safety_net": {
"type": "number",
"minimum": 0,
"maximum": 100
}
}
}
}
}
}