API Documentation - Endpoints & Examples

Cities by Country

Overview

This endpoint retrieves all cities that belong to a specific country. It is perfect for building country-city selectors, filtering geographical data by country, or when you need to display all cities within a particular nation.

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/cities/country

Returns all cities from a country

Every 5 cities returned will consume 1 token

Query Params


Parameter Type Description
apikey required, token Account authentication key
country required, id or string Country ID or name
limitToken optional, number 1000 (default). Maximum number of tokens you want to spend on this request
lang optional, lang en (default). Expected language of the response

Response

Response Example

[
  {
    "id": "d54ba796-1136-4776-9776-537fd5a857c9",
    "lang": "en",
    "city_name": "Bala Morghab"
  }
]

Code Examples

JavaScript (Fetch)

const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://api.countrydataapi.com/v1/cities/country';

async function getCitiesByCountry(countryName) {
  try {
    const params = new URLSearchParams({
      apikey: API_KEY,
      country: countryName,
      lang: 'en'
    });

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

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

    const cities = await response.json();
    console.log(`Cities in ${countryName}:`, cities.length);
    return cities;
  } catch (error) {
    console.error('Error fetching cities by country:', error);
    throw error;
  }
}

// Usage
getCitiesByCountry('United States');
getCitiesByCountry('Spain');
getCitiesByCountry('Germany');

JavaScript (Axios)

import axios from 'axios';

const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://api.countrydataapi.com/v1/cities/country';

async function getCitiesByCountry(countryName, limitToken = 1000) {
  try {
    const response = await axios.get(BASE_URL, {
      params: {
        apikey: API_KEY,
        country: countryName,
        lang: 'en',
        limitToken: limitToken
      }
    });

    console.log(`Cities in ${countryName}:`, response.data.length);
    return response.data;
  } catch (error) {
    if (axios.isAxiosError(error)) {
      console.error('API Error:', error.response?.data || error.message);
    }
    throw error;
  }
}

// Usage
getCitiesByCountry('France');
getCitiesByCountry('Japan', 500);

React

import { useState, useEffect } from 'react';

const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://api.countrydataapi.com/v1/cities/country';

function CitiesByCountry({ country }) {
  const [cities, setCities] = useState([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchCities = async () => {
      if (!country) {
        setCities([]);
        return;
      }

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

        const params = new URLSearchParams({
          apikey: API_KEY,
          country: country,
          lang: 'en'
        });

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

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

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

    fetchCities();
  }, [country]);

  if (loading) return <div>Loading cities...</div>;
  if (error) return <div>Error: {error}</div>;

  return (
    <div>
      <h2>Cities in {country}</h2>
      <p>Total: {cities.length} cities</p>
      <ul>
        {cities.slice(0, 50).map((city) => (
          <li key={city.id}>{city.city_name}</li>
        ))}
      </ul>
      {cities.length > 50 && (
        <p>...and {cities.length - 50} more cities</p>
      )}
    </div>
  );
}

// Country selector with cities list
function CountryCityBrowser() {
  const [selectedCountry, setSelectedCountry] = useState('');
  const [cities, setCities] = useState([]);
  const [loading, setLoading] = useState(false);
  const [searchTerm, setSearchTerm] = useState('');

  const countries = ['United States', 'Spain', 'Germany', 'France', 'Japan', 'Mexico', 'Canada'];

  useEffect(() => {
    if (!selectedCountry) {
      setCities([]);
      return;
    }

    const fetchCities = async () => {
      setLoading(true);
      const params = new URLSearchParams({
        apikey: API_KEY,
        country: selectedCountry,
        lang: 'en'
      });

      try {
        const response = await fetch(`${BASE_URL}?${params}`);
        const data = await response.json();
        setCities(data);
      } catch (err) {
        console.error(err);
      } finally {
        setLoading(false);
      }
    };

    fetchCities();
  }, [selectedCountry]);

  const filteredCities = cities.filter(city =>
    city.city_name.toLowerCase().includes(searchTerm.toLowerCase())
  );

  return (
    <div>
      <select
        value={selectedCountry}
        onChange={(e) => setSelectedCountry(e.target.value)}
      >
        <option value="">Select Country</option>
        {countries.map((c) => (
          <option key={c} value={c}>{c}</option>
        ))}
      </select>

      {selectedCountry && (
        <>
          <input
            type="text"
            value={searchTerm}
            onChange={(e) => setSearchTerm(e.target.value)}
            placeholder="Filter cities..."
          />
          <p>Showing {filteredCities.length} of {cities.length} cities</p>
        </>
      )}

      {loading ? (
        <p>Loading...</p>
      ) : (
        <ul>
          {filteredCities.slice(0, 100).map((city) => (
            <li key={city.id}>{city.city_name}</li>
          ))}
        </ul>
      )}
    </div>
  );
}

export default CitiesByCountry;

Vue 3

<template>
  <div>
    <div v-if="loading">Loading cities...</div>
    <div v-else-if="error">Error: {{ error }}</div>
    <div v-else>
      <h2>Cities in {{ country }}</h2>
      <p>Total: {{ cities.length }} cities</p>
      <input
        v-model="searchTerm"
        type="text"
        placeholder="Filter cities..."
      />
      <ul>
        <li v-for="city in filteredCities" :key="city.id">
          {{ city.city_name }}
        </li>
      </ul>
    </div>
  </div>
</template>

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

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

const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://api.countrydataapi.com/v1/cities/country';

const cities = ref([]);
const loading = ref(false);
const error = ref(null);
const searchTerm = ref('');

const filteredCities = computed(() => {
  if (!searchTerm.value) {
    return cities.value.slice(0, 100);
  }
  return cities.value
    .filter(city =>
      city.city_name.toLowerCase().includes(searchTerm.value.toLowerCase())
    )
    .slice(0, 100);
});

const fetchCities = async () => {
  if (!props.country) {
    cities.value = [];
    return;
  }

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

    const params = new URLSearchParams({
      apikey: API_KEY,
      country: props.country,
      lang: 'en'
    });

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

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

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

watch(() => props.country, fetchCities);
onMounted(fetchCities);
</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 City {
  id: string;
  city_name: string;
  lang: string;
}

@Component({
  selector: 'app-cities-by-country',
  standalone: true,
  imports: [CommonModule, FormsModule],
  template: `
    <div>
      <div *ngIf="loading">Loading cities...</div>
      <div *ngIf="error">Error: {{ error }}</div>
      <div *ngIf="!loading && !error">
        <h2>Cities in {{ country }}</h2>
        <p>Total: {{ cities.length }} cities</p>
        <input
          type="text"
          [(ngModel)]="searchTerm"
          placeholder="Filter cities..."
        />
        <ul>
          <li *ngFor="let city of filteredCities">{{ city.city_name }}</li>
        </ul>
      </div>
    </div>
  `
})
export class CitiesByCountryComponent implements OnInit, OnChanges {
  @Input() country!: string;

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

  cities: City[] = [];
  loading = false;
  error: string | null = null;
  searchTerm = '';

  constructor(private http: HttpClient) {}

  get filteredCities(): City[] {
    if (!this.searchTerm) {
      return this.cities.slice(0, 100);
    }
    return this.cities
      .filter(city =>
        city.city_name.toLowerCase().includes(this.searchTerm.toLowerCase())
      )
      .slice(0, 100);
  }

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

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

  private fetchCities(): void {
    if (!this.country) {
      this.cities = [];
      return;
    }

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

    const params = new HttpParams()
      .set('apikey', this.API_KEY)
      .set('country', this.country)
      .set('lang', 'en');

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

PHP

<?php

$apiKey = 'YOUR_API_KEY';
$baseUrl = 'https://api.countrydataapi.com/v1/cities/country';

function getCitiesByCountry($countryName, $apiKey, $limitToken = 1000) {
    $baseUrl = 'https://api.countrydataapi.com/v1/cities/country';

    $params = http_build_query([
        'apikey' => $apiKey,
        'country' => $countryName,
        'lang' => 'en',
        'limitToken' => $limitToken
    ]);

    $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 {
    $countryName = 'United States';
    $cities = getCitiesByCountry($countryName, $apiKey);

    echo "Cities in $countryName:\n";
    echo "Total: " . count($cities) . " cities\n\n";

    // Display first 20 cities
    foreach (array_slice($cities, 0, 20) as $city) {
        echo "- " . $city['city_name'] . "\n";
    }

    if (count($cities) > 20) {
        echo "... and " . (count($cities) - 20) . " more cities\n";
    }
} catch (Exception $e) {
    echo "Error: " . $e->getMessage() . "\n";
}

// Calculate token usage
function calculateTokenUsage($cityCount) {
    return ceil($cityCount / 5);
}

$cities = getCitiesByCountry('Spain', $apiKey);
echo "\nCities in Spain: " . count($cities) . "\n";
echo "Tokens consumed: " . calculateTokenUsage(count($cities)) . "\n";

// Search cities by name within a country
function searchCitiesInCountry($countryName, $searchTerm, $apiKey) {
    $cities = getCitiesByCountry($countryName, $apiKey);

    return array_filter($cities, function($city) use ($searchTerm) {
        return stripos($city['city_name'], $searchTerm) !== false;
    });
}

$results = searchCitiesInCountry('Germany', 'Berlin', $apiKey);
print_r($results);
?>

Python

import requests

API_KEY = 'YOUR_API_KEY'
BASE_URL = 'https://api.countrydataapi.com/v1/cities/country'

def get_cities_by_country(country_name, limit_token=1000):
    """Fetch all cities for a specific country."""
    params = {
        'apikey': API_KEY,
        'country': country_name,
        'lang': 'en',
        'limitToken': limit_token
    }

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

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

def calculate_token_usage(city_count):
    """Calculate tokens consumed (5 cities = 1 token)."""
    return (city_count + 4) // 5

def search_cities_in_country(country_name, search_term):
    """Search for cities containing a specific term within a country."""
    cities = get_cities_by_country(country_name)
    return [
        city for city in cities
        if search_term.lower() in city['city_name'].lower()
    ]

# Usage
if __name__ == '__main__':
    country = 'United States'
    cities = get_cities_by_country(country)

    print(f"Cities in {country}:")
    print(f"Total: {len(cities)} cities")
    print(f"Tokens consumed: {calculate_token_usage(len(cities))}")
    print("\nFirst 10 cities:")

    for city in cities[:10]:
        print(f"  - {city['city_name']}")

    # Search example
    print("\nSearching for 'New' in US cities:")
    results = search_cities_in_country('United States', 'New')
    for city in results[:5]:
        print(f"  - {city['city_name']}")


# Async version with aiohttp
import aiohttp
import asyncio

async def get_cities_by_country_async(country_name):
    """Fetch cities by country asynchronously."""
    params = {
        'apikey': API_KEY,
        'country': country_name,
        'lang': 'en'
    }

    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}')

# Fetch cities for multiple countries concurrently
async def get_cities_for_multiple_countries(countries):
    """Fetch cities for multiple countries concurrently."""
    tasks = [get_cities_by_country_async(country) for country in countries]
    results = await asyncio.gather(*tasks, return_exceptions=True)
    return dict(zip(countries, results))

# Usage
# countries = ['United States', 'Spain', 'Germany', 'France']
# results = asyncio.run(get_cities_for_multiple_countries(countries))
# for country, cities in results.items():
#     if isinstance(cities, list):
#         print(f"{country}: {len(cities)} cities")

cURL

# Get cities for United States
curl -X GET "https://api.countrydataapi.com/v1/cities/country?apikey=YOUR_API_KEY&country=United%20States&lang=en"

# Get cities for Spain
curl -X GET "https://api.countrydataapi.com/v1/cities/country?apikey=YOUR_API_KEY&country=Spain&lang=en"

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

# Limit token usage
curl -X GET "https://api.countrydataapi.com/v1/cities/country?apikey=YOUR_API_KEY&country=France&limitToken=500"

# Get cities by country ID
curl -X GET "https://api.countrydataapi.com/v1/cities/country?apikey=YOUR_API_KEY&country=8dd25479-067a-43b0-ac4a-8e7faf2bcafb&lang=en"

# Save response to file
curl -X GET "https://api.countrydataapi.com/v1/cities/country?apikey=YOUR_API_KEY&country=Japan&lang=en" -o japan_cities.json

# Get cities for multiple countries
for country in "United States" Spain Germany France; do
  echo "Country: $country"
  curl -s "https://api.countrydataapi.com/v1/cities/country?apikey=YOUR_API_KEY&country=$country" | json_pp | head -20
  echo ""
done

# Count cities per country
for country in "United States" Spain Germany; do
  count=$(curl -s "https://api.countrydataapi.com/v1/cities/country?apikey=YOUR_API_KEY&country=$country" | jq '. | length')
  echo "$country: $count cities"
done

Error Handling

The API may return the following error responses:

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

Error Response Example

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

Token Consumption

Every 5 cities returned will consume 1 token. For example:

  • 50 cities = 10 tokens
  • 100 cities = 20 tokens
  • 500 cities = 100 tokens

Use the limitToken parameter to control your token usage, especially when querying countries with many cities.

Important Notes

  • Large Countries: Countries like the United States, China, or Russia may have thousands of cities. Use limitToken to manage costs.
  • Country Name Variations: Use the official English name of the country for best results.
  • Performance: For countries with many cities, consider caching results client-side to reduce API calls.