API Documentation - Endpoints & Examples

Search states by postal code

Overview

This endpoint allows you to find states based on a postal code (ZIP code). It is particularly useful for address validation, shipping calculations, and location-based services. Note that the same postal code may exist in different countries, so multiple results may be returned.

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/zipCode

Returns a list of all states according to their postal code

Relevant Information

Keep in mind that there are many states from different countries that have the same postal codes

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
zipcode required, string Postal code of the desired 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/zipCode';

async function getStateByZipCode(zipCode) {
  try {
    const params = new URLSearchParams({
      apikey: API_KEY,
      zipcode: zipCode,
      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 with postal code "${zipCode}":`, states);
    return states;
  } catch (error) {
    console.error('Error fetching state by zip code:', error);
    throw error;
  }
}

// Usage
getStateByZipCode('90210');  // Beverly Hills, California
getStateByZipCode('10001');  // New York
getStateByZipCode('28001');  // Madrid, Spain

JavaScript (Axios)

import axios from 'axios';

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

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

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

// Validate ZIP code and get state
async function validateZipCode(zipCode) {
  const states = await getStateByZipCode(zipCode);

  if (states.length === 0) {
    return { valid: false, message: 'Invalid ZIP code' };
  }

  if (states.length === 1) {
    return {
      valid: true,
      state: states[0].state_name,
      message: `ZIP code belongs to ${states[0].state_name}`
    };
  }

  return {
    valid: true,
    states: states.map(s => s.state_name),
    message: `ZIP code exists in multiple locations`
  };
}

// Usage
validateZipCode('33101');  // Miami, Florida

React

import { useState, useEffect, useCallback } from 'react';

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

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

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

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

        const params = new URLSearchParams({
          apikey: API_KEY,
          zipcode: zipCode,
          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);
      }
    };

    fetchStateByZipCode();
  }, [zipCode]);

  if (loading) return <div>Looking up ZIP code...</div>;
  if (error) return <div>Error: {error}</div>;

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

// ZIP code lookup component with input and debounce
function ZipCodeLookup() {
  const [zipInput, setZipInput] = useState('');
  const [searchZip, setSearchZip] = useState('');
  const [debouncedZip, setDebouncedZip] = useState('');

  // Debounce the search
  useEffect(() => {
    const timer = setTimeout(() => {
      if (zipInput.length >= 3) {
        setDebouncedZip(zipInput);
      }
    }, 500);

    return () => clearTimeout(timer);
  }, [zipInput]);

  const handleSearch = (e) => {
    e.preventDefault();
    setSearchZip(zipInput);
  };

  return (
    <div>
      <form onSubmit={handleSearch}>
        <input
          type="text"
          value={zipInput}
          onChange={(e) => setZipInput(e.target.value)}
          placeholder="Enter ZIP code..."
          pattern="[0-9]*"
        />
        <button type="submit">Lookup</button>
      </form>

      {(searchZip || debouncedZip) && (
        <StateByZipCode zipCode={searchZip || debouncedZip} />
      )}
    </div>
  );
}

export default ZipCodeLookup;

Vue 3

<template>
  <div>
    <div v-if="loading">Looking up ZIP code...</div>
    <div v-else-if="error">Error: {{ error }}</div>
    <div v-else>
      <h2>States with ZIP code "{{ zipCode }}"</h2>
      <p v-if="states.length === 0">No states found for this ZIP code</p>
      <div v-else>
        <p>Found {{ states.length }} result(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({
  zipCode: {
    type: String,
    required: true
  }
});

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

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

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

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

    const params = new URLSearchParams({
      apikey: API_KEY,
      zipcode: props.zipCode,
      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.zipCode, fetchStateByZipCode);
onMounted(fetchStateByZipCode);
</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';
import { Subject, debounceTime, distinctUntilChanged } from 'rxjs';

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-zipcode',
  standalone: true,
  imports: [CommonModule],
  template: `
    <div>
      <div *ngIf="loading">Looking up ZIP code...</div>
      <div *ngIf="error">Error: {{ error }}</div>
      <div *ngIf="!loading && !error">
        <h2>States with ZIP code "{{ zipCode }}"</h2>
        <p *ngIf="states.length === 0">No states found for this ZIP code</p>
        <div *ngIf="states.length > 0">
          <p>Found {{ states.length }} result(s)</p>
          <ul>
            <li *ngFor="let state of states">{{ state.state_name }}</li>
          </ul>
        </div>
      </div>
    </div>
  `
})
export class StateByZipCodeComponent implements OnInit, OnChanges {
  @Input() zipCode!: string;

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

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

  constructor(private http: HttpClient) {}

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

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

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

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

    const params = new HttpParams()
      .set('apikey', this.API_KEY)
      .set('zipcode', this.zipCode)
      .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;
      }
    });
  }
}

// ZIP code lookup with debounce
@Component({
  selector: 'app-zipcode-lookup',
  standalone: true,
  imports: [CommonModule, FormsModule, StateByZipCodeComponent],
  template: `
    <div>
      <form (ngSubmit)="search()">
        <input
          type="text"
          [(ngModel)]="zipInput"
          name="zipcode"
          (ngModelChange)="onZipChange($event)"
          placeholder="Enter ZIP code..."
        />
        <button type="submit">Lookup</button>
      </form>

      <app-state-by-zipcode
        *ngIf="searchZip"
        [zipCode]="searchZip"
      ></app-state-by-zipcode>
    </div>
  `
})
export class ZipCodeLookupComponent {
  zipInput = '';
  searchZip = '';
  private zipSubject = new Subject<string>();

  constructor() {
    this.zipSubject.pipe(
      debounceTime(500),
      distinctUntilChanged()
    ).subscribe(zip => {
      if (zip.length >= 3) {
        this.searchZip = zip;
      }
    });
  }

  onZipChange(value: string): void {
    this.zipSubject.next(value);
  }

  search(): void {
    this.searchZip = this.zipInput;
  }
}

PHP

<?php

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

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

    $params = http_build_query([
        'apikey' => $apiKey,
        'zipcode' => $zipCode,
        '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 {
    $zipCode = '90210';
    $states = getStateByZipCode($zipCode, $apiKey);

    echo "States with ZIP code '$zipCode':\n";
    echo "Found " . count($states) . " result(s)\n\n";

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

// Validate ZIP code function
function validateZipCode($zipCode, $apiKey) {
    $states = getStateByZipCode($zipCode, $apiKey);

    if (empty($states)) {
        return [
            'valid' => false,
            'message' => "Invalid ZIP code: $zipCode"
        ];
    }

    if (count($states) === 1) {
        return [
            'valid' => true,
            'state' => $states[0]['state_name'],
            'message' => "ZIP code $zipCode is in " . $states[0]['state_name']
        ];
    }

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

    return [
        'valid' => true,
        'states' => $stateNames,
        'message' => "ZIP code $zipCode exists in: " . implode(', ', $stateNames)
    ];
}

// Example
$result = validateZipCode('10001', $apiKey);
echo $result['message'] . "\n";
?>

Python

import requests

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

def get_state_by_zipcode(zip_code):
    """Find the state(s) for a given postal code."""
    params = {
        'apikey': API_KEY,
        'zipcode': zip_code,
        '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 ZIP code: {e}')
        raise

def validate_zipcode(zip_code):
    """Validate a ZIP code and return state information."""
    states = get_state_by_zipcode(zip_code)

    if not states:
        return {
            'valid': False,
            'message': f'Invalid ZIP code: {zip_code}'
        }

    if len(states) == 1:
        return {
            'valid': True,
            'state': states[0]['state_name'],
            'state_id': states[0]['id'],
            'message': f"ZIP code {zip_code} is in {states[0]['state_name']}"
        }

    state_names = [s['state_name'] for s in states]
    return {
        'valid': True,
        'states': state_names,
        'message': f"ZIP code {zip_code} exists in multiple locations: {', '.join(state_names)}"
    }

# Usage
if __name__ == '__main__':
    # US ZIP codes
    us_zips = ['90210', '10001', '33101', '60601']

    for zip_code in us_zips:
        result = validate_zipcode(zip_code)
        print(f"{zip_code}: {result['message']}")


# Async version with aiohttp
import aiohttp
import asyncio

async def get_state_by_zipcode_async(zip_code):
    """Find state by ZIP code asynchronously."""
    params = {
        'apikey': API_KEY,
        'zipcode': zip_code,
        '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}')

# Batch ZIP code validation
async def validate_multiple_zipcodes(zip_codes):
    """Validate multiple ZIP codes concurrently."""
    tasks = [get_state_by_zipcode_async(z) for z in zip_codes]
    results = await asyncio.gather(*tasks, return_exceptions=True)
    return dict(zip(zip_codes, results))

# Usage
# zip_codes = ['90210', '10001', '33101', '60601', '98101']
# results = asyncio.run(validate_multiple_zipcodes(zip_codes))
# for zip_code, states in results.items():
#     if isinstance(states, list) and states:
#         print(f"{zip_code}: {states[0]['state_name']}")

cURL

# Search state by ZIP code
curl -X GET "https://api.countrydataapi.com/v1/states/zipCode?apikey=YOUR_API_KEY&zipcode=90210&lang=en&fields=id,state_name,lang"

# New York ZIP code
curl -X GET "https://api.countrydataapi.com/v1/states/zipCode?apikey=YOUR_API_KEY&zipcode=10001&lang=en"

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

# European postal code
curl -X GET "https://api.countrydataapi.com/v1/states/zipCode?apikey=YOUR_API_KEY&zipcode=28001&lang=en"

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

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

# Check multiple ZIP codes in sequence
for zip in 90210 10001 33101 60601; do
  echo "ZIP: $zip"
  curl -s "https://api.countrydataapi.com/v1/states/zipCode?apikey=YOUR_API_KEY&zipcode=$zip&fields=state_name" | json_pp
  echo ""
done

Error Handling

The API may return the following error responses:

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

Error Response Example

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

Important Notes

  • International Postal Codes: Postal codes vary in format across countries (e.g., US uses 5-digit codes, UK uses alphanumeric codes). Ensure you pass the correct format.
  • Duplicate Codes: Some postal codes may exist in different countries. The API returns all matching states.
  • Leading Zeros: Some postal codes have leading zeros (e.g., "01234"). Always pass them as strings to preserve the format.