Complete Integration Examples
Basic API Client Setup
Set up a robust API client with proper authentication and error handling:class CountryStateCityAPI {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseURL = 'https://api.countrystatecity.in/v1';
}
async request(endpoint) {
try {
const response = await fetch(`${this.baseURL}${endpoint}`, {
headers: {
'X-CSCAPI-KEY': this.apiKey,
'Content-Type': 'application/json'
}
});
if (!response.ok) {
if (response.status === 401) {
throw new Error('Invalid API key. Please check your credentials.');
} else if (response.status === 429) {
throw new Error('Too many requests. Please try again later.');
} else {
throw new Error(`API error: ${response.status}`);
}
}
return await response.json();
} catch (error) {
console.error('API request failed:', error);
throw error;
}
}
async getCountries() {
return await this.request('/countries');
}
async getStates(countryCode) {
return await this.request(`/countries/${countryCode}/states`);
}
async getCities(countryCode, stateCode = null) {
const endpoint = stateCode
? `/countries/${countryCode}/states/${stateCode}/cities`
: `/countries/${countryCode}/cities`;
return await this.request(endpoint);
}
async getCountryDetails(countryCode) {
return await this.request(`/countries/${countryCode}`);
}
}
// Usage
const api = new CountryStateCityAPI('YOUR_API_KEY');
const countries = await api.getCountries();
const usStates = await api.getStates('US');
const californiaCities = await api.getCities('US', 'CA');
import requests
from typing import Optional, Dict, List
class CountryStateCityAPI:
def __init__(self, api_key: str):
self.api_key = api_key
self.base_url = 'https://api.countrystatecity.in/v1'
self.session = requests.Session()
self.session.headers.update({
'X-CSCAPI-KEY': api_key,
'Content-Type': 'application/json'
})
def _request(self, endpoint: str) -> Dict:
"""Make authenticated request to API endpoint"""
try:
response = self.session.get(f"{self.base_url}{endpoint}")
if response.status_code == 401:
raise ValueError('Invalid API key. Please check your credentials.')
elif response.status_code == 429:
raise ValueError('Too many requests. Please try again later.')
elif not response.ok:
raise ValueError(f'API error: {response.status_code}')
return response.json()
except requests.exceptions.RequestException as e:
raise ConnectionError(f'Request failed: {str(e)}')
def get_countries(self) -> List[Dict]:
"""Get all countries"""
return self._request('/countries')
def get_states(self, country_code: str) -> List[Dict]:
"""Get states for a specific country"""
return self._request(f'/countries/{country_code}/states')
def get_cities(self, country_code: str, state_code: Optional[str] = None) -> List[Dict]:
"""Get cities for a country, optionally filtered by state"""
endpoint = f'/countries/{country_code}/states/{state_code}/cities' if state_code else f'/countries/{country_code}/cities'
return self._request(endpoint)
def get_country_details(self, country_code: str) -> Dict:
"""Get detailed information for a specific country"""
return self._request(f'/countries/{country_code}')
# Usage
api = CountryStateCityAPI('YOUR_API_KEY')
countries = api.get_countries()
us_states = api.get_states('US')
california_cities = api.get_cities('US', 'CA')
<?php
class CountryStateCityAPI {
private $apiKey;
private $baseUrl = 'https://api.countrystatecity.in/v1';
public function __construct($apiKey) {
$this->apiKey = $apiKey;
}
private function request($endpoint) {
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => $this->baseUrl . $endpoint,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-CSCAPI-KEY: ' . $this->apiKey,
'Content-Type: application/json'
],
CURLOPT_TIMEOUT => 30
]);
$response = curl_exec($curl);
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if (curl_error($curl)) {
curl_close($curl);
throw new Exception('Request failed: ' . curl_error($curl));
}
curl_close($curl);
if ($httpCode === 401) {
throw new Exception('Invalid API key. Please check your credentials.');
} elseif ($httpCode === 429) {
throw new Exception('Too many requests. Please try again later.');
} elseif ($httpCode !== 200) {
throw new Exception('API error: ' . $httpCode);
}
return json_decode($response, true);
}
public function getCountries() {
return $this->request('/countries');
}
public function getStates($countryCode) {
return $this->request("/countries/{$countryCode}/states");
}
public function getCities($countryCode, $stateCode = null) {
$endpoint = $stateCode
? "/countries/{$countryCode}/states/{$stateCode}/cities"
: "/countries/{$countryCode}/cities";
return $this->request($endpoint);
}
}
// Usage
$api = new CountryStateCityAPI('YOUR_API_KEY');
$countries = $api->getCountries();
$usStates = $api->getStates('US');
?>
import java.io.IOException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
import java.time.Duration;
public class CountryStateCityAPI {
private final String apiKey;
private final String baseUrl = "https://api.countrystatecity.in/v1";
private final HttpClient httpClient;
public CountryStateCityAPI(String apiKey) {
this.apiKey = apiKey;
this.httpClient = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(30))
.build();
}
private String request(String endpoint) throws IOException, InterruptedException {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(baseUrl + endpoint))
.header("X-CSCAPI-KEY", apiKey)
.header("Content-Type", "application/json")
.GET()
.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 401) {
throw new RuntimeException("Invalid API key. Please check your credentials.");
} else if (response.statusCode() == 429) {
throw new RuntimeException("Too many requests. Please try again later.");
} else if (response.statusCode() != 200) {
throw new RuntimeException("API error: " + response.statusCode());
}
return response.body();
}
public String getCountries() throws IOException, InterruptedException {
return request("/countries");
}
public String getStates(String countryCode) throws IOException, InterruptedException {
return request("/countries/" + countryCode + "/states");
}
}
// Usage
CountryStateCityAPI api = new CountryStateCityAPI("YOUR_API_KEY");
String countries = api.getCountries();
using System;
using System.Net.Http;
using System.Threading.Tasks;
public class CountryStateCityAPI
{
private readonly HttpClient _httpClient;
private readonly string _baseUrl = "https://api.countrystatecity.in/v1";
public CountryStateCityAPI(string apiKey)
{
_httpClient = new HttpClient();
_httpClient.DefaultRequestHeaders.Add("X-CSCAPI-KEY", apiKey);
_httpClient.DefaultRequestHeaders.Add("Content-Type", "application/json");
_httpClient.Timeout = TimeSpan.FromSeconds(30);
}
private async Task<string> RequestAsync(string endpoint)
{
try
{
var response = await _httpClient.GetAsync($"{_baseUrl}{endpoint}");
if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
throw new UnauthorizedAccessException("Invalid API key. Please check your credentials.");
}
else if (response.StatusCode == System.Net.HttpStatusCode.TooManyRequests)
{
throw new InvalidOperationException("Too many requests. Please try again later.");
}
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
catch (HttpRequestException ex)
{
throw new Exception($"Request failed: {ex.Message}");
}
}
public async Task<string> GetCountriesAsync()
{
return await RequestAsync("/countries");
}
public async Task<string> GetStatesAsync(string countryCode)
{
return await RequestAsync($"/countries/{countryCode}/states");
}
public void Dispose()
{
_httpClient?.Dispose();
}
}
// Usage
var api = new CountryStateCityAPI("YOUR_API_KEY");
var countries = await api.GetCountriesAsync();
package main
import (
"fmt"
"io"
"net/http"
"time"
)
type CountryStateCityAPI struct {
apiKey string
baseURL string
client *http.Client
}
func NewCountryStateCityAPI(apiKey string) *CountryStateCityAPI {
return &CountryStateCityAPI{
apiKey: apiKey,
baseURL: "https://api.countrystatecity.in/v1",
client: &http.Client{
Timeout: 30 * time.Second,
},
}
}
func (api *CountryStateCityAPI) request(endpoint string) ([]byte, error) {
req, err := http.NewRequest("GET", api.baseURL+endpoint, nil)
if err != nil {
return nil, err
}
req.Header.Set("X-CSCAPI-KEY", api.apiKey)
req.Header.Set("Content-Type", "application/json")
resp, err := api.client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode == 401 {
return nil, fmt.Errorf("invalid API key")
} else if resp.StatusCode == 429 {
return nil, fmt.Errorf("too many requests")
} else if resp.StatusCode != 200 {
return nil, fmt.Errorf("API error: %d", resp.StatusCode)
}
return io.ReadAll(resp.Body)
}
func (api *CountryStateCityAPI) GetCountries() ([]byte, error) {
return api.request("/countries")
}
func (api *CountryStateCityAPI) GetStates(countryCode string) ([]byte, error) {
return api.request("/countries/" + countryCode + "/states")
}
// Usage
func main() {
api := NewCountryStateCityAPI("YOUR_API_KEY")
countries, err := api.GetCountries()
if err != nil {
fmt.Println("Error:", err)
}
}
require 'net/http'
require 'json'
require 'uri'
class CountryStateCityAPI
def initialize(api_key)
@api_key = api_key
@base_url = 'https://api.countrystatecity.in/v1'
end
private
def request(endpoint)
uri = URI("#{@base_url}#{endpoint}")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.read_timeout = 30
request = Net::HTTP::Get.new(uri)
request['X-CSCAPI-KEY'] = @api_key
request['Content-Type'] = 'application/json'
response = http.request(request)
case response.code.to_i
when 401
raise 'Invalid API key. Please check your credentials.'
when 429
raise 'Too many requests. Please try again later.'
when 200
JSON.parse(response.body)
else
raise "API error: #{response.code}"
end
end
public
def get_countries
request('/countries')
end
def get_states(country_code)
request("/countries/#{country_code}/states")
end
def get_cities(country_code, state_code = nil)
endpoint = state_code ?
"/countries/#{country_code}/states/#{state_code}/cities" :
"/countries/#{country_code}/cities"
request(endpoint)
end
end
# Usage
api = CountryStateCityAPI.new('YOUR_API_KEY')
countries = api.get_countries
us_states = api.get_states('US')
Real-World Use Cases
1. Complete Registration Form with Cascading Dropdowns
Build a comprehensive user registration form with dependent location selectors:import React, { useState, useEffect } from 'react';
const LocationSelector = ({ apiKey, onLocationChange }) => {
const [countries, setCountries] = useState([]);
const [states, setStates] = useState([]);
const [cities, setCities] = useState([]);
const [selectedCountry, setSelectedCountry] = useState('');
const [selectedState, setSelectedState] = useState('');
const [selectedCity, setSelectedCity] = useState('');
const [loading, setLoading] = useState(false);
const api = new CountryStateCityAPI(apiKey);
// Load countries on component mount
useEffect(() => {
const loadCountries = async () => {
try {
setLoading(true);
const countriesData = await api.getCountries();
setCountries(countriesData);
} catch (error) {
console.error('Failed to load countries:', error);
} finally {
setLoading(false);
}
};
loadCountries();
}, []);
// Load states when country changes
useEffect(() => {
if (selectedCountry) {
const loadStates = async () => {
try {
setLoading(true);
const statesData = await api.getStates(selectedCountry);
setStates(statesData);
setSelectedState(''); // Reset state selection
setCities([]); // Clear cities
setSelectedCity(''); // Reset city selection
} catch (error) {
console.error('Failed to load states:', error);
} finally {
setLoading(false);
}
};
loadStates();
}
}, [selectedCountry]);
// Load cities when state changes
useEffect(() => {
if (selectedCountry && selectedState) {
const loadCities = async () => {
try {
setLoading(true);
const citiesData = await api.getCities(selectedCountry, selectedState);
setCities(citiesData);
setSelectedCity(''); // Reset city selection
} catch (error) {
console.error('Failed to load cities:', error);
} finally {
setLoading(false);
}
};
loadCities();
}
}, [selectedState]);
return (
<div className="location-selector">
<div className="form-group">
<label htmlFor="country">Country *</label>
<select
id="country"
value={selectedCountry}
onChange={(e) => setSelectedCountry(e.target.value)}
disabled={loading}
required
>
<option value="">Select Country</option>
{countries.map(country => (
<option key={country.iso2} value={country.iso2}>
{country.emoji} {country.name}
</option>
))}
</select>
</div>
<div className="form-group">
<label htmlFor="state">State/Province *</label>
<select
id="state"
value={selectedState}
onChange={(e) => setSelectedState(e.target.value)}
disabled={loading || !selectedCountry}
required
>
<option value="">Select State</option>
{states.map(state => (
<option key={state.iso2} value={state.iso2}>
{state.name}
</option>
))}
</select>
</div>
<div className="form-group">
<label htmlFor="city">City *</label>
<select
id="city"
value={selectedCity}
onChange={(e) => setSelectedCity(e.target.value)}
disabled={loading || !selectedState}
required
>
<option value="">Select City</option>
{cities.map(city => (
<option key={city.id} value={city.id}>
{city.name}
</option>
))}
</select>
</div>
{loading && <div className="loading">Loading...</div>}
</div>
);
};
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)
class LocationService:
def __init__(self, api_key):
self.api = CountryStateCityAPI(api_key)
def get_countries_for_dropdown(self):
"""Format countries for HTML select dropdown"""
try:
countries = self.api.get_countries()
return [
{'value': country['iso2'], 'text': f"{country.get('emoji', '')} {country['name']}"}
for country in countries
]
except Exception as e:
print(f"Error fetching countries: {e}")
return []
def get_states_for_dropdown(self, country_code):
"""Format states for HTML select dropdown"""
try:
states = self.api.get_states(country_code)
return [
{'value': state['iso2'], 'text': state['name']}
for state in states
]
except Exception as e:
print(f"Error fetching states: {e}")
return []
location_service = LocationService('YOUR_API_KEY')
@app.route('/')
def registration_form():
countries = location_service.get_countries_for_dropdown()
return render_template('registration.html', countries=countries)
@app.route('/api/states/<country_code>')
def get_states(country_code):
states = location_service.get_states_for_dropdown(country_code)
return jsonify(states)
@app.route('/register', methods=['POST'])
def register_user():
user_data = {
'name': request.form.get('name'),
'email': request.form.get('email'),
'country': request.form.get('country'),
'state': request.form.get('state'),
'city': request.form.get('city')
}
if not all([user_data['country'], user_data['state'], user_data['city']]):
return jsonify({'error': 'All location fields are required'}), 400
return jsonify({'message': 'User registered successfully', 'user': user_data})
if __name__ == '__main__':
app.run(debug=True)
2. E-commerce Shipping Calculator
Calculate shipping costs and delivery times based on geographical locations:class ShippingCalculator {
constructor(apiKey) {
this.api = new CountryStateCityAPI(apiKey);
this.shippingRates = {
domestic: { base: 5.99, perKg: 1.50, deliveryDays: '2-3' },
international: {
asia: { base: 25.99, perKg: 8.50, deliveryDays: '7-10' },
europe: { base: 29.99, perKg: 9.50, deliveryDays: '7-12' },
americas: { base: 19.99, perKg: 7.50, deliveryDays: '5-8' },
africa: { base: 35.99, perKg: 12.50, deliveryDays: '10-15' }
}
};
}
async calculateShipping(fromCountryCode, toCountryCode, weight) {
try {
const [fromCountry, toCountry] = await Promise.all([
this.api.getCountryDetails(fromCountryCode),
this.api.getCountryDetails(toCountryCode)
]);
// Domestic shipping
if (fromCountryCode === toCountryCode) {
const rate = this.shippingRates.domestic;
return {
cost: rate.base + (weight * rate.perKg),
deliveryTime: rate.deliveryDays,
type: 'Domestic',
from: fromCountry.name,
to: toCountry.name
};
}
// International shipping
const toRegion = this.getRegion(toCountry.region);
const rate = this.shippingRates.international[toRegion];
return {
cost: rate.base + (weight * rate.perKg),
deliveryTime: rate.deliveryDays,
type: 'International',
region: toRegion,
from: fromCountry.name,
to: toCountry.name
};
} catch (error) {
throw new Error(`Shipping calculation failed: ${error.message}`);
}
}
getRegion(countryRegion) {
const regionMap = {
'Asia': 'asia',
'Europe': 'europe',
'Americas': 'americas',
'Africa': 'africa'
};
return regionMap[countryRegion] || 'international';
}
}
// Usage
const calculator = new ShippingCalculator('YOUR_API_KEY');
const shippingInfo = await calculator.calculateShipping('US', 'CA', 2.5);
console.log(`Shipping cost: $${shippingInfo.cost.toFixed(2)}`);
console.log(`Delivery: ${shippingInfo.deliveryTime} business days`);
3. Multi-Currency Price Display
Display prices in local currencies based on user location:class PriceLocalization {
constructor(apiKey) {
this.api = new CountryStateCityAPI(apiKey);
this.exchangeRates = {}; // Cache exchange rates
this.baseCurrency = 'USD';
}
async getLocalizedPrice(basePrice, userCountryCode) {
try {
const country = await this.api.getCountryDetails(userCountryCode);
const currency = country.currency;
if (currency === this.baseCurrency) {
return {
amount: basePrice,
currency: currency,
symbol: country.currency_symbol || '$',
formatted: `${country.currency_symbol || '$'}${basePrice.toFixed(2)}`
};
}
// Get exchange rate (you'd typically use a service like exchangerates-api.io)
const rate = await this.getExchangeRate(this.baseCurrency, currency);
const localAmount = basePrice * rate;
return {
amount: localAmount,
currency: currency,
symbol: country.currency_symbol || '',
formatted: `${country.currency_symbol || ''}${localAmount.toFixed(2)}`,
exchangeRate: rate,
originalPrice: basePrice,
originalCurrency: this.baseCurrency
};
} catch (error) {
console.error('Price localization failed:', error);
// Fallback to base price
return {
amount: basePrice,
currency: this.baseCurrency,
symbol: '$',
formatted: `$${basePrice.toFixed(2)}`
};
}
}
async getExchangeRate(from, to) {
// This is a placeholder - use a real exchange rate service
const cacheKey = `${from}-${to}`;
if (this.exchangeRates[cacheKey] &&
this.exchangeRates[cacheKey].timestamp > Date.now() - 3600000) {
return this.exchangeRates[cacheKey].rate;
}
// Mock exchange rate - replace with real service
const mockRates = { 'EUR': 0.85, 'GBP': 0.73, 'CAD': 1.25, 'INR': 74.5 };
const rate = mockRates[to] || 1;
this.exchangeRates[cacheKey] = {
rate: rate,
timestamp: Date.now()
};
return rate;
}
}
Best Practices and Optimization
Caching Strategy for Performance
Implement intelligent caching to minimize API calls and improve performance:class OptimizedCountryStateCityAPI extends CountryStateCityAPI {
constructor(apiKey, cacheOptions = {}) {
super(apiKey);
this.cache = new Map();
this.cacheTTL = cacheOptions.ttl || 3600000; // 1 hour default
this.requestQueue = new Map(); // Prevent duplicate requests
}
async request(endpoint) {
// Check cache first
const cached = this.cache.get(endpoint);
if (cached && Date.now() - cached.timestamp < this.cacheTTL) {
return cached.data;
}
// Check if request is already in progress
if (this.requestQueue.has(endpoint)) {
return await this.requestQueue.get(endpoint);
}
// Make request and cache the promise
const requestPromise = super.request(endpoint);
this.requestQueue.set(endpoint, requestPromise);
try {
const data = await requestPromise;
this.cache.set(endpoint, {
data,
timestamp: Date.now()
});
return data;
} finally {
this.requestQueue.delete(endpoint);
}
}
// Preload commonly used data
async preloadEssentials() {
const essentials = [
'/countries',
'/countries/US/states',
'/countries/GB/states',
'/countries/CA/states'
];
await Promise.all(essentials.map(endpoint => this.request(endpoint)));
}
}
Need More Help?
API Reference
Complete API documentation with all endpoints and parameters.
SDKs & Libraries
Official SDKs and community libraries for popular programming languages.
Support
Get help from our community and support team.
All code examples are production-ready and include proper error handling and caching. Remember to replace
YOUR_API_KEY with your actual API key from the Country State City portal.