API Documentation - Endpoints & Examples

Select States

Get states/provinces by country, optimized for select dropdowns

The /v1/select/states endpoint returns a lightweight list of states/provinces filtered by country, with only id and name fields, optimized for dropdown menus.

Endpoint

GET https://api.countrydataapi.com/v1/select/states

Authentication

Include your API key as a query parameter:

?apikey=your-api-key

Your API key is like a password, keep it secure. Get your key from the account dashboard.

Query Parameters

Parameter Type Required Description
apikey string Yes Your API authentication key
country string Yes Country ID (from /select/countries endpoint)
lang string No Language code for state names (default: en)

Supported Languages

  • en - English (default)
  • es - Spanish
  • pt - Portuguese
  • fr - French
  • de - German
  • it - Italian

Request Example

# Get states for United States
curl "https://api.countrydataapi.com/v1/select/states?apikey=your-api-key&country=66c7a6c9e4bda21f4ab10fd5&lang=en"

JavaScript (Fetch)

const API_KEY = 'your-api-key';
const COUNTRY_ID = '66c7a6c9e4bda21f4ab10fd5'; // United States

async function loadStates(countryId) {
  const response = await fetch(
    `https://api.countrydataapi.com/v1/select/states?apikey=${API_KEY}&country=${countryId}&lang=en`
  );
  const data = await response.json();
  return data;
}

const states = await loadStates(COUNTRY_ID);

JavaScript (Axios)

import axios from 'axios';

const response = await axios.get(
  'https://api.countrydataapi.com/v1/select/states',
  {
    params: {
      apikey: 'your-api-key',
      country: '66c7a6c9e4bda21f4ab10fd5',
      lang: 'en',
    },
  }
);

Python

import requests

response = requests.get(
    'https://api.countrydataapi.com/v1/select/states',
    params={
        'apikey': 'your-api-key',
        'country': '66c7a6c9e4bda21f4ab10fd5',
        'lang': 'en'
    }
)
data = response.json()

PHP

<?php
$apiKey = 'your-api-key';
$countryId = '66c7a6c9e4bda21f4ab10fd5';
$url = "https://api.countrydataapi.com/v1/select/states?apikey={$apiKey}&country={$countryId}&lang=en";

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);

$data = json_decode($response, true);
?>

Angular

// state.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

interface State {
  id: string;
  name: string;
}

interface ApiResponse {
  success: boolean;
  data: State[];
}

@Injectable({
  providedIn: 'root'
})
export class StateService {
  private readonly API_KEY = 'your-api-key';
  private readonly BASE_URL = 'https://api.countrydataapi.com/v1';

  constructor(private http: HttpClient) {}

  getStatesByCountry(countryId: string, lang: string = 'en'): Observable<State[]> {
    const params = new HttpParams()
      .set('apikey', this.API_KEY)
      .set('country', countryId)
      .set('lang', lang);

    return this.http.get<ApiResponse>(
      `${this.BASE_URL}/select/states`,
      { params }
    ).pipe(
      map(response => response.data)
    );
  }
}

// state-select.component.ts
import { Component, Input, Output, EventEmitter, OnChanges, SimpleChanges } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { StateService } from './state.service';

@Component({
  selector: 'app-state-select',
  standalone: true,
  imports: [CommonModule, FormsModule],
  template: `
    <div *ngIf="loading">Loading states...</div>
    <div *ngIf="error" class="error">{{ error }}</div>
    <select
      *ngIf="!loading && !error"
      [(ngModel)]="selectedState"
      (ngModelChange)="onStateChange($event)"
      [disabled]="!countryId"
    >
      <option value="">Select a state...</option>
      <option *ngFor="let state of states" [value]="state.id">
        {{ state.name }}
      </option>
    </select>
  `
})
export class StateSelectComponent implements OnChanges {
  @Input() countryId: string = '';
  @Output() stateChange = new EventEmitter<string>();

  states: any[] = [];
  selectedState = '';
  loading = false;
  error: string | null = null;

  constructor(private stateService: StateService) {}

  ngOnChanges(changes: SimpleChanges) {
    if (changes['countryId'] && this.countryId) {
      this.loadStates();
    } else {
      this.states = [];
      this.selectedState = '';
    }
  }

  loadStates() {
    this.loading = true;
    this.error = null;

    this.stateService.getStatesByCountry(this.countryId, 'en').subscribe({
      next: (data) => {
        this.states = data;
        this.loading = false;
      },
      error: (err) => {
        this.error = 'Failed to load states';
        this.loading = false;
      }
    });
  }

  onStateChange(stateId: string) {
    this.stateChange.emit(stateId);
  }
}

Response Format

Success Response (United States)

{
  "success": true,
  "data": [
    {
      "id": "66c7a6cae4bda21f4ab11d16",
      "name": "Alabama"
    },
    {
      "id": "66c7a6cae4bda21f4ab11d17",
      "name": "Alaska"
    },
    {
      "id": "66c7a6cae4bda21f4ab11d18",
      "name": "Arizona"
    },
    {
      "id": "66c7a6cae4bda21f4ab11d19",
      "name": "Arkansas"
    },
    {
      "id": "66c7a6cae4bda21f4ab11d1a",
      "name": "California"
    }
    // ... 50 states total
  ]
}

Response Fields

Field Type Description
success boolean Indicates if the request was successful
data array Array of state/province objects
data[].id string Unique state identifier (MongoDB ObjectId)
data[].name string State/province name in the requested language

Error Response

{
  "success": false,
  "error": {
    "code": "MISSING_PARAMETER",
    "message": "Required parameter 'country' is missing"
  }
}

Empty Result

If a country has no states (e.g., small countries):

{
  "success": true,
  "data": []
}

Token Usage

This endpoint consumes 1 token per request.

Tip: Cache state data by country ID to reduce API calls when users navigate back and forth.

Cascading Dropdown Example

HTML

<select id="country" onchange="loadStates(this.value)">
  <option value="">Select country...</option>
  <!-- Populated from /select/countries -->
</select>

<select id="state" disabled>
  <option value="">Select state...</option>
</select>

<script>
const API_KEY = 'your-api-key';

async function loadStates(countryId) {
  const stateSelect = document.getElementById('state');

  // Reset and disable
  stateSelect.innerHTML = '<option value="">Loading...</option>';
  stateSelect.disabled = true;

  if (!countryId) {
    stateSelect.innerHTML = '<option value="">Select state...</option>';
    return;
  }

  try {
    const response = await fetch(
      `https://api.countrydataapi.com/v1/select/states?apikey=${API_KEY}&country=${countryId}&lang=en`
    );
    const { success, data, error } = await response.json();

    if (!success) {
      console.error('API Error:', error);
      stateSelect.innerHTML = '<option value="">Error loading states</option>';
      return;
    }

    stateSelect.innerHTML = '<option value="">Select state...</option>';
    data.forEach(state => {
      stateSelect.add(new Option(state.name, state.id));
    });
    stateSelect.disabled = false;
  } catch (err) {
    console.error('Network Error:', err);
    stateSelect.innerHTML = '<option value="">Error loading states</option>';
  }
}
</script>

React Component

import { useState, useEffect } from 'react';

function StateSelect({ countryId, onChange }) {
  const [states, setStates] = useState([]);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    if (!countryId) {
      setStates([]);
      return;
    }

    setLoading(true);
    fetch(
      `https://api.countrydataapi.com/v1/select/states?apikey=your-api-key&country=${countryId}&lang=en`
    )
      .then(res => res.json())
      .then(({ data }) => {
        setStates(data || []);
        setLoading(false);
      })
      .catch(err => {
        console.error(err);
        setLoading(false);
      });
  }, [countryId]);

  return (
    <select onChange={e => onChange(e.target.value)} disabled={!countryId || loading}>
      <option value="">
        {loading ? 'Loading...' : 'Select state...'}
      </option>
      {states.map(state => (
        <option key={state.id} value={state.id}>
          {state.name}
        </option>
      ))}
    </select>
  );
}

Vue Component

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

const props = defineProps(['countryId']);
const emit = defineEmits(['change']);

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

watch(() => props.countryId, async (countryId) => {
  if (!countryId) {
    states.value = [];
    return;
  }

  loading.value = true;
  try {
    const response = await fetch(
      `https://api.countrydataapi.com/v1/select/states?apikey=your-api-key&country=${countryId}&lang=en`
    );
    const { data } = await response.json();
    states.value = data || [];
  } catch (err) {
    console.error(err);
  } finally {
    loading.value = false;
  }
});
</script>

<template>
  <select @change="emit('change', $event.target.value)" :disabled="!countryId || loading">
    <option value="">{{ loading ? 'Loading...' : 'Select state...' }}</option>
    <option v-for="state in states" :key="state.id" :value="state.id">
      {{ state.name }}
    </option>
  </select>
</template>

Country-Specific Examples

United States (50 states)

const US_ID = '66c7a6c9e4bda21f4ab10fd5';
const response = await fetch(
  `https://api.countrydataapi.com/v1/select/states?apikey=your-api-key&country=${US_ID}`
);
// Returns: Alabama, Alaska, Arizona, ... Wyoming

Canada (10 provinces + 3 territories)

const CANADA_ID = '66c7a6c9e4bda21f4ab10ef7';
const response = await fetch(
  `https://api.countrydataapi.com/v1/select/states?apikey=your-api-key&country=${CANADA_ID}`
);
// Returns: Alberta, British Columbia, ... Yukon

Mexico (32 states)

const MEXICO_ID = '66c7a6c9e4bda21f4ab10fa8';
const response = await fetch(
  `https://api.countrydataapi.com/v1/select/states?apikey=your-api-key&country=${MEXICO_ID}&lang=es`
);
// Returns: Aguascalientes, Baja California, ... Zacatecas (in Spanish)

Caching Strategy

Cache states by country to minimize API calls:

const stateCache = new Map();

async function getStates(countryId) {
  // Check cache first
  if (stateCache.has(countryId)) {
    return stateCache.get(countryId);
  }

  // Fetch from API
  const response = await fetch(
    `https://api.countrydataapi.com/v1/select/states?apikey=your-api-key&country=${countryId}&lang=en`
  );
  const { data } = await response.json();

  // Save to cache
  stateCache.set(countryId, data);

  return data;
}

Error Handling

Always handle errors gracefully:

async function loadStates(countryId) {
  try {
    const response = await fetch(
      `https://api.countrydataapi.com/v1/select/states?apikey=your-api-key&country=${countryId}`
    );

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

    const result = await response.json();

    if (!result.success) {
      throw new Error(result.error?.message || 'API error');
    }

    return result.data;
  } catch (err) {
    console.error('Failed to load states:', err);
    // Show user-friendly error message
    alert('Failed to load states. Please try again.');
    return [];
  }
}

Performance Tips

  1. Lazy load: Only fetch when country is selected
  2. Cache by country: Store in memory or localStorage
  3. Debounce requests: If using search/filter
  4. Show loading state: Provide visual feedback

Rate Limits

  • Free tier: 100 requests/day
  • Basic tier: 1,000 requests/day
  • Pro tier: 10,000 requests/day
  • Enterprise tier: Unlimited

Check our pricing page for more details.

Common Errors

Error Code Description Solution
INVALID_API_KEY API key is invalid Check your API key in account dashboard
MISSING_PARAMETER country parameter missing Include country ID in request
INVALID_COUNTRY_ID Country ID format is invalid Use valid MongoDB ObjectId from /select/countries
QUOTA_EXCEEDED Daily token limit reached Upgrade plan or wait for reset

See the Error Codes documentation for all possible errors.

Related Endpoints

Complete Integration Guides

Need Help?


Note: Some countries have no administrative divisions (e.g., Monaco, Vatican City) and will return an empty array. Always handle empty results gracefully in your UI.