Recipe: Postal code → place lookup
Resolve a postal code to a city/state/coordinates. Reverse: find postal codes for a city.
Tools used: zippopotam.lookup_zipcode, zippopotam.lookup_city. Geocoding fallback: weather.get_weather (Open-Meteo geocoder).
Calls: 1.
Decision tree
| Question | Tool |
|---|---|
| ”What city is ZIP 90210?” | lookup_zipcode({ country: "us", zipcode: "90210" }) |
| ”What’s the postal code for Beverly Hills, CA?” | lookup_city({ country: "us", state: "ca", city: "beverly hills" }) |
| ”Coordinates for SW1A 1AA?” | lookup_zipcode({ country: "gb", zipcode: "SW1A 1AA" }) |
| Postal code in unsupported country | Use weather.get_weather({location: "...zipcode..., country"}) — Open-Meteo’s geocoder is broader |
Country coverage
Zippopotam has good coverage for:
- US, GB, CA, AU, DE, FR, NL, BE, ES, IT, JP, MX, BR
- ~60 countries total
Spotty or no coverage for many other countries. Calls return {found: false, hint: ...} (cleanly handled — no crash) but the agent burns a call.
For countries outside this set, use Open-Meteo’s geocoder via the weather pack. It accepts city + country strings and returns coordinates with hierarchy (city, state/region, country).
The shapes of failure
// Wrong: zipcode that doesn't exist
zippopotam.lookup_zipcode({ country: "us", zipcode: "00000" })
// → {found: false, hint: "Postal code not found..."}
// Wrong: country not in zippopotam's index
zippopotam.lookup_zipcode({ country: "ke", zipcode: "00100" }) // Kenya
// → {found: false, hint: "...coverage varies by country..."}
Both return {found: false} instead of crashing — but you’ve still wasted a call. Pre-check coverage if you can.
Worked examples
US ZIP
zippopotam.lookup_zipcode({ country: "us", zipcode: "90210" })
// → {
// post_code: "90210",
// country: "United States",
// country_abbreviation: "US",
// found: true,
// places: [{ name: "Beverly Hills", state: "California", state_abbreviation: "CA", lat: 34.0901, lon: -118.4065 }]
// }
UK postcode
zippopotam.lookup_zipcode({ country: "gb", zipcode: "SW1A 1AA" })
// → resolves to Westminster
Reverse: city → postal codes
zippopotam.lookup_city({ country: "us", state: "ca", city: "beverly hills" })
// → multiple postal codes for the city
Note: state is the abbreviation ("ca", not "California"). City name is case-insensitive; spaces become +.
Fallback: country not supported
// Skip zippopotam entirely. Use Open-Meteo's geocoder:
weather.get_weather({ location: "00100, Nairobi, Kenya" })
// → coordinates resolved by Open-Meteo's broader geocoder, plus current weather
If you only need coordinates (not weather), this is overkill but it works.
Pattern: validated lookup
async function resolvePostalCode(country, zipcode) {
const result = await zippopotam.lookup_zipcode({ country, zipcode })
if (result.found) return result.places[0]
// Fallback: build a query string and let Open-Meteo geocode
const fallback = await weather.get_weather({ location: `${zipcode}, ${country}` })
if (fallback.location) {
return {
name: fallback.location.name,
lat: fallback.location.latitude,
lon: fallback.location.longitude,
}
}
return null
}
Citation pattern
90210 resolves to Beverly Hills, CA (34.09°N, 118.41°W) per Zippopotam.
Caveats
- Country code is ISO-3166-1 alpha-2, lowercase.
"us"not"USA","gb"not"UK". - State abbreviation, not full name.
"ca"for California,"ny"for New York. - City names are case-insensitive but have to match. “St. Louis” might need to be “saint louis”; “New York” usually works as “new york” (often the API normalizes).
- Postal code formats vary by country. US is 5 digits or 5+4. UK is alphanumeric with a space. Check the upstream Zippopotam docs for any country before relying on a specific format.
- Multiple places per code. US ZIPs can map to multiple cities (e.g. boundary zips). Returns are an array — don’t assume
.places[0]is canonical.