The Search Country by Postal Code endpoint allows you to find the country that contains a specific postal/zip code. This is essential for address validation, e-commerce shipping, and location-based services.
All API requests require authentication using an API key passed as a query parameter.
https://api.countrydataapi.com/v1/countries/zipCode?apikey=YOUR_API_KEY&postalCode=10001
https://api.countrydataapi.com/v1/countries/zipCode
Return the country that contains the postal code
There are 4 types of operations:
BASIC: Returns the fields id, lang, country_name, country_short_iso, country_phone_code, country_cca2, country_ccn3, country_cca3, country_cioc.
NORMAL: Returns the previous fields and adds country_independent, country_status, country_unMember, country_flag, country_map_googleMaps, country_map_openStreetMaps, country_fifa, country_flag_png, country_flag_svg, country_flag_alt, country_coatOfArms_png, country_coatOfArms_svg, country_startofWeek, country_continent_code, country_current_currency, country_GDP, country_location, country_land, country_terrain, country_climate, country_natural_hazards, country_note, country_history, country_GDP_per_capita_PPP, country_life_expectancy, country_median_age, country_birth_rate, country_death_rate, country_sex_ratio, country_literacy, country_roadways, country_airports, country_railways, country_waterways, country_heliports, country_airports_paved, country_wikipedia_url.
ADVANCED: Returns the previous fields and adds country_car_info, _country_idd_info.
ALL: Returns the previous fields and adds country_tld, country_capital, country_altSpellings, country_latLng, country_borders, country_timezones, country_continents, country_currencies, country_languages, country_translations, country_capital_info, country_demonyms, country_name.nativeName.
Each country returned with the BASIC method will cost 1 tokens.
Each country returned with the NORMAL method will cost 2 tokens.
Each country returned with the ADVANCED method will cost 3 tokens.
Each country returned with the ALL method will cost 4 tokens.
| Parameter | Type | Description |
|---|---|---|
| apikey | required, token | Authentication key of the account |
| postalCode | required, string | Postal code you want to search for |
| limitToken | optional, number | 1000 (default). Maximum number of countries to be returned |
| lang | optional, lang | en (default). Expected language of the response |
| fields | optional, string | id,lang,country_name (default). Expected fields in the response |
[
{
"id": "33be30c5-80fc-429d-bf10-bd11f2e3e84c",
"lang": "en",
"country_name": "United States",
"country_short_iso": "US",
"country_phone_code": "1",
"country_cca2": "US",
"country_ccn3": "840",
"country_cca3": "USA",
"country_cioc": "USA",
"country_independent": true,
"country_status": "officially-assigned",
"country_unMember": true,
"country_capital": ["Washington, D.C."],
"country_region": "Americas",
"country_subregion": "Northern America",
"country_flag": "flag-emoji",
"country_flag_png": "https://flagcdn.com/w320/us.png",
"country_flag_svg": "https://flagcdn.com/us.svg"
}
]
# Search country by postal code (US ZIP)
curl -X GET "https://api.countrydataapi.com/v1/countries/zipCode?apikey=YOUR_API_KEY&postalCode=10001"
# Search by UK postal code
curl -X GET "https://api.countrydataapi.com/v1/countries/zipCode?apikey=YOUR_API_KEY&postalCode=SW1A"
# Search by German postal code
curl -X GET "https://api.countrydataapi.com/v1/countries/zipCode?apikey=YOUR_API_KEY&postalCode=10115"
# With specific fields (NORMAL level)
curl -X GET "https://api.countrydataapi.com/v1/countries/zipCode?apikey=YOUR_API_KEY&postalCode=75001&fields=id,lang,country_name,country_flag_png,country_capital"
# Search with different language response
curl -X GET "https://api.countrydataapi.com/v1/countries/zipCode?apikey=YOUR_API_KEY&postalCode=28001&lang=es"
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://api.countrydataapi.com/v1/countries';
// Search country by postal code
async function searchCountryByPostalCode(postalCode, options = {}) {
const params = new URLSearchParams({
apikey: API_KEY,
postalCode: postalCode,
...options
});
try {
const response = await fetch(`${BASE_URL}/zipCode?${params}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error('Error searching country by postal code:', error);
throw error;
}
}
// Usage examples
// US ZIP code
searchCountryByPostalCode('10001')
.then(countries => {
console.log('Country for ZIP 10001:', countries[0]?.country_name);
});
// UK postal code
searchCountryByPostalCode('SW1A', {
fields: 'id,lang,country_name,country_flag_png,country_capital'
})
.then(countries => {
console.log('UK postal code result:', countries);
});
// French postal code with French response
searchCountryByPostalCode('75001', { lang: 'fr' })
.then(countries => {
console.log('French result:', countries);
});
// Validate if postal code belongs to expected country
async function validatePostalCode(postalCode, expectedCountryCode) {
const countries = await searchCountryByPostalCode(postalCode);
if (countries.length === 0) {
return { valid: false, message: 'Invalid postal code' };
}
const matchesExpected = countries.some(
c => c.country_cca2 === expectedCountryCode ||
c.country_cca3 === expectedCountryCode
);
return {
valid: matchesExpected,
country: countries[0]?.country_name,
message: matchesExpected
? 'Postal code matches expected country'
: `Postal code belongs to ${countries[0]?.country_name}`
};
}
import axios from 'axios';
const apiClient = axios.create({
baseURL: 'https://api.countrydataapi.com/v1/countries',
params: {
apikey: 'YOUR_API_KEY'
}
});
// Search country by postal code
async function searchCountryByPostalCode(postalCode, options = {}) {
try {
const response = await apiClient.get('/zipCode', {
params: {
postalCode: postalCode,
...options
}
});
return response.data;
} catch (error) {
if (error.response) {
console.error('API Error:', error.response.status, error.response.data);
} else {
console.error('Network Error:', error.message);
}
throw error;
}
}
// Address validation service
const addressValidationService = {
async validatePostalCode(postalCode) {
const countries = await searchCountryByPostalCode(postalCode, {
fields: 'id,lang,country_name,country_cca2,country_flag_png'
});
return {
isValid: countries.length > 0,
country: countries[0] || null
};
},
async getCountryFromPostalCode(postalCode) {
return searchCountryByPostalCode(postalCode, {
fields: 'id,lang,country_name,country_flag_png,country_capital,country_phone_code'
});
},
async matchPostalCodeToCountry(postalCode, countryCode) {
const result = await this.validatePostalCode(postalCode);
if (!result.isValid) {
return { matches: false, error: 'Invalid postal code' };
}
return {
matches: result.country.country_cca2 === countryCode,
actualCountry: result.country.country_name
};
}
};
// Usage
addressValidationService.validatePostalCode('90210')
.then(result => {
if (result.isValid) {
console.log(`Valid postal code for ${result.country.country_name}`);
}
});
import { useState, useCallback } from 'react';
const API_KEY = 'YOUR_API_KEY';
function usePostalCodeSearch() {
const [country, setCountry] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [isValid, setIsValid] = useState(null);
const searchByPostalCode = useCallback(async (postalCode) => {
if (!postalCode.trim()) {
setCountry(null);
setIsValid(null);
return;
}
setLoading(true);
setError(null);
const params = new URLSearchParams({
apikey: API_KEY,
postalCode: postalCode,
fields: 'id,lang,country_name,country_flag_png,country_capital,country_phone_code,country_cca2'
});
try {
const response = await fetch(
`https://api.countrydataapi.com/v1/countries/zipCode?${params}`
);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
if (data.length > 0) {
setCountry(data[0]);
setIsValid(true);
} else {
setCountry(null);
setIsValid(false);
}
} catch (err) {
setError(err.message);
setCountry(null);
setIsValid(false);
} finally {
setLoading(false);
}
}, []);
const reset = useCallback(() => {
setCountry(null);
setIsValid(null);
setError(null);
}, []);
return { country, loading, error, isValid, searchByPostalCode, reset };
}
function PostalCodeValidator() {
const [postalCode, setPostalCode] = useState('');
const { country, loading, error, isValid, searchByPostalCode, reset } = usePostalCodeSearch();
const handleSubmit = (e) => {
e.preventDefault();
searchByPostalCode(postalCode);
};
const handleInputChange = (e) => {
setPostalCode(e.target.value);
if (!e.target.value) {
reset();
}
};
return (
<div className="postal-code-validator">
<h2>Postal Code Validator</h2>
<p>Enter a postal code to find its country</p>
<form onSubmit={handleSubmit} className="search-form">
<input
type="text"
value={postalCode}
onChange={handleInputChange}
placeholder="Enter postal code (e.g., 10001, SW1A, 75001)"
className="postal-input"
/>
<button type="submit" disabled={loading || !postalCode.trim()}>
{loading ? 'Validating...' : 'Validate'}
</button>
</form>
{error && (
<div className="error-message">
Error: {error}
</div>
)}
{isValid === true && country && (
<div className="result valid">
<div className="status-badge success">Valid Postal Code</div>
<div className="country-card">
<img
src={country.country_flag_png}
alt={`${country.country_name} flag`}
className="country-flag"
/>
<div className="country-details">
<h3>{country.country_name}</h3>
<p><strong>Code:</strong> {country.country_cca2}</p>
<p><strong>Capital:</strong> {country.country_capital?.join(', ')}</p>
<p><strong>Phone:</strong> +{country.country_phone_code}</p>
</div>
</div>
</div>
)}
{isValid === false && !loading && (
<div className="result invalid">
<div className="status-badge error">Invalid Postal Code</div>
<p>No country found for postal code "{postalCode}"</p>
</div>
)}
</div>
);
}
export default PostalCodeValidator;
<template>
<div class="postal-code-validator">
<h2>Postal Code Validator</h2>
<p>Enter a postal code to find its country</p>
<form @submit.prevent="handleSubmit" class="search-form">
<input
v-model="postalCode"
type="text"
placeholder="Enter postal code (e.g., 10001, SW1A, 75001)"
class="postal-input"
@input="handleInputChange"
/>
<button type="submit" :disabled="loading || !postalCode.trim()">
{{ loading ? 'Validating...' : 'Validate' }}
</button>
</form>
<div v-if="error" class="error-message">
{{ error }}
</div>
<div v-if="isValid === true && country" class="result valid">
<div class="status-badge success">Valid Postal Code</div>
<div class="country-card">
<img
:src="country.country_flag_png"
:alt="`${country.country_name} flag`"
class="country-flag"
/>
<div class="country-details">
<h3>{{ country.country_name }}</h3>
<p><strong>Code:</strong> {{ country.country_cca2 }}</p>
<p><strong>Capital:</strong> {{ formatCapital(country.country_capital) }}</p>
<p><strong>Phone:</strong> +{{ country.country_phone_code }}</p>
</div>
</div>
</div>
<div v-if="isValid === false && !loading" class="result invalid">
<div class="status-badge error">Invalid Postal Code</div>
<p>No country found for postal code "{{ searchedCode }}"</p>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
const API_KEY = 'YOUR_API_KEY';
const postalCode = ref('');
const searchedCode = ref('');
const country = ref(null);
const loading = ref(false);
const error = ref(null);
const isValid = ref(null);
const formatCapital = (capital) => {
return capital?.join(', ') || 'N/A';
};
const handleInputChange = () => {
if (!postalCode.value) {
reset();
}
};
const reset = () => {
country.value = null;
isValid.value = null;
error.value = null;
};
const handleSubmit = async () => {
if (!postalCode.value.trim()) return;
loading.value = true;
error.value = null;
searchedCode.value = postalCode.value;
const params = new URLSearchParams({
apikey: API_KEY,
postalCode: postalCode.value,
fields: 'id,lang,country_name,country_flag_png,country_capital,country_phone_code,country_cca2'
});
try {
const response = await fetch(
`https://api.countrydataapi.com/v1/countries/zipCode?${params}`
);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
if (data.length > 0) {
country.value = data[0];
isValid.value = true;
} else {
country.value = null;
isValid.value = false;
}
} catch (err) {
error.value = err.message;
country.value = null;
isValid.value = false;
} finally {
loading.value = false;
}
};
</script>
<style scoped>
.postal-code-validator {
max-width: 500px;
margin: 0 auto;
padding: 20px;
}
.search-form {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
.postal-input {
flex: 1;
padding: 12px;
font-size: 16px;
border: 1px solid #ddd;
border-radius: 4px;
}
button {
padding: 12px 24px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}
button:disabled {
background-color: #ccc;
cursor: not-allowed;
}
.result {
padding: 20px;
border-radius: 8px;
margin-top: 20px;
}
.result.valid {
background-color: #d4edda;
border: 1px solid #c3e6cb;
}
.result.invalid {
background-color: #f8d7da;
border: 1px solid #f5c6cb;
}
.status-badge {
display: inline-block;
padding: 5px 10px;
border-radius: 4px;
font-weight: bold;
margin-bottom: 15px;
}
.status-badge.success {
background-color: #28a745;
color: white;
}
.status-badge.error {
background-color: #dc3545;
color: white;
}
.country-card {
display: flex;
gap: 20px;
align-items: flex-start;
}
.country-flag {
width: 100px;
height: auto;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.country-details h3 {
margin: 0 0 10px 0;
}
.country-details p {
margin: 5px 0;
}
.error-message {
color: #dc3545;
padding: 10px;
background-color: #f8d7da;
border-radius: 4px;
}
</style>
// postal-code.service.ts
import { Injectable, inject } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable, catchError, throwError, map } from 'rxjs';
export interface Country {
id: string;
lang: string;
country_name: string;
country_flag_png?: string;
country_capital?: string[];
country_phone_code?: string;
country_cca2?: string;
country_cca3?: string;
}
export interface ValidationResult {
isValid: boolean;
country: Country | null;
}
@Injectable({
providedIn: 'root'
})
export class PostalCodeService {
private http = inject(HttpClient);
private readonly API_KEY = 'YOUR_API_KEY';
private readonly BASE_URL = 'https://api.countrydataapi.com/v1/countries';
searchByPostalCode(postalCode: string, options: Record<string, string> = {}): Observable<Country[]> {
let params = new HttpParams()
.set('apikey', this.API_KEY)
.set('postalCode', postalCode)
.set('fields', 'id,lang,country_name,country_flag_png,country_capital,country_phone_code,country_cca2');
Object.entries(options).forEach(([key, value]) => {
params = params.set(key, value);
});
return this.http.get<Country[]>(`${this.BASE_URL}/zipCode`, { params }).pipe(
catchError(error => {
console.error('Postal code search error:', error);
return throwError(() => new Error('Failed to search by postal code'));
})
);
}
validatePostalCode(postalCode: string): Observable<ValidationResult> {
return this.searchByPostalCode(postalCode).pipe(
map(countries => ({
isValid: countries.length > 0,
country: countries[0] || null
}))
);
}
matchPostalCodeToCountry(postalCode: string, countryCode: string): Observable<{matches: boolean; actualCountry?: string}> {
return this.validatePostalCode(postalCode).pipe(
map(result => {
if (!result.isValid) {
return { matches: false };
}
return {
matches: result.country?.country_cca2 === countryCode,
actualCountry: result.country?.country_name
};
})
);
}
}
// postal-code-validator.component.ts
import { Component, inject, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { PostalCodeService, Country } from './postal-code.service';
@Component({
selector: 'app-postal-code-validator',
standalone: true,
imports: [CommonModule, FormsModule],
template: `
<div class="postal-code-validator">
<h2>Postal Code Validator</h2>
<p>Enter a postal code to find its country</p>
<form (ngSubmit)="validatePostalCode()" class="search-form">
<input
type="text"
[(ngModel)]="postalCode"
name="postalCode"
placeholder="Enter postal code (e.g., 10001, SW1A, 75001)"
class="postal-input"
(input)="onInputChange()"
/>
<button type="submit" [disabled]="loading() || !postalCode.trim()">
{{ loading() ? 'Validating...' : 'Validate' }}
</button>
</form>
<div *ngIf="error()" class="error-message">
{{ error() }}
</div>
<div *ngIf="isValid() === true && country()" class="result valid">
<div class="status-badge success">Valid Postal Code</div>
<div class="country-card">
<img
[src]="country()!.country_flag_png"
[alt]="country()!.country_name + ' flag'"
class="country-flag"
/>
<div class="country-details">
<h3>{{ country()!.country_name }}</h3>
<p><strong>Code:</strong> {{ country()!.country_cca2 }}</p>
<p><strong>Capital:</strong> {{ formatCapital(country()!.country_capital) }}</p>
<p><strong>Phone:</strong> +{{ country()!.country_phone_code }}</p>
</div>
</div>
</div>
<div *ngIf="isValid() === false && !loading()" class="result invalid">
<div class="status-badge error">Invalid Postal Code</div>
<p>No country found for postal code "{{ searchedCode() }}"</p>
</div>
</div>
`,
styles: [`
.postal-code-validator {
max-width: 500px;
margin: 0 auto;
padding: 20px;
}
.search-form {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
.postal-input {
flex: 1;
padding: 12px;
font-size: 16px;
border: 1px solid #ddd;
border-radius: 4px;
}
button {
padding: 12px 24px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:disabled {
background-color: #ccc;
}
.result {
padding: 20px;
border-radius: 8px;
margin-top: 20px;
}
.result.valid {
background-color: #d4edda;
border: 1px solid #c3e6cb;
}
.result.invalid {
background-color: #f8d7da;
border: 1px solid #f5c6cb;
}
.status-badge {
display: inline-block;
padding: 5px 10px;
border-radius: 4px;
font-weight: bold;
margin-bottom: 15px;
}
.status-badge.success {
background-color: #28a745;
color: white;
}
.status-badge.error {
background-color: #dc3545;
color: white;
}
.country-card {
display: flex;
gap: 20px;
align-items: flex-start;
}
.country-flag {
width: 100px;
height: auto;
border-radius: 4px;
}
.error-message {
color: #dc3545;
padding: 10px;
background-color: #f8d7da;
border-radius: 4px;
}
`]
})
export class PostalCodeValidatorComponent {
private postalCodeService = inject(PostalCodeService);
postalCode = '';
country = signal<Country | null>(null);
loading = signal(false);
error = signal<string | null>(null);
isValid = signal<boolean | null>(null);
searchedCode = signal('');
formatCapital(capital?: string[]): string {
return capital?.join(', ') || 'N/A';
}
onInputChange(): void {
if (!this.postalCode) {
this.reset();
}
}
reset(): void {
this.country.set(null);
this.isValid.set(null);
this.error.set(null);
}
validatePostalCode(): void {
if (!this.postalCode.trim()) return;
this.loading.set(true);
this.error.set(null);
this.searchedCode.set(this.postalCode);
this.postalCodeService.validatePostalCode(this.postalCode).subscribe({
next: (result) => {
this.country.set(result.country);
this.isValid.set(result.isValid);
this.loading.set(false);
},
error: (err) => {
this.error.set(err.message);
this.country.set(null);
this.isValid.set(false);
this.loading.set(false);
}
});
}
}
import requests
from typing import Optional, List, Dict, Any
from dataclasses import dataclass
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.countrydataapi.com/v1/countries"
@dataclass
class PostalCodeResult:
"""Represents a postal code lookup result"""
is_valid: bool
country_name: str
country_code: str
flag_url: str
capital: List[str]
phone_code: str
def search_country_by_postal_code(
postal_code: str,
fields: Optional[str] = None,
lang: str = "en"
) -> List[Dict[str, Any]]:
"""
Search for countries by postal code.
Args:
postal_code: The postal code to search for
fields: Comma-separated list of fields to return
lang: Language for the response (default: "en")
Returns:
List of countries containing the postal code
"""
params = {
"apikey": API_KEY,
"postalCode": postal_code,
"lang": lang
}
if fields:
params["fields"] = fields
try:
response = requests.get(f"{BASE_URL}/zipCode", params=params)
response.raise_for_status()
return response.json()
except requests.exceptions.HTTPError as e:
print(f"HTTP Error: {e}")
raise
except requests.exceptions.RequestException as e:
print(f"Request Error: {e}")
raise
def validate_postal_code(postal_code: str) -> PostalCodeResult:
"""
Validate a postal code and get country information.
Args:
postal_code: The postal code to validate
Returns:
PostalCodeResult with validation status and country info
"""
fields = "id,lang,country_name,country_flag_png,country_capital,country_phone_code,country_cca2"
try:
countries = search_country_by_postal_code(postal_code, fields=fields)
if not countries:
return PostalCodeResult(
is_valid=False,
country_name="",
country_code="",
flag_url="",
capital=[],
phone_code=""
)
country = countries[0]
return PostalCodeResult(
is_valid=True,
country_name=country.get("country_name", ""),
country_code=country.get("country_cca2", ""),
flag_url=country.get("country_flag_png", ""),
capital=country.get("country_capital", []),
phone_code=country.get("country_phone_code", "")
)
except Exception:
return PostalCodeResult(
is_valid=False,
country_name="",
country_code="",
flag_url="",
capital=[],
phone_code=""
)
def match_postal_code_to_country(postal_code: str, expected_country_code: str) -> Dict[str, Any]:
"""
Check if a postal code belongs to an expected country.
Args:
postal_code: The postal code to check
expected_country_code: The expected country code (ISO 3166-1 alpha-2)
Returns:
Dictionary with match result and actual country
"""
result = validate_postal_code(postal_code)
if not result.is_valid:
return {
"matches": False,
"error": "Invalid postal code"
}
matches = result.country_code.upper() == expected_country_code.upper()
return {
"matches": matches,
"expected_country": expected_country_code,
"actual_country": result.country_name,
"actual_country_code": result.country_code
}
class AddressValidator:
"""Service for validating addresses using postal codes"""
def __init__(self, api_key: str):
global API_KEY
API_KEY = api_key
def validate_address(self, postal_code: str, country_code: str) -> Dict[str, Any]:
"""Validate if postal code matches country"""
return match_postal_code_to_country(postal_code, country_code)
def get_country_from_postal_code(self, postal_code: str) -> Optional[str]:
"""Get country name from postal code"""
result = validate_postal_code(postal_code)
return result.country_name if result.is_valid else None
# Example usage
if __name__ == "__main__":
# Basic validation
print("Validating postal codes...")
# US ZIP code
us_result = validate_postal_code("10001")
if us_result.is_valid:
print(f"10001 (NYC): {us_result.country_name} ({us_result.country_code})")
# UK postal code
uk_result = validate_postal_code("SW1A")
if uk_result.is_valid:
print(f"SW1A (London): {uk_result.country_name} ({uk_result.country_code})")
# German postal code
de_result = validate_postal_code("10115")
if de_result.is_valid:
print(f"10115 (Berlin): {de_result.country_name} ({de_result.country_code})")
# Match validation
print("\nMatching postal codes to countries...")
match_result = match_postal_code_to_country("90210", "US")
print(f"90210 matches US: {match_result['matches']}")
wrong_match = match_postal_code_to_country("90210", "GB")
print(f"90210 matches GB: {wrong_match['matches']} (actual: {wrong_match['actual_country']})")
<?php
class PostalCodeService
{
private string $apiKey;
private string $baseUrl = 'https://api.countrydataapi.com/v1/countries';
public function __construct(string $apiKey)
{
$this->apiKey = $apiKey;
}
/**
* Search for countries by postal code
*
* @param string $postalCode The postal code to search for
* @param array $options Additional options (fields, lang)
* @return array List of countries
* @throws Exception
*/
public function searchByPostalCode(string $postalCode, array $options = []): array
{
$params = array_merge([
'apikey' => $this->apiKey,
'postalCode' => $postalCode
], $options);
$url = $this->baseUrl . '/zipCode?' . http_build_query($params);
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_HTTPHEADER => [
'Accept: application/json'
]
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
throw new Exception("cURL Error: $error");
}
if ($httpCode !== 200) {
throw new Exception("HTTP Error: $httpCode");
}
return json_decode($response, true) ?? [];
}
/**
* Validate a postal code
*
* @param string $postalCode The postal code to validate
* @return array Validation result with country info
*/
public function validatePostalCode(string $postalCode): array
{
try {
$countries = $this->searchByPostalCode($postalCode, [
'fields' => 'id,lang,country_name,country_flag_png,country_capital,country_phone_code,country_cca2'
]);
if (empty($countries)) {
return [
'isValid' => false,
'country' => null
];
}
return [
'isValid' => true,
'country' => $countries[0]
];
} catch (Exception $e) {
return [
'isValid' => false,
'country' => null,
'error' => $e->getMessage()
];
}
}
/**
* Check if postal code matches expected country
*
* @param string $postalCode The postal code to check
* @param string $expectedCountryCode Expected country code (ISO 3166-1 alpha-2)
* @return array Match result
*/
public function matchPostalCodeToCountry(string $postalCode, string $expectedCountryCode): array
{
$result = $this->validatePostalCode($postalCode);
if (!$result['isValid']) {
return [
'matches' => false,
'error' => 'Invalid postal code'
];
}
$actualCode = strtoupper($result['country']['country_cca2'] ?? '');
$expectedCode = strtoupper($expectedCountryCode);
return [
'matches' => $actualCode === $expectedCode,
'expectedCountry' => $expectedCode,
'actualCountry' => $result['country']['country_name'],
'actualCountryCode' => $actualCode
];
}
}
/**
* Address validation helper class
*/
class AddressValidator
{
private PostalCodeService $postalCodeService;
public function __construct(string $apiKey)
{
$this->postalCodeService = new PostalCodeService($apiKey);
}
/**
* Validate address components
*
* @param array $address Address with 'postalCode' and 'countryCode' keys
* @return array Validation result
*/
public function validateAddress(array $address): array
{
if (empty($address['postalCode'])) {
return ['valid' => false, 'error' => 'Postal code is required'];
}
if (empty($address['countryCode'])) {
// Just validate the postal code exists
$result = $this->postalCodeService->validatePostalCode($address['postalCode']);
return [
'valid' => $result['isValid'],
'detectedCountry' => $result['country']['country_name'] ?? null
];
}
// Validate postal code matches country
$match = $this->postalCodeService->matchPostalCodeToCountry(
$address['postalCode'],
$address['countryCode']
);
return [
'valid' => $match['matches'],
'detectedCountry' => $match['actualCountry'] ?? null,
'mismatch' => !$match['matches'] && isset($match['actualCountry'])
];
}
}
// Example usage
$apiKey = 'YOUR_API_KEY';
$postalCodeService = new PostalCodeService($apiKey);
try {
// Basic validation
echo "Validating postal codes...\n";
// US ZIP code
$usResult = $postalCodeService->validatePostalCode('10001');
if ($usResult['isValid']) {
echo "10001 (NYC): " . $usResult['country']['country_name'] . "\n";
}
// UK postal code
$ukResult = $postalCodeService->validatePostalCode('SW1A');
if ($ukResult['isValid']) {
echo "SW1A (London): " . $ukResult['country']['country_name'] . "\n";
}
// French postal code
$frResult = $postalCodeService->validatePostalCode('75001');
if ($frResult['isValid']) {
echo "75001 (Paris): " . $frResult['country']['country_name'] . "\n";
}
// Match validation
echo "\nMatching postal codes to countries...\n";
$match1 = $postalCodeService->matchPostalCodeToCountry('90210', 'US');
echo "90210 matches US: " . ($match1['matches'] ? 'Yes' : 'No') . "\n";
$match2 = $postalCodeService->matchPostalCodeToCountry('90210', 'GB');
echo "90210 matches GB: " . ($match2['matches'] ? 'Yes' : 'No');
echo " (actual: " . $match2['actualCountry'] . ")\n";
// Address validation
echo "\nAddress validation...\n";
$validator = new AddressValidator($apiKey);
$validAddress = $validator->validateAddress([
'postalCode' => '10001',
'countryCode' => 'US'
]);
echo "NYC address valid: " . ($validAddress['valid'] ? 'Yes' : 'No') . "\n";
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
}
?>
| Status Code | Description |
|---|---|
| 200 | Success - Returns array of countries |
| 400 | Bad Request - Invalid or missing postal code parameter |
| 401 | Unauthorized - Invalid or missing API key |
| 404 | Not Found - No countries found with the given postal code |
| 429 | Too Many Requests - Rate limit exceeded |
| 500 | Internal Server Error - Server-side error |