{
  "openapi": "3.0.3",
  "info": {
    "title": "CityCheck API",
    "description": "Free public API for US city safety, crime data, and local activity listings. Safety data covers 3,200+ cities with grades, risk levels, crime rate breakdowns, and head-to-head comparisons. Based on FBI Uniform Crime Report data. No API key required.",
    "version": "2.0.0",
    "contact": {
      "name": "CityCheck",
      "url": "https://citycheck.live",
      "email": "api@citycheck.live"
    }
  },
  "servers": [
    {
      "url": "https://citycheck.live",
      "description": "Production"
    }
  ],
  "paths": {
    "/api/v1/safety/cities": {
      "get": {
        "operationId": "listSafetyCities",
        "summary": "List all cities with safety grades and crime rates",
        "description": "Returns all 3,200+ US cities with safety grades (A+ to F), risk levels, crime rates per 1K, and violent/property rates per 100K. Filter by state, sort by safest or most dangerous.",
        "parameters": [
          {
            "name": "state",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by state slug (e.g., california, new-york, texas)"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 5000,
              "maximum": 5000
            },
            "description": "Max results to return"
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "safest",
                "most-dangerous",
                "population"
              ]
            },
            "description": "Sort order (default: population)"
          }
        ],
        "responses": {
          "200": {
            "description": "List of cities with safety data",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "total": {
                      "type": "integer",
                      "example": 3212
                    },
                    "dataYear": {
                      "type": "integer",
                      "example": 2023
                    },
                    "lastUpdated": {
                      "type": "string",
                      "example": "2024-10-27"
                    },
                    "source": {
                      "type": "string",
                      "example": "CityCheck (citycheck.live)"
                    },
                    "sourceUrl": {
                      "type": "string",
                      "example": "https://citycheck.live/safety"
                    },
                    "cities": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CitySafetySummary"
                      }
                    }
                  }
                },
                "example": {
                  "total": 3212,
                  "dataYear": 2023,
                  "lastUpdated": "2024-10-27",
                  "source": "CityCheck (citycheck.live)",
                  "sourceUrl": "https://citycheck.live/safety",
                  "cities": [
                    {
                      "name": "New York",
                      "state": "New York",
                      "slug": "new-york",
                      "stateSlug": "new-york",
                      "population": 8336817,
                      "grade": "B-",
                      "riskLevel": "moderate",
                      "riskLabel": "Moderate",
                      "crimeRatePer1K": 19.8,
                      "violentRate": 380,
                      "propertyRate": 1600,
                      "nationalPercentile": 54,
                      "url": "https://citycheck.live/safety/new-york/new-york"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/safety/city/{state}/{city}": {
      "get": {
        "operationId": "getCitySafety",
        "summary": "Full safety profile for a city",
        "description": "Returns complete safety profile including grade, risk level, violent/property breakdowns (murder, assault, robbery, burglary, theft, vehicle theft), percentiles, trend, victim odds, and FAQs.",
        "parameters": [
          {
            "name": "state",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "State slug (e.g., california, new-york)"
          },
          {
            "name": "city",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "City slug (e.g., los-angeles, new-york)"
          }
        ],
        "responses": {
          "200": {
            "description": "Full city safety profile",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CitySafetyProfile"
                }
              }
            }
          },
          "404": {
            "description": "City not found"
          }
        }
      }
    },
    "/api/v1/safety/state/{state}": {
      "get": {
        "operationId": "getStateSafety",
        "summary": "State overview with all cities",
        "description": "Returns a state overview with context, aggregate safety stats, and all cities in the state ranked by population.",
        "parameters": [
          {
            "name": "state",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "State slug (e.g., texas, california)"
          }
        ],
        "responses": {
          "200": {
            "description": "State safety overview",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "state": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "slug": {
                          "type": "string"
                        },
                        "cityCount": {
                          "type": "integer"
                        },
                        "totalPopulation": {
                          "type": "integer"
                        },
                        "averageSafetyPercentile": {
                          "type": "integer"
                        }
                      }
                    },
                    "context": {
                      "type": "string"
                    },
                    "cities": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CitySafetySummary"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "State not found"
          }
        }
      }
    },
    "/api/v1/safety/compare/{slug}": {
      "get": {
        "operationId": "compareCities",
        "summary": "Head-to-head safety comparison",
        "description": "Compare two cities side-by-side. Returns both profiles plus computed comparison data showing which city is safer overall, for violent crime, and for property crime.",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Comparison slug: {city}-{state}-vs-{city}-{state} (e.g., houston-texas-vs-dallas-texas)",
            "example": "houston-texas-vs-dallas-texas"
          }
        ],
        "responses": {
          "200": {
            "description": "Comparison result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "city1": {
                      "$ref": "#/components/schemas/ComparisonCityData"
                    },
                    "city2": {
                      "$ref": "#/components/schemas/ComparisonCityData"
                    },
                    "comparison": {
                      "type": "object",
                      "properties": {
                        "saferOverall": {
                          "type": "string"
                        },
                        "percentileDifference": {
                          "type": "integer"
                        },
                        "violentCrimeSafer": {
                          "type": "string"
                        },
                        "violentCrimeRateDifference": {
                          "type": "number"
                        },
                        "propertyCrimeSafer": {
                          "type": "string"
                        },
                        "propertyCrimeRateDifference": {
                          "type": "number"
                        },
                        "summary": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Could not parse comparison slug or cities not found"
          }
        }
      }
    },
    "/api/v1/safety/safest": {
      "get": {
        "operationId": "getSafestCities",
        "summary": "Top safest cities",
        "description": "Returns the top 50 safest cities in the US (or in a specific state). Ranked by national safety percentile.",
        "parameters": [
          {
            "name": "state",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter to a specific state (e.g., texas)"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 200
            },
            "description": "Number of results"
          }
        ],
        "responses": {
          "200": {
            "description": "Ranked list of safest cities",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "total": {
                      "type": "integer"
                    },
                    "description": {
                      "type": "string"
                    },
                    "cities": {
                      "type": "array",
                      "items": {
                        "allOf": [
                          {
                            "$ref": "#/components/schemas/CitySafetySummary"
                          },
                          {
                            "type": "object",
                            "properties": {
                              "rank": {
                                "type": "integer"
                              }
                            }
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/cost-of-living": {
      "get": {
        "operationId": "getCostOfLiving",
        "summary": "Cost of living data for 200+ US cities",
        "description": "Returns cost-of-living indices for 200+ US cities across 6 categories: overall, housing, groceries, transportation, healthcare, utilities. National average = 100. Supports single city lookup, state filtering, sorting, and CSV export.",
        "parameters": [
          {
            "name": "city",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "City slug for single lookup (e.g. denver-colorado)"
          },
          {
            "name": "state",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by state name (e.g. California)"
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "overall",
                "housing",
                "groceries",
                "transportation",
                "healthcare",
                "utilities"
              ]
            },
            "description": "Sort by category index (descending)"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Limit results"
          },
          {
            "name": "format",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "csv"
              ]
            },
            "description": "Response format (default: json)"
          }
        ],
        "responses": {
          "200": {
            "description": "Cost of living data",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer"
                    },
                    "source": {
                      "type": "string"
                    },
                    "nationalAverage": {
                      "type": "integer",
                      "example": 100
                    },
                    "cities": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "city": {
                            "type": "string"
                          },
                          "state": {
                            "type": "string"
                          },
                          "slug": {
                            "type": "string"
                          },
                          "costOfLiving": {
                            "type": "object",
                            "properties": {
                              "overallIndex": {
                                "type": "integer",
                                "example": 130
                              },
                              "housing": {
                                "type": "integer",
                                "example": 195
                              },
                              "groceries": {
                                "type": "integer",
                                "example": 108
                              },
                              "transportation": {
                                "type": "integer",
                                "example": 112
                              },
                              "healthcare": {
                                "type": "integer",
                                "example": 105
                              },
                              "utilities": {
                                "type": "integer",
                                "example": 92
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/climate": {
      "get": {
        "operationId": "getClimate",
        "summary": "Climate data for 200+ US cities",
        "description": "Returns monthly climate data (temperature, precipitation, snow, wind, humidity, sunshine) for 200+ US cities. Includes annual summaries, comfort months, and best/worst visiting months. Supports CSV export.",
        "parameters": [
          {
            "name": "city",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "City lookup in 'City, State' format (e.g. 'Denver, Colorado')"
          },
          {
            "name": "state",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by state name"
          },
          {
            "name": "format",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "csv"
              ]
            },
            "description": "Response format (default: json)"
          }
        ],
        "responses": {
          "200": {
            "description": "Climate data",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer"
                    },
                    "source": {
                      "type": "string"
                    },
                    "cities": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "city": {
                            "type": "string"
                          },
                          "state": {
                            "type": "string"
                          },
                          "annualHighF": {
                            "type": "number"
                          },
                          "annualLowF": {
                            "type": "number"
                          },
                          "annualRainIn": {
                            "type": "number"
                          },
                          "annualSnowIn": {
                            "type": "number"
                          },
                          "comfortMonths": {
                            "type": "integer"
                          },
                          "freezingMonths": {
                            "type": "integer"
                          },
                          "bestMonth": {
                            "type": "integer"
                          },
                          "worstMonth": {
                            "type": "integer"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/cities": {
      "get": {
        "operationId": "listCities",
        "summary": "List all cities with activity listing counts",
        "description": "Returns all cities that have verified activity listings, with the total count of listings per city.",
        "responses": {
          "200": {
            "description": "List of cities",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "total": {
                      "type": "integer"
                    },
                    "totalListings": {
                      "type": "integer"
                    },
                    "cities": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "slug": {
                            "type": "string",
                            "example": "chicago"
                          },
                          "name": {
                            "type": "string",
                            "example": "Chicago"
                          },
                          "fullName": {
                            "type": "string",
                            "example": "Chicago, IL"
                          },
                          "state": {
                            "type": "string",
                            "example": "IL",
                            "nullable": true
                          },
                          "listings": {
                            "type": "integer",
                            "example": 160
                          },
                          "tagline": {
                            "type": "string",
                            "nullable": true
                          }
                        }
                      }
                    },
                    "attribution": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/cities/{city}/listings": {
      "get": {
        "operationId": "getCityListings",
        "summary": "Get activity listings for a city",
        "description": "Returns verified activity listings for a specific city. Supports filtering by price, indoor/outdoor, category, and text search.",
        "parameters": [
          {
            "name": "city",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "City slug (e.g., chicago, los-angeles)"
          },
          {
            "name": "free",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Filter to free listings only"
          },
          {
            "name": "indoor",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Filter to indoor listings only"
          },
          {
            "name": "outdoor",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Filter to outdoor listings only"
          },
          {
            "name": "maxPrice",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Maximum price in cents"
          },
          {
            "name": "category",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "kids_family",
                "recreation_sports",
                "entertainment_experiences",
                "services",
                "food_drink",
                "dog_friendly"
              ]
            },
            "description": "Filter by activity category"
          },
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Text search"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 200
            },
            "description": "Max results"
          }
        ],
        "responses": {
          "200": {
            "description": "City listings"
          },
          "404": {
            "description": "City not found"
          }
        }
      }
    },
    "/api/v1/search": {
      "get": {
        "operationId": "searchListings",
        "summary": "Natural language search across all cities",
        "description": "Search for activities using natural language. Parses constraints like price, indoor/outdoor, age, time, and city.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Natural language query"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20,
              "maximum": 100
            },
            "description": "Max results"
          }
        ],
        "responses": {
          "200": {
            "description": "Search results"
          },
          "400": {
            "description": "Missing query parameter"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "CitySafetySummary": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "New York"
          },
          "state": {
            "type": "string",
            "example": "New York"
          },
          "slug": {
            "type": "string",
            "example": "new-york"
          },
          "stateSlug": {
            "type": "string",
            "example": "new-york"
          },
          "population": {
            "type": "integer",
            "example": 8336817
          },
          "grade": {
            "type": "string",
            "example": "B-"
          },
          "riskLevel": {
            "type": "string",
            "enum": [
              "low",
              "below_average",
              "moderate",
              "elevated",
              "high",
              "very_high"
            ],
            "example": "moderate"
          },
          "riskLabel": {
            "type": "string",
            "example": "Moderate"
          },
          "crimeRatePer1K": {
            "type": "number",
            "example": 19.8
          },
          "violentRate": {
            "type": "number",
            "example": 380
          },
          "propertyRate": {
            "type": "number",
            "example": 1600
          },
          "nationalPercentile": {
            "type": "integer",
            "example": 54
          },
          "url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "CrimeBreakdown": {
        "type": "object",
        "properties": {
          "murder": {
            "type": "number",
            "description": "Per 100K residents"
          },
          "assault": {
            "type": "number"
          },
          "robbery": {
            "type": "number"
          },
          "burglary": {
            "type": "number"
          },
          "theft": {
            "type": "number"
          },
          "vehicleTheft": {
            "type": "number"
          }
        }
      },
      "CitySafetyProfile": {
        "type": "object",
        "properties": {
          "dataYear": {
            "type": "integer"
          },
          "lastUpdated": {
            "type": "string"
          },
          "source": {
            "type": "string"
          },
          "sourceUrl": {
            "type": "string",
            "format": "uri"
          },
          "city": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "state": {
                "type": "string"
              },
              "slug": {
                "type": "string"
              },
              "stateSlug": {
                "type": "string"
              },
              "population": {
                "type": "integer"
              }
            }
          },
          "safety": {
            "type": "object",
            "properties": {
              "grade": {
                "type": "string"
              },
              "riskLevel": {
                "type": "string"
              },
              "riskLabel": {
                "type": "string"
              },
              "violentGrade": {
                "type": "string"
              },
              "violentRisk": {
                "type": "string"
              },
              "propertyGrade": {
                "type": "string"
              },
              "propertyRisk": {
                "type": "string"
              },
              "crimeRatePer1K": {
                "type": "number"
              },
              "violentCrimeRate": {
                "type": "number"
              },
              "propertyCrimeRate": {
                "type": "number"
              },
              "nationalPercentile": {
                "type": "integer"
              },
              "statePercentile": {
                "type": "integer"
              },
              "trend": {
                "type": "string",
                "enum": [
                  "improving",
                  "stable",
                  "declining"
                ]
              },
              "victimOdds": {
                "type": "string",
                "example": "1 in 47"
              }
            }
          },
          "breakdown": {
            "$ref": "#/components/schemas/CrimeBreakdown"
          },
          "summary": {
            "type": "string"
          },
          "faqs": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "question": {
                  "type": "string"
                },
                "answer": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "ComparisonCityData": {
        "type": "object",
        "properties": {
          "city": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "state": {
                "type": "string"
              },
              "slug": {
                "type": "string"
              },
              "stateSlug": {
                "type": "string"
              },
              "population": {
                "type": "integer"
              }
            }
          },
          "safety": {
            "type": "object",
            "properties": {
              "grade": {
                "type": "string"
              },
              "riskLevel": {
                "type": "string"
              },
              "riskLabel": {
                "type": "string"
              },
              "violentGrade": {
                "type": "string"
              },
              "propertyGrade": {
                "type": "string"
              },
              "crimeRatePer1K": {
                "type": "number"
              },
              "violentCrimeRate": {
                "type": "number"
              },
              "propertyCrimeRate": {
                "type": "number"
              },
              "nationalPercentile": {
                "type": "integer"
              },
              "trend": {
                "type": "string"
              },
              "victimOdds": {
                "type": "string"
              }
            }
          },
          "breakdown": {
            "$ref": "#/components/schemas/CrimeBreakdown"
          }
        }
      },
      "Listing": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "address": {
            "type": "string"
          },
          "price": {
            "type": "string",
            "nullable": true
          },
          "priceCents": {
            "type": "integer",
            "nullable": true
          },
          "hours": {
            "type": "string",
            "nullable": true
          },
          "neighborhood": {
            "type": "string",
            "nullable": true
          },
          "indoor": {
            "type": "boolean",
            "nullable": true
          },
          "description": {
            "type": "string"
          },
          "website": {
            "type": "string",
            "format": "uri",
            "nullable": true
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "lastVerified": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "source": {
            "type": "string",
            "example": "citycheck.live"
          }
        }
      }
    }
  }
}