API Documentation - Endpoints & Examples

Search states by city

Overview

This endpoint allows you to find the state that contains a specific city. It is useful for reverse lookups when you know the city name but need to determine its parent state. Note that many cities around the world share the same name, so the API may return multiple results from different countries.

Country Data API provides detailed information about +200 different countries

Authentication

All API requests require authentication using an API key. Include your API key as a query parameter in each request:

?apikey=YOUR_API_KEY

You can obtain an API key by registering at CountryDataAPI.


Request

HTTP GET

https://api.countrydataapi.com/v1/states/city

Returns the state that contains that city.

Some examples of the structure

Country: USA, State: Colorado, City: Denver

Country: Spain, State: Comunidad Valenciana, City: Valencia

Relevant Information

Keep in mind that there are many cities with the same name

According to the requested fields, there will be 3 types of requests:

  • BASIC: Returns the fields id, state_name, lang Each state will cost 1 token

  • NORMAL: Returns the field state_cities [All IDs and names of cities in the state] Each city will cost 1 token

  • ADVANCED: Returns the field state_zip_codes [All postal codes of the city] Each postal code costs 1 token

Query Params


Parameter Type Description
apikey required, token Account authentication key
city required, string Name of the city found in the state
limitToken optional, number 1000 (default). Maximum number of tokens you want to spend on this request
fields optional, string id,lang,state_name (default). Expected fields in the response
lang optional, lang en (default). Expected language of the response

Response

Sample Response

[
  {
    "id": "8dd25479-067a-43b0-ac4a-8e7faf2bcafb",
    "state_name": "Takhar",
    "lang": "en",
    "state_cities": [
      {
        "id": "8dd25476-067a-43b0-ac4b-8e7faf2bcbfb",
        "city_name": "City"
      }
    ],
    "state_zip_codes": [
      "00000",
      "00001"
    ]
  }
]

Code Examples

JavaScript (Fetch)

const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://api.countrydataapi.com/v1/states/city';

async function getStateByCity(cityName) {
  try {
    const params = new URLSearchParams({
      apikey: API_KEY,
      city: cityName,
      lang: 'en',
      fields: 'id,state_name,lang'
    });

    const response = await fetch(`${BASE_URL}?${params}`);

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const states = await response.json();
    console.log(`States containing city "${cityName}":`, states);
    return states;
  } catch (error) {
    console.error('Error fetching state by city:', error);
    throw error;
  }
}

// Usage - Note: Multiple states may be returned if city name exists in different regions
getStateByCity('Denver');
getStateByCity('Valencia');
getStateByCity('Springfield'); // Common city name - will return multiple results

JavaScript (Axios)

import axios from 'axios';

const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://api.countrydataapi.com/v1/states/city';

async function getStateByCity(cityName) {
  try {
    const response = await axios.get(BASE_URL, {
      params: {
        apikey: API_KEY,
        city: cityName,
        lang: 'en',
        fields: 'id,state_name,lang'
      }
    });

    console.log(`States containing city "${cityName}":`, response.data);
    return response.data;
  } catch (error) {
    if (axios.isAxiosError(error)) {
      console.error('API Error:', error.response?.data || error.message);
    }
    throw error;
  }
}

// Usage
getStateByCity('Miami');

React

import { useState, useEffect } from 'react';

const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://api.countrydataapi.com/v1/states/city';

function StateByCity({ cityName }) {
  const [states, setStates] = useState([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchStateByCity = async () => {
      if (!cityName) {
        setStates([]);
        return;
      }

      try {
        setLoading(true);
        setError(null);

        const params = new URLSearchParams({
          apikey: API_KEY,
          city: cityName,
          lang: 'en',
          fields: 'id,state_name,lang'
        });

        const response = await fetch(`${BASE_URL}?${params}`);

        if (!response.ok) {
          throw new Error('Failed to fetch state');
        }

        const data = await response.json();
        setStates(data);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };

    fetchStateByCity();
  }, [cityName]);

  if (loading) return <div>Searching for states...</div>;
  if (error) return <div>Error: {error}</div>;

  return (
    <div>
      <h2>States containing "{cityName}"</h2>
      {states.length === 0 ? (
        <p>No states found for this city</p>
      ) : (
        <>
          <p>Found {states.length} state(s)</p>
          <ul>
            {states.map((state) => (
              <li key={state.id}>
                {state.state_name}
              </li>
            ))}
          </ul>
        </>
      )}
    </div>
  );
}

// City search component with input
function CityStateSearch() {
  const [cityInput, setCityInput] = useState('');
  const [searchCity, setSearchCity] = useState('');

  const handleSearch = (e) => {
    e.preventDefault();
    setSearchCity(cityInput);
  };

  return (
    <div>
      <form onSubmit={handleSearch}>
        <input
          type="text"
          value={cityInput}
          onChange={(e) => setCityInput(e.target.value)}
          placeholder="Enter city name..."
        />
        <button type="submit">Search</button>
      </form>

      {searchCity && <StateByCity cityName={searchCity} />}
    </div>
  );
}

export default CityStateSearch;

Vue 3

<template>
  <div>
    <div v-if="loading">Searching for states...</div>
    <div v-else-if="error">Error: {{ error }}</div>
    <div v-else>
      <h2>States containing "{{ city }}"</h2>
      <p v-if="states.length === 0">No states found for this city</p>
      <div v-else>
        <p>Found {{ states.length }} state(s)</p>
        <ul>
          <li v-for="state in states" :key="state.id">
            {{ state.state_name }}
          </li>
        </ul>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, watch, onMounted } from 'vue';

const props = defineProps({
  city: {
    type: String,
    required: true
  }
});

const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://api.countrydataapi.com/v1/states/city';

const states = ref([]);
const loading = ref(false);
const error = ref(null);

const fetchStateByCity = async () => {
  if (!props.city) {
    states.value = [];
    return;
  }

  try {
    loading.value = true;
    error.value = null;

    const params = new URLSearchParams({
      apikey: API_KEY,
      city: props.city,
      lang: 'en',
      fields: 'id,state_name,lang'
    });

    const response = await fetch(`${BASE_URL}?${params}`);

    if (!response.ok) {
      throw new Error('Failed to fetch state');
    }

    states.value = await response.json();
  } catch (err) {
    error.value = err.message;
  } finally {
    loading.value = false;
  }
};

watch(() => props.city, fetchStateByCity);
onMounted(fetchStateByCity);
</script>

Angular

import { Component, Input, OnInit, OnChanges } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';

interface State {
  id: string;
  state_name: string;
  lang: string;
  state_cities?: Array<{ id: string; city_name: string }>;
  state_zip_codes?: string[];
}

@Component({
  selector: 'app-state-by-city',
  standalone: true,
  imports: [CommonModule, FormsModule],
  template: `
    <div>
      <div *ngIf="loading">Searching for states...</div>
      <div *ngIf="error">Error: {{ error }}</div>
      <div *ngIf="!loading && !error">
        <h2>States containing "{{ city }}"</h2>
        <p *ngIf="states.length === 0">No states found for this city</p>
        <div *ngIf="states.length > 0">
          <p>Found {{ states.length }} state(s)</p>
          <ul>
            <li *ngFor="let state of states">{{ state.state_name }}</li>
          </ul>
        </div>
      </div>
    </div>
  `
})
export class StateByCityComponent implements OnInit, OnChanges {
  @Input() city!: string;

  private readonly API_KEY = 'YOUR_API_KEY';
  private readonly BASE_URL = 'https://api.countrydataapi.com/v1/states/city';

  states: State[] = [];
  loading = false;
  error: string | null = null;

  constructor(private http: HttpClient) {}

  ngOnInit(): void {
    this.fetchStateByCity();
  }

  ngOnChanges(): void {
    this.fetchStateByCity();
  }

  private fetchStateByCity(): void {
    if (!this.city) {
      this.states = [];
      return;
    }

    this.loading = true;
    this.error = null;

    const params = new HttpParams()
      .set('apikey', this.API_KEY)
      .set('city', this.city)
      .set('lang', 'en')
      .set('fields', 'id,state_name,lang');

    this.http.get<State[]>(this.BASE_URL, { params }).subscribe({
      next: (data) => {
        this.states = data;
        this.loading = false;
      },
      error: (err) => {
        this.error = err.message;
        this.loading = false;
      }
    });
  }
}

// Search component with input
@Component({
  selector: 'app-city-state-search',
  standalone: true,
  imports: [CommonModule, FormsModule, StateByCityComponent],
  template: `
    <div>
      <form (ngSubmit)="search()">
        <input
          type="text"
          [(ngModel)]="cityInput"
          name="city"
          placeholder="Enter city name..."
        />
        <button type="submit">Search</button>
      </form>

      <app-state-by-city
        *ngIf="searchCity"
        [city]="searchCity"
      ></app-state-by-city>
    </div>
  `
})
export class CityStateSearchComponent {
  cityInput = '';
  searchCity = '';

  search(): void {
    this.searchCity = this.cityInput;
  }
}

PHP

<?php

$apiKey = 'YOUR_API_KEY';
$baseUrl = 'https://api.countrydataapi.com/v1/states/city';

function getStateByCity($cityName, $apiKey) {
    $baseUrl = 'https://api.countrydataapi.com/v1/states/city';

    $params = http_build_query([
        'apikey' => $apiKey,
        'city' => $cityName,
        'lang' => 'en',
        'fields' => 'id,state_name,lang'
    ]);

    $url = $baseUrl . '?' . $params;

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($httpCode !== 200) {
        throw new Exception("HTTP Error: $httpCode");
    }

    return json_decode($response, true);
}

// Usage
try {
    $cityName = 'Denver';
    $states = getStateByCity($cityName, $apiKey);

    echo "States containing '$cityName':\n";
    echo "Found " . count($states) . " state(s)\n\n";

    foreach ($states as $state) {
        echo "- " . $state['state_name'] . " (ID: " . $state['id'] . ")\n";
    }
} catch (Exception $e) {
    echo "Error: " . $e->getMessage() . "\n";
}

// Handle multiple cities with the same name
function findStatesForCity($cityName, $apiKey) {
    $states = getStateByCity($cityName, $apiKey);

    if (empty($states)) {
        return "No states found for city: $cityName";
    }

    if (count($states) === 1) {
        return "City '$cityName' is located in: " . $states[0]['state_name'];
    }

    $stateNames = array_map(function($s) {
        return $s['state_name'];
    }, $states);

    return "City '$cityName' exists in multiple states: " . implode(', ', $stateNames);
}

echo findStatesForCity('Springfield', $apiKey); // Will show multiple states
?>

Python

import requests

API_KEY = 'YOUR_API_KEY'
BASE_URL = 'https://api.countrydataapi.com/v1/states/city'

def get_state_by_city(city_name):
    """Find the state(s) containing a specific city."""
    params = {
        'apikey': API_KEY,
        'city': city_name,
        'lang': 'en',
        'fields': 'id,state_name,lang'
    }

    try:
        response = requests.get(BASE_URL, params=params)
        response.raise_for_status()

        states = response.json()
        return states
    except requests.exceptions.RequestException as e:
        print(f'Error fetching state by city: {e}')
        raise

# Usage
if __name__ == '__main__':
    city = 'Denver'
    states = get_state_by_city(city)

    print(f"States containing '{city}':")
    print(f"Found {len(states)} state(s)\n")

    for state in states:
        print(f"  - {state['state_name']} (ID: {state['id']})")

    # Example with a common city name
    print("\n--- Searching for 'Springfield' (common name) ---")
    springfield_states = get_state_by_city('Springfield')
    print(f"Found {len(springfield_states)} states with city named 'Springfield'")


# Async version with aiohttp
import aiohttp
import asyncio

async def get_state_by_city_async(city_name):
    """Find state by city asynchronously."""
    params = {
        'apikey': API_KEY,
        'city': city_name,
        'lang': 'en',
        'fields': 'id,state_name,lang'
    }

    async with aiohttp.ClientSession() as session:
        async with session.get(BASE_URL, params=params) as response:
            if response.status == 200:
                return await response.json()
            else:
                raise Exception(f'HTTP Error: {response.status}')

# Search for multiple cities concurrently
async def search_multiple_cities(cities):
    """Search states for multiple cities concurrently."""
    tasks = [get_state_by_city_async(city) for city in cities]
    results = await asyncio.gather(*tasks, return_exceptions=True)
    return dict(zip(cities, results))

# Usage
# cities = ['Denver', 'Miami', 'Seattle', 'Austin']
# results = asyncio.run(search_multiple_cities(cities))
# for city, states in results.items():
#     print(f"{city}: {[s['state_name'] for s in states]}")

cURL

# Search state by city name
curl -X GET "https://api.countrydataapi.com/v1/states/city?apikey=YOUR_API_KEY&city=Denver&lang=en&fields=id,state_name,lang"

# Search for Valencia (exists in multiple countries)
curl -X GET "https://api.countrydataapi.com/v1/states/city?apikey=YOUR_API_KEY&city=Valencia&lang=en"

# With pretty-printed JSON output
curl -X GET "https://api.countrydataapi.com/v1/states/city?apikey=YOUR_API_KEY&city=Miami&lang=en" | json_pp

# Search for a common city name (returns multiple results)
curl -X GET "https://api.countrydataapi.com/v1/states/city?apikey=YOUR_API_KEY&city=Springfield&lang=en"

# Get detailed state info including cities
curl -X GET "https://api.countrydataapi.com/v1/states/city?apikey=YOUR_API_KEY&city=Boston&fields=id,state_name,state_cities"

# Save response to file
curl -X GET "https://api.countrydataapi.com/v1/states/city?apikey=YOUR_API_KEY&city=Seattle&lang=en" -o seattle_state.json

Error Handling

The API may return the following error responses:

Status Code Description
400 Bad Request - Invalid parameters or missing city
401 Unauthorized - Invalid or missing API key
403 Forbidden - Insufficient permissions or token balance
404 Not Found - City not found
429 Too Many Requests - Rate limit exceeded
500 Internal Server Error

Error Response Example

{
  "statusCode": 404,
  "message": "City not found",
  "error": "Not Found"
}

Important Notes

  • Duplicate City Names: Many cities share the same name across different states and countries. For example, "Springfield" exists in multiple US states. The API will return all matching states.
  • Disambiguation: If you receive multiple results, consider using additional parameters or filtering by country to narrow down results.
  • Case Sensitivity: City names are case-insensitive, but using proper capitalization is recommended.