Documentación de la API - Endpoints y Ejemplos

Buscar códigos postales por país

Country Data API proporciona información detallada sobre +200 países diferentes

Descripción general

El endpoint /v1/zipcodes/country devuelve todos los códigos postales de un país específico, organizados por estado/provincia. Es perfecto para aplicaciones que necesitan cobertura completa de códigos postales para un país específico.

Endpoint

GET https://api.countrydataapi.com/v1/zipcodes/country

Autenticación

Incluye tu clave API como parámetro de consulta:

?apikey=tu-clave-api

Tu clave API es como una contraseña, mantenla segura. Obtén tu clave desde el panel de cuenta.

Parámetros de consulta

Parámetro Tipo Requerido Descripción
apikey string Tu clave de autenticación API
country string ID del país, código ISO (ej. "US", "DE"), o nombre
lang string No Código de idioma para la respuesta (predeterminado: en)
limitToken number No Máximo de tokens a gastar en esta petición (predeterminado: 1000)

Idiomas soportados

  • en - Inglés (predeterminado)
  • es - Español
  • pt - Portugués
  • fr - Francés
  • de - Alemán
  • it - Italiano

Uso de tokens

Cada código postal devuelto costará 1 token.

Nota: Países grandes como Estados Unidos o Alemania tienen miles de códigos postales. Usa limitToken para controlar costos.

Formato de respuesta

Respuesta exitosa

[
  {
    "id": "8dd25479-067a-43b0-ac4a-8e7faf2bcaf",
    "country_name": "United States",
    "state_names": [
      {
        "id": "8dd25479-067a-43b0-ac4a-8e7faf2bcad",
        "name": "California",
        "postal_code": [
          "90001",
          "90002",
          "90003",
          "90004"
        ]
      },
      {
        "id": "9ae35480-178b-54c1-bd5b-9f8gbf3cdeh",
        "name": "Texas",
        "postal_code": [
          "73301",
          "73344",
          "75001"
        ]
      }
    ]
  }
]

Campos de respuesta

Campo Tipo Descripción
id string Identificador único del país
country_name string Nombre del país en el idioma solicitado
state_names array Array de objetos de estado que contienen códigos postales
state_names[].id string Identificador único del estado
state_names[].name string Nombre del estado/provincia
state_names[].postal_code array Array de códigos postales para este estado

Respuesta de error

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

Consulta la documentación de códigos de error para todos los códigos de error posibles.

Ejemplos de código

cURL

# Buscar por nombre de país
curl -X GET "https://api.countrydataapi.com/v1/zipcodes/country?apikey=tu-clave-api&country=Germany&lang=en"

# Buscar por código ISO
curl -X GET "https://api.countrydataapi.com/v1/zipcodes/country?apikey=tu-clave-api&country=US&lang=en&limitToken=500"

# Buscar por ID de país
curl -X GET "https://api.countrydataapi.com/v1/zipcodes/country?apikey=tu-clave-api&country=66c7a6c9e4bda21f4ab10fd5&lang=en"

JavaScript (Fetch)

const API_KEY = 'tu-clave-api';
const BASE_URL = 'https://api.countrydataapi.com/v1';

async function getZipcodesByCountry(country, limitToken = 1000) {
  try {
    const params = new URLSearchParams({
      apikey: API_KEY,
      country: country,
      lang: 'en',
      limitToken: limitToken.toString()
    });

    const response = await fetch(`${BASE_URL}/zipcodes/country?${params}`);

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

    const data = await response.json();
    return data;
  } catch (error) {
    console.error('Error fetching zipcodes by country:', error);
    throw error;
  }
}

// Ejemplos de uso
// Por nombre de país
const germanyZipcodes = await getZipcodesByCountry('Germany');
console.log(germanyZipcodes);

// Por código ISO
const usZipcodes = await getZipcodesByCountry('US', 500);
console.log(usZipcodes);

// Por ID de país
const mexicoZipcodes = await getZipcodesByCountry('66c7a6c9e4bda21f4ab10fa8');
console.log(mexicoZipcodes);

JavaScript (Axios)

import axios from 'axios';

const API_KEY = 'tu-clave-api';
const BASE_URL = 'https://api.countrydataapi.com/v1';

async function getZipcodesByCountry(country, limitToken = 1000) {
  try {
    const response = await axios.get(`${BASE_URL}/zipcodes/country`, {
      params: {
        apikey: API_KEY,
        country: country,
        lang: 'en',
        limitToken: limitToken
      }
    });

    return response.data;
  } catch (error) {
    if (error.response) {
      console.error('API Error:', error.response.data);
      throw new Error(error.response.data.error?.message || 'API Error');
    } else {
      console.error('Network Error:', error.message);
      throw error;
    }
  }
}

// Uso
const data = await getZipcodesByCountry('France', 500);
console.log(`Encontrados códigos postales para ${data[0]?.state_names?.length || 0} estados`);

React

import { useState, useEffect } from 'react';

const API_KEY = 'tu-clave-api';
const BASE_URL = 'https://api.countrydataapi.com/v1';

function useCountryZipcodes(country, limitToken = 1000) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  useEffect(() => {
    if (!country) {
      setData(null);
      return;
    }

    async function fetchZipcodes() {
      try {
        setLoading(true);
        setError(null);

        const params = new URLSearchParams({
          apikey: API_KEY,
          country: country,
          lang: 'en',
          limitToken: limitToken.toString()
        });

        const response = await fetch(`${BASE_URL}/zipcodes/country?${params}`);

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

        const result = await response.json();
        setData(result[0] || null);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    }

    fetchZipcodes();
  }, [country, limitToken]);

  return { data, loading, error };
}

// Ejemplo de componente
function CountryZipcodeExplorer() {
  const [selectedCountry, setSelectedCountry] = useState('');
  const { data, loading, error } = useCountryZipcodes(selectedCountry, 500);

  const countries = [
    { code: 'US', name: 'Estados Unidos' },
    { code: 'DE', name: 'Alemania' },
    { code: 'FR', name: 'Francia' },
    { code: 'ES', name: 'España' },
    { code: 'MX', name: 'México' }
  ];

  const totalZipcodes = data?.state_names?.reduce(
    (sum, state) => sum + state.postal_code.length,
    0
  ) || 0;

  return (
    <div>
      <h2>Explorar Códigos Postales por País</h2>

      <select
        value={selectedCountry}
        onChange={(e) => setSelectedCountry(e.target.value)}
      >
        <option value="">Selecciona un país...</option>
        {countries.map(c => (
          <option key={c.code} value={c.code}>{c.name}</option>
        ))}
      </select>

      {loading && <p>Cargando códigos postales...</p>}
      {error && <p style={{ color: 'red' }}>Error: {error}</p>}

      {data && (
        <div>
          <h3>{data.country_name}</h3>
          <p>Total de estados: {data.state_names.length}</p>
          <p>Total de códigos postales cargados: {totalZipcodes}</p>

          <div style={{ maxHeight: '400px', overflow: 'auto' }}>
            {data.state_names.map(state => (
              <details key={state.id}>
                <summary>
                  {state.name} ({state.postal_code.length} códigos)
                </summary>
                <p style={{ fontSize: '0.9em', color: '#666' }}>
                  {state.postal_code.slice(0, 20).join(', ')}
                  {state.postal_code.length > 20 && '...'}
                </p>
              </details>
            ))}
          </div>
        </div>
      )}
    </div>
  );
}

export default CountryZipcodeExplorer;

Vue 3

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

const API_KEY = 'tu-clave-api';
const BASE_URL = 'https://api.countrydataapi.com/v1';

const selectedCountry = ref('');
const countryData = ref(null);
const loading = ref(false);
const error = ref(null);

const countries = [
  { code: 'US', name: 'Estados Unidos' },
  { code: 'DE', name: 'Alemania' },
  { code: 'FR', name: 'Francia' },
  { code: 'ES', name: 'España' },
  { code: 'MX', name: 'México' }
];

const totalZipcodes = computed(() => {
  if (!countryData.value?.state_names) return 0;
  return countryData.value.state_names.reduce(
    (sum, state) => sum + state.postal_code.length,
    0
  );
});

watch(selectedCountry, async (newCountry) => {
  if (!newCountry) {
    countryData.value = null;
    return;
  }

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

    const params = new URLSearchParams({
      apikey: API_KEY,
      country: newCountry,
      lang: 'en',
      limitToken: '500'
    });

    const response = await fetch(`${BASE_URL}/zipcodes/country?${params}`);

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

    const data = await response.json();
    countryData.value = data[0] || null;
  } catch (err) {
    error.value = err.message;
  } finally {
    loading.value = false;
  }
});
</script>

<template>
  <div>
    <h2>Explorar Códigos Postales por País</h2>

    <select v-model="selectedCountry">
      <option value="">Selecciona un país...</option>
      <option v-for="c in countries" :key="c.code" :value="c.code">
        {{ c.name }}
      </option>
    </select>

    <div v-if="loading">Cargando códigos postales...</div>
    <div v-else-if="error" style="color: red;">Error: {{ error }}</div>

    <div v-else-if="countryData">
      <h3>{{ countryData.country_name }}</h3>
      <p>Total de estados: {{ countryData.state_names.length }}</p>
      <p>Total de códigos postales cargados: {{ totalZipcodes }}</p>

      <div style="max-height: 400px; overflow: auto;">
        <details v-for="state in countryData.state_names" :key="state.id">
          <summary>
            {{ state.name }} ({{ state.postal_code.length }} códigos)
          </summary>
          <p style="font-size: 0.9em; color: #666;">
            {{ state.postal_code.slice(0, 20).join(', ') }}
            <span v-if="state.postal_code.length > 20">...</span>
          </p>
        </details>
      </div>
    </div>
  </div>
</template>

Angular

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

interface State {
  id: string;
  name: string;
  postal_code: string[];
}

interface CountryZipcode {
  id: string;
  country_name: string;
  state_names: State[];
}

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

  constructor(private http: HttpClient) {}

  getZipcodesByCountry(
    country: string,
    limitToken: number = 1000
  ): Observable<CountryZipcode[]> {
    const params = new HttpParams()
      .set('apikey', this.API_KEY)
      .set('country', country)
      .set('lang', 'en')
      .set('limitToken', limitToken.toString());

    return this.http.get<CountryZipcode[]>(
      `${this.BASE_URL}/zipcodes/country`,
      { params }
    );
  }
}

// country-zipcode-explorer.component.ts
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { ZipcodeService } from './zipcode.service';

interface Country {
  code: string;
  name: string;
}

@Component({
  selector: 'app-country-zipcode-explorer',
  standalone: true,
  imports: [CommonModule, FormsModule],
  template: `
    <div>
      <h2>Explorar Códigos Postales por País</h2>

      <select [(ngModel)]="selectedCountry" (ngModelChange)="onCountryChange()">
        <option value="">Selecciona un país...</option>
        <option *ngFor="let c of countries" [value]="c.code">
          {{ c.name }}
        </option>
      </select>

      <div *ngIf="loading">Cargando códigos postales...</div>
      <div *ngIf="error" style="color: red;">Error: {{ error }}</div>

      <div *ngIf="countryData && !loading">
        <h3>{{ countryData.country_name }}</h3>
        <p>Total de estados: {{ countryData.state_names.length }}</p>
        <p>Total de códigos postales cargados: {{ getTotalZipcodes() }}</p>

        <div style="max-height: 400px; overflow: auto;">
          <details *ngFor="let state of countryData.state_names">
            <summary>
              {{ state.name }} ({{ state.postal_code.length }} códigos)
            </summary>
            <p style="font-size: 0.9em; color: #666;">
              {{ state.postal_code.slice(0, 20).join(', ') }}
              <span *ngIf="state.postal_code.length > 20">...</span>
            </p>
          </details>
        </div>
      </div>
    </div>
  `
})
export class CountryZipcodeExplorerComponent {
  countries: Country[] = [
    { code: 'US', name: 'Estados Unidos' },
    { code: 'DE', name: 'Alemania' },
    { code: 'FR', name: 'Francia' },
    { code: 'ES', name: 'España' },
    { code: 'MX', name: 'México' }
  ];

  selectedCountry = '';
  countryData: any = null;
  loading = false;
  error: string | null = null;

  constructor(private zipcodeService: ZipcodeService) {}

  onCountryChange() {
    if (!this.selectedCountry) {
      this.countryData = null;
      return;
    }

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

    this.zipcodeService.getZipcodesByCountry(this.selectedCountry, 500).subscribe({
      next: (data) => {
        this.countryData = data[0] || null;
        this.loading = false;
      },
      error: (err) => {
        this.error = err.message;
        this.loading = false;
      }
    });
  }

  getTotalZipcodes(): number {
    if (!this.countryData?.state_names) return 0;
    return this.countryData.state_names.reduce(
      (sum: number, state: any) => sum + state.postal_code.length,
      0
    );
  }
}

PHP

<?php
$apiKey = 'tu-clave-api';
$country = 'Germany'; // Puede ser nombre de país, código ISO o ID
$limitToken = 500;

$url = "https://api.countrydataapi.com/v1/zipcodes/country?" . http_build_query([
    'apikey' => $apiKey,
    'country' => $country,
    'lang' => 'en',
    'limitToken' => $limitToken
]);

// Usando cURL
$ch = curl_init();
curl_setopt_array($ch, [
    CURLOPT_URL => $url,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTPHEADER => [
        'Accept: application/json'
    ]
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlError = curl_error($ch);
curl_close($ch);

if ($curlError) {
    die("cURL Error: {$curlError}");
}

if ($httpCode === 200) {
    $data = json_decode($response, true);

    if (!empty($data)) {
        $countryData = $data[0];
        echo "País: " . $countryData['country_name'] . "\n";
        echo "Total de Estados: " . count($countryData['state_names']) . "\n";

        $totalZipcodes = 0;
        foreach ($countryData['state_names'] as $state) {
            $totalZipcodes += count($state['postal_code']);
            echo "\n  Estado: " . $state['name'] . "\n";
            echo "  Códigos Postales: " . count($state['postal_code']) . "\n";
            echo "  Muestra: " . implode(', ', array_slice($state['postal_code'], 0, 5)) . "...\n";
        }
        echo "\nTotal de Códigos Postales: {$totalZipcodes}\n";
    } else {
        echo "No se encontraron códigos postales para el país: {$country}\n";
    }
} else {
    echo "Error: HTTP {$httpCode}\n";
    $error = json_decode($response, true);
    echo "Mensaje: " . ($error['error']['message'] ?? 'Error desconocido') . "\n";
}

// Función reutilizable
function getZipcodesByCountry($apiKey, $country, $lang = 'en', $limitToken = 1000) {
    $url = "https://api.countrydataapi.com/v1/zipcodes/country?" . http_build_query([
        'apikey' => $apiKey,
        'country' => $country,
        'lang' => $lang,
        'limitToken' => $limitToken
    ]);

    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 30
    ]);

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($httpCode !== 200) {
        throw new Exception("API Error: HTTP {$httpCode}");
    }

    return json_decode($response, true);
}

// Uso
try {
    // Por código ISO
    $usData = getZipcodesByCountry($apiKey, 'US', 'en', 100);
    print_r($usData);

    // Por nombre de país en español
    $spainData = getZipcodesByCountry($apiKey, 'Spain', 'es', 200);
    print_r($spainData);
} catch (Exception $e) {
    echo $e->getMessage();
}
?>

Python

import requests
from typing import List, Dict, Any, Optional

API_KEY = 'tu-clave-api'
BASE_URL = 'https://api.countrydataapi.com/v1'

def get_zipcodes_by_country(
    country: str,
    lang: str = 'en',
    limit_token: int = 1000
) -> List[Dict[str, Any]]:
    """
    Obtener códigos postales de un país específico.

    Args:
        country: Nombre del país, código ISO o ID
        lang: Código de idioma para la respuesta
        limit_token: Máximo de tokens a gastar en esta petición

    Returns:
        Lista conteniendo datos del país con estados y códigos postales
    """
    try:
        response = requests.get(
            f'{BASE_URL}/zipcodes/country',
            params={
                'apikey': API_KEY,
                'country': country,
                'lang': lang,
                'limitToken': limit_token
            },
            timeout=30
        )
        response.raise_for_status()
        return response.json()
    except requests.exceptions.HTTPError as e:
        print(f'HTTP Error: {e.response.status_code}')
        print(f'Response: {e.response.text}')
        raise
    except requests.exceptions.RequestException as e:
        print(f'Request Error: {e}')
        raise

def count_total_zipcodes(country_data: Dict[str, Any]) -> int:
    """Contar total de códigos postales en datos de país"""
    return sum(
        len(state['postal_code'])
        for state in country_data.get('state_names', [])
    )

# Ejemplos de uso
if __name__ == '__main__':
    # Buscar por nombre de país
    germany_data = get_zipcodes_by_country('Germany', limit_token=500)
    if germany_data:
        country = germany_data[0]
        print(f"País: {country['country_name']}")
        print(f"Total de estados: {len(country['state_names'])}")
        print(f"Total de códigos postales: {count_total_zipcodes(country)}")

        for state in country['state_names'][:3]:
            print(f"\n  Estado: {state['name']}")
            print(f"  Códigos: {', '.join(state['postal_code'][:5])}...")

    # Buscar por código ISO
    print("\n--- Francia (por código ISO) ---")
    france_data = get_zipcodes_by_country('FR', limit_token=300)
    if france_data:
        print(f"Total de códigos postales: {count_total_zipcodes(france_data[0])}")

    # Buscar en español
    print("\n--- México (en español) ---")
    mexico_data = get_zipcodes_by_country('Mexico', lang='es', limit_token=200)
    if mexico_data:
        for state in mexico_data[0]['state_names'][:3]:
            print(f"  Estado: {state['name']}")

# Versión asíncrona usando aiohttp
import aiohttp
import asyncio

async def get_zipcodes_by_country_async(
    country: str,
    lang: str = 'en',
    limit_token: int = 1000
) -> List[Dict[str, Any]]:
    """Versión asíncrona usando aiohttp"""
    async with aiohttp.ClientSession() as session:
        async with session.get(
            f'{BASE_URL}/zipcodes/country',
            params={
                'apikey': API_KEY,
                'country': country,
                'lang': lang,
                'limitToken': limit_token
            }
        ) as response:
            if response.status != 200:
                text = await response.text()
                raise Exception(f'API Error: {response.status} - {text}')
            return await response.json()

# Obtener múltiples países en paralelo
async def get_multiple_countries(countries: List[str]) -> Dict[str, Any]:
    """Obtener códigos postales de múltiples países en paralelo"""
    tasks = [
        get_zipcodes_by_country_async(country, limit_token=100)
        for country in countries
    ]
    results = await asyncio.gather(*tasks, return_exceptions=True)
    return dict(zip(countries, results))

# Ejecutar async
# data = asyncio.run(get_multiple_countries(['US', 'DE', 'FR']))

Manejo de errores

Siempre implementa un manejo de errores adecuado:

async function getZipcodesWithErrorHandling(country) {
  try {
    const response = await fetch(
      `https://api.countrydataapi.com/v1/zipcodes/country?apikey=tu-clave-api&country=${encodeURIComponent(country)}`
    );

    if (!response.ok) {
      const errorData = await response.json().catch(() => ({}));

      switch (response.status) {
        case 400:
          throw new Error(errorData.error?.message || 'Parámetros de petición inválidos');
        case 401:
          throw new Error('Clave API inválida');
        case 402:
          throw new Error('Tokens insuficientes. Por favor actualiza tu plan.');
        case 404:
          throw new Error(`País "${country}" no encontrado`);
        case 429:
          throw new Error('Límite de tasa excedido. Por favor intenta más tarde.');
        default:
          throw new Error(`HTTP error! status: ${response.status}`);
      }
    }

    const data = await response.json();

    if (!Array.isArray(data) || data.length === 0) {
      console.warn(`No se encontraron códigos postales para el país: ${country}`);
      return null;
    }

    return data[0];
  } catch (error) {
    console.error('Error al obtener códigos postales del país:', error.message);
    throw error;
  }
}

Códigos de error comunes

Código de Error Descripción Solución
INVALID_API_KEY La clave API es inválida Verifica tu clave API en el panel de cuenta
MISSING_PARAMETER Falta el parámetro country Incluye nombre del país, código ISO o ID
COUNTRY_NOT_FOUND El país no existe Verifica el nombre del país o usa un código ISO válido
QUOTA_EXCEEDED Límite diario de tokens alcanzado Actualiza tu plan o espera el reinicio

Casos de uso

1. Poblar formulario de dirección por país

async function populateAddressForm(countryCode) {
  const data = await getZipcodesByCountry(countryCode);

  if (!data) return;

  const stateSelect = document.getElementById('state');
  stateSelect.innerHTML = '<option value="">Selecciona estado...</option>';

  data.state_names.forEach(state => {
    const option = new Option(state.name, state.id);
    option.dataset.zipcodes = JSON.stringify(state.postal_code);
    stateSelect.add(option);
  });
}

2. Validar código postal para país

async function validatePostalCode(countryCode, postalCode) {
  const data = await getZipcodesByCountry(countryCode);

  if (!data) {
    return { valid: false, message: 'País no encontrado' };
  }

  for (const state of data.state_names) {
    if (state.postal_code.includes(postalCode)) {
      return {
        valid: true,
        state: state.name,
        message: `Código postal válido para ${state.name}`
      };
    }
  }

  return { valid: false, message: 'Código postal inválido para este país' };
}

// Uso
const result = await validatePostalCode('DE', '10115');
console.log(result); // { valid: true, state: 'Berlin', message: '...' }

Consejos de rendimiento

  1. Usa limitToken: Controla el tamaño de datos para países con muchos códigos postales
  2. Cachea por país: Almacena códigos postales por país (rara vez cambian)
  3. Carga perezosa de estados: Obtén todos, pero muestra progresivamente
  4. Usa códigos ISO: Búsqueda más rápida que nombres completos de países

Límites de tasa

  • Tier gratuito: 100 peticiones/día
  • Tier básico: 1,000 peticiones/día
  • Tier pro: 10,000 peticiones/día
  • Tier empresarial: Ilimitado

Consulta nuestra página de precios para más detalles.

Endpoints relacionados

¿Necesitas ayuda?