curl -X GET 'https://api.countrystatecity.in/v1/countries/IN/states' \
-H 'X-CSCAPI-KEY: YOUR_API_KEY'
curl -X GET 'https://api.countrystatecity.in/v1/countries/IN/states?q=maha' \
-H 'X-CSCAPI-KEY: YOUR_API_KEY'
curl -X GET 'https://api.countrystatecity.in/v1/countries/IN/states?include_translations=true' \
-H 'X-CSCAPI-KEY: YOUR_API_KEY'
import requests
def get_states_by_country(country_code):
response = requests.get(
f'https://api.countrystatecity.in/v1/countries/{country_code}/states',
headers={'X-CSCAPI-KEY': 'YOUR_API_KEY'}
)
if response.ok:
states = response.json()
print(f'Found {len(states)} states in {country_code}')
return states
else:
print('Country not found or no states available')
return []
states = get_states_by_country('IN')
const getStatesByCountry = async (countryCode) => {
const response = await fetch(`https://api.countrystatecity.in/v1/countries/${countryCode}/states`, {
headers: { 'X-CSCAPI-KEY': 'YOUR_API_KEY' }
});
if (response.ok) {
const states = await response.json();
console.log(`Found ${states.length} states in ${countryCode}`);
return states;
} else {
console.error('Country not found or no states available');
}
};
getStatesByCountry('IN');
<?php
function getStatesByCountry($countryCode) {
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://api.countrystatecity.in/v1/countries/{$countryCode}/states",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => array(
'X-CSCAPI-KEY: YOUR_API_KEY'
),
));
$response = curl_exec($curl);
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
if ($httpCode == 200) {
$states = json_decode($response, true);
echo "Found " . count($states) . " states in {$countryCode}\n";
return $states;
} else {
echo "Country not found or no states available\n";
return [];
}
}
$states = getStatesByCountry('IN');
?>
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
func getStatesByCountry(countryCode string) []map[string]interface{} {
url := fmt.Sprintf("https://api.countrystatecity.in/v1/countries/%s/states", countryCode)
client := &http.Client{}
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-CSCAPI-KEY", "YOUR_API_KEY")
res, _ := client.Do(req)
defer res.Body.Close()
if res.StatusCode == 200 {
body, _ := ioutil.ReadAll(res.Body)
var states []map[string]interface{}
json.Unmarshal(body, &states)
fmt.Printf("Found %d states in %s\n", len(states), countryCode)
return states
} else {
fmt.Printf("Country not found or no states available\n")
return nil
}
}
func main() {
states := getStatesByCountry("IN")
fmt.Println(states)
}
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
public class StatesByCountry {
public static void main(String[] args) throws Exception {
String countryCode = "IN";
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.countrystatecity.in/v1/countries/" + countryCode + "/states"))
.header("X-CSCAPI-KEY", "YOUR_API_KEY")
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200) {
Gson gson = new Gson();
Type listType = new TypeToken<List<Map<String, Object>>>(){}.getType();
List<Map<String, Object>> states = gson.fromJson(response.body(), listType);
System.out.println("Found " + states.size() + " states in " + countryCode);
} else {
System.out.println("Country not found or no states available");
}
}
}
require 'net/http'
require 'json'
def get_states_by_country(country_code)
uri = URI("https://api.countrystatecity.in/v1/countries/#{country_code}/states")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri)
request['X-CSCAPI-KEY'] = 'YOUR_API_KEY'
response = http.request(request)
if response.code == '200'
states = JSON.parse(response.body)
puts "Found #{states.length} states in #{country_code}"
states
else
puts 'Country not found or no states available'
[]
end
end
states = get_states_by_country('IN')
[
{
"id": 4008,
"name": "Maharashtra",
"iso2": "MH",
"country_id": 101,
"country_code": "IN",
"latitude": "19.75147980",
"longitude": "75.71388840",
"timezone": "Asia/Kolkata"
}
]
[
{
"id": 4008,
"name": "Maharashtra",
"iso2": "MH",
"country_id": 101,
"country_code": "IN",
"latitude": "19.75147980",
"longitude": "75.71388840",
"timezone": "Asia/Kolkata",
"fips_code": "16",
"iso3166_2": "IN-MH",
"type": "state",
"level": 1,
"parent_id": null,
"native": "महाराष्ट्र",
"population": 112374333,
"translations": "{\"kr\":\"마하라슈트라\",\"de\":\"Maharashtra\",\"fr\":\"Maharashtra\",\"cn\":\"马哈拉施特拉邦\"}",
"wikiDataId": "Q1191"
}
]
{
"error": "No States/Regions found."
}
{
"error": "Unauthorized. You shouldn't be here."
}
Get States by Country
Retrieve all states/provinces for a specific country
curl -X GET 'https://api.countrystatecity.in/v1/countries/IN/states' \
-H 'X-CSCAPI-KEY: YOUR_API_KEY'
curl -X GET 'https://api.countrystatecity.in/v1/countries/IN/states?q=maha' \
-H 'X-CSCAPI-KEY: YOUR_API_KEY'
curl -X GET 'https://api.countrystatecity.in/v1/countries/IN/states?include_translations=true' \
-H 'X-CSCAPI-KEY: YOUR_API_KEY'
import requests
def get_states_by_country(country_code):
response = requests.get(
f'https://api.countrystatecity.in/v1/countries/{country_code}/states',
headers={'X-CSCAPI-KEY': 'YOUR_API_KEY'}
)
if response.ok:
states = response.json()
print(f'Found {len(states)} states in {country_code}')
return states
else:
print('Country not found or no states available')
return []
states = get_states_by_country('IN')
const getStatesByCountry = async (countryCode) => {
const response = await fetch(`https://api.countrystatecity.in/v1/countries/${countryCode}/states`, {
headers: { 'X-CSCAPI-KEY': 'YOUR_API_KEY' }
});
if (response.ok) {
const states = await response.json();
console.log(`Found ${states.length} states in ${countryCode}`);
return states;
} else {
console.error('Country not found or no states available');
}
};
getStatesByCountry('IN');
<?php
function getStatesByCountry($countryCode) {
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://api.countrystatecity.in/v1/countries/{$countryCode}/states",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => array(
'X-CSCAPI-KEY: YOUR_API_KEY'
),
));
$response = curl_exec($curl);
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
if ($httpCode == 200) {
$states = json_decode($response, true);
echo "Found " . count($states) . " states in {$countryCode}\n";
return $states;
} else {
echo "Country not found or no states available\n";
return [];
}
}
$states = getStatesByCountry('IN');
?>
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
func getStatesByCountry(countryCode string) []map[string]interface{} {
url := fmt.Sprintf("https://api.countrystatecity.in/v1/countries/%s/states", countryCode)
client := &http.Client{}
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-CSCAPI-KEY", "YOUR_API_KEY")
res, _ := client.Do(req)
defer res.Body.Close()
if res.StatusCode == 200 {
body, _ := ioutil.ReadAll(res.Body)
var states []map[string]interface{}
json.Unmarshal(body, &states)
fmt.Printf("Found %d states in %s\n", len(states), countryCode)
return states
} else {
fmt.Printf("Country not found or no states available\n")
return nil
}
}
func main() {
states := getStatesByCountry("IN")
fmt.Println(states)
}
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
public class StatesByCountry {
public static void main(String[] args) throws Exception {
String countryCode = "IN";
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.countrystatecity.in/v1/countries/" + countryCode + "/states"))
.header("X-CSCAPI-KEY", "YOUR_API_KEY")
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200) {
Gson gson = new Gson();
Type listType = new TypeToken<List<Map<String, Object>>>(){}.getType();
List<Map<String, Object>> states = gson.fromJson(response.body(), listType);
System.out.println("Found " + states.size() + " states in " + countryCode);
} else {
System.out.println("Country not found or no states available");
}
}
}
require 'net/http'
require 'json'
def get_states_by_country(country_code)
uri = URI("https://api.countrystatecity.in/v1/countries/#{country_code}/states")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri)
request['X-CSCAPI-KEY'] = 'YOUR_API_KEY'
response = http.request(request)
if response.code == '200'
states = JSON.parse(response.body)
puts "Found #{states.length} states in #{country_code}"
states
else
puts 'Country not found or no states available'
[]
end
end
states = get_states_by_country('IN')
[
{
"id": 4008,
"name": "Maharashtra",
"iso2": "MH",
"country_id": 101,
"country_code": "IN",
"latitude": "19.75147980",
"longitude": "75.71388840",
"timezone": "Asia/Kolkata"
}
]
[
{
"id": 4008,
"name": "Maharashtra",
"iso2": "MH",
"country_id": 101,
"country_code": "IN",
"latitude": "19.75147980",
"longitude": "75.71388840",
"timezone": "Asia/Kolkata",
"fips_code": "16",
"iso3166_2": "IN-MH",
"type": "state",
"level": 1,
"parent_id": null,
"native": "महाराष्ट्र",
"population": 112374333,
"translations": "{\"kr\":\"마하라슈트라\",\"de\":\"Maharashtra\",\"fr\":\"Maharashtra\",\"cn\":\"马哈拉施特拉邦\"}",
"wikiDataId": "Q1191"
}
]
{
"error": "No States/Regions found."
}
{
"error": "Unauthorized. You shouldn't be here."
}
?fields= to limit columns returned, or ?sort= to order the list. Both are available on Starter+ plans. See the Field Filtering & Sorting guide for syntax and per-entity sortable fields.fips_code, iso3166_2, type, level, parent_id, native, population, translations, and wikiDataId are returned on higher tiers. See Tier-Based Field Availability below.curl -X GET 'https://api.countrystatecity.in/v1/countries/IN/states' \
-H 'X-CSCAPI-KEY: YOUR_API_KEY'
curl -X GET 'https://api.countrystatecity.in/v1/countries/IN/states?q=maha' \
-H 'X-CSCAPI-KEY: YOUR_API_KEY'
curl -X GET 'https://api.countrystatecity.in/v1/countries/IN/states?include_translations=true' \
-H 'X-CSCAPI-KEY: YOUR_API_KEY'
import requests
def get_states_by_country(country_code):
response = requests.get(
f'https://api.countrystatecity.in/v1/countries/{country_code}/states',
headers={'X-CSCAPI-KEY': 'YOUR_API_KEY'}
)
if response.ok:
states = response.json()
print(f'Found {len(states)} states in {country_code}')
return states
else:
print('Country not found or no states available')
return []
states = get_states_by_country('IN')
const getStatesByCountry = async (countryCode) => {
const response = await fetch(`https://api.countrystatecity.in/v1/countries/${countryCode}/states`, {
headers: { 'X-CSCAPI-KEY': 'YOUR_API_KEY' }
});
if (response.ok) {
const states = await response.json();
console.log(`Found ${states.length} states in ${countryCode}`);
return states;
} else {
console.error('Country not found or no states available');
}
};
getStatesByCountry('IN');
<?php
function getStatesByCountry($countryCode) {
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://api.countrystatecity.in/v1/countries/{$countryCode}/states",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => array(
'X-CSCAPI-KEY: YOUR_API_KEY'
),
));
$response = curl_exec($curl);
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
if ($httpCode == 200) {
$states = json_decode($response, true);
echo "Found " . count($states) . " states in {$countryCode}\n";
return $states;
} else {
echo "Country not found or no states available\n";
return [];
}
}
$states = getStatesByCountry('IN');
?>
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
func getStatesByCountry(countryCode string) []map[string]interface{} {
url := fmt.Sprintf("https://api.countrystatecity.in/v1/countries/%s/states", countryCode)
client := &http.Client{}
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-CSCAPI-KEY", "YOUR_API_KEY")
res, _ := client.Do(req)
defer res.Body.Close()
if res.StatusCode == 200 {
body, _ := ioutil.ReadAll(res.Body)
var states []map[string]interface{}
json.Unmarshal(body, &states)
fmt.Printf("Found %d states in %s\n", len(states), countryCode)
return states
} else {
fmt.Printf("Country not found or no states available\n")
return nil
}
}
func main() {
states := getStatesByCountry("IN")
fmt.Println(states)
}
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
public class StatesByCountry {
public static void main(String[] args) throws Exception {
String countryCode = "IN";
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.countrystatecity.in/v1/countries/" + countryCode + "/states"))
.header("X-CSCAPI-KEY", "YOUR_API_KEY")
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200) {
Gson gson = new Gson();
Type listType = new TypeToken<List<Map<String, Object>>>(){}.getType();
List<Map<String, Object>> states = gson.fromJson(response.body(), listType);
System.out.println("Found " + states.size() + " states in " + countryCode);
} else {
System.out.println("Country not found or no states available");
}
}
}
require 'net/http'
require 'json'
def get_states_by_country(country_code)
uri = URI("https://api.countrystatecity.in/v1/countries/#{country_code}/states")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri)
request['X-CSCAPI-KEY'] = 'YOUR_API_KEY'
response = http.request(request)
if response.code == '200'
states = JSON.parse(response.body)
puts "Found #{states.length} states in #{country_code}"
states
else
puts 'Country not found or no states available'
[]
end
end
states = get_states_by_country('IN')
[
{
"id": 4008,
"name": "Maharashtra",
"iso2": "MH",
"country_id": 101,
"country_code": "IN",
"latitude": "19.75147980",
"longitude": "75.71388840",
"timezone": "Asia/Kolkata"
}
]
[
{
"id": 4008,
"name": "Maharashtra",
"iso2": "MH",
"country_id": 101,
"country_code": "IN",
"latitude": "19.75147980",
"longitude": "75.71388840",
"timezone": "Asia/Kolkata",
"fips_code": "16",
"iso3166_2": "IN-MH",
"type": "state",
"level": 1,
"parent_id": null,
"native": "महाराष्ट्र",
"population": 112374333,
"translations": "{\"kr\":\"마하라슈트라\",\"de\":\"Maharashtra\",\"fr\":\"Maharashtra\",\"cn\":\"马哈拉施特拉邦\"}",
"wikiDataId": "Q1191"
}
]
{
"error": "No States/Regions found."
}
{
"error": "Unauthorized. You shouldn't be here."
}
Common Use Cases
Cascading Address Forms
Cascading Address Forms
const populateStatesDropdown = async (countryCode) => {
const states = await getStatesByCountry(countryCode);
const select = document.getElementById('state-select');
// Clear existing options
select.innerHTML = '<option value="">Select State...</option>';
states.forEach(state => {
const option = document.createElement('option');
option.value = state.iso2;
option.textContent = state.name;
select.appendChild(option);
});
};
// Listen for country changes
document.getElementById('country-select').addEventListener('change', (e) => {
populateStatesDropdown(e.target.value);
});
Regional Validation
Regional Validation
const validateStateForCountry = async (countryCode, stateCode) => {
const states = await getStatesByCountry(countryCode);
return states.some(state => state.iso2 === stateCode);
};
Tier-Based Field Availability
| Tier | Plans | Fields |
|---|---|---|
| Basic | Community, Starter, Legacy | id, name, iso2, country_id, country_code, latitude, longitude, timezone |
| Full | Supporter, Professional, Business | All Basic + fips_code, iso3166_2, type, level, parent_id, native, population, translations, wikiDataId, localized_name, matched_locale |
translations is part of Full access but is not returned by default: add include_translations=true, or name it in ?fields=. localized_name and matched_locale are computed from the translations rather than stored, and appear only when you pass locale. See Localized Place Names.
See Pricing for plan details.Authorizations
API key for authentication. Get your free key at app.countrystatecity.in.
Path Parameters
ISO2 code of the country (e.g., IN)
"IN"
Query Parameters
Search filter. Case-insensitive match on name and native fields. Min 2 characters. Requires Starter+ plan.
2 - 100"maha"
Comma-separated list of fields to include in the response. id is always included. Requires Starter+ plan.
"name,iso2"
Comma-separated sort tokens: field or field:asc|desc. Requires Starter+ plan.
"name:asc"
BCP 47 locale code (e.g. pt-BR) to request a localized name. Adds localized_name (resolved via exact locale → base language → native name → English name fallback) and matched_locale (which tier matched) to each result; name is unaffected. Supporter+ plans only — silently omitted (not an error) on lower tiers. A malformed value is rejected with a 400 on every tier.
2 - 7^[a-zA-Z]{2}(-[a-zA-Z]{2,4})?$"pt-BR"
When true, includes the full translations field (JSON string keyed by language code). Supporter+ plans only — silently omitted (not an error) on lower tiers. Note that an explicit fields=translations also returns the field and takes precedence over this flag.
true
Response
List of states
Unique identifier
4008
State name in English
"Maharashtra"
Parent country ID
Parent country ISO2 code
"IN"
State/province ISO code
"MH"
Latitude coordinate
"19.75147980"
Longitude coordinate
"75.71388840"
IANA timezone identifier
"Asia/Kolkata"
FIPS code. Coordinates tier and above.
ISO 3166-2 subdivision code. Coordinates tier and above.
Administrative type (e.g., state, province, territory). Coordinates tier and above.
"state"
Administrative level. Coordinates tier and above.
Parent subdivision ID (for nested administrative structures). Coordinates tier and above.
Name in native language. Coordinates tier and above.
Population count. Coordinates tier and above.
JSON string keyed by language code. Supporter+ plans only. Returned when include_translations=true or when fields=translations explicitly requests it.
Wikidata item identifier. Full access level only.
"Q1191"
Name resolved via the locale query param's fallback chain (exact locale → base language → native name → English name). Only present when locale was supplied. Supporter+ plans only — silently omitted on lower tiers.
"Maharashtra"
Which fallback tier satisfied the locale request: the exact locale (e.g. pt-BR), its base language (e.g. pt), native, or en (English fallback). Only present when locale was supplied. Supporter+ plans only — silently omitted on lower tiers.
"en"