zip-codes-api
Python client for the ZIP Codes API — US ZIP and Canadian postal data with 14 years of US Census ACS demographics (2011–2024), radius search (centroid + spatial coverage-weighting), address validation with ZIP+4, distance, and typo-tolerant autocomplete.
pip install zip-codes-api # core
pip install 'zip-codes-api[pandas]' # + DataFrame helpers for research
Quickstart
from zip_codes_api import ZipCodesClient
# Public demo key works for demo ZIPs (90210, 10001, ...). Any ZIP: get a free
# key at https://www.zip-codes.com/api/signup (2,500 credits/day, no card).
client = ZipCodesClient("zc_test_DEMOAPIKEY000000000000")
bh = client.zip("90210", include=["acs_demographic", "timezone"])
print(bh["city"]) # Beverly Hills
print(client.last_meta["credits"]["used"]) # credits this call cost
Single-target methods (zip, quick_zip, radius, distance, address, suggest)
return the first result object. Batch methods return the list of per-item results.
Pass raw=True for the full response envelope. client.last_meta always holds the
most recent response's meta (including credits).
14 years of demographics as a DataFrame
The reason most researchers reach for this API — a longitudinal ZIP-level series in one
call, with the year-to-year Census variable drift and the 2020 GEO_ID change already
normalized:
df = client.acs_timeseries("90210", profile="demographic", years=range(2011, 2025))
print(df[["sex_and_age.total_population", "sex_and_age.median_age"]])
# sex_and_age.total_population sex_and_age.median_age
# year
# 2011 21719 45.7
# ...
# 2024 19004 51.9
profile is one of demographic (DP05), social (DP02), economic (DP03),
housing (DP04).
Coverage-weighted radius aggregation (no GIS)
/radius in spatial mode intersects your radius with actual ZIP/FSA boundary polygons
and weights the ACS aggregate by each ZIP's pct_inside — a ZIP 30% inside contributes
30% of its population, not all-or-nothing:
r = client.radius("90210", max_radius=10, mode="spatial", include="acs_demographic")
pop = r["stats"]["acs"]["current"]["demographic"]["sex_and_age"]["total_population"]["est"]
print(f"{pop:,} people within 10 miles (coverage-weighted)")
matches = client.radius_dataframe("90210", max_radius=10, mode="spatial") # pandas
print(matches[["code", "city", "pct_inside", "distance_miles"]].head())
Other endpoints
client.quick_zip("M5V") # Canadian FSA: city/province/coords
client.distance("90210", "10001") # great-circle distance + bearing
client.address("200 N Spring St, Los Angeles, CA 90012") # validate + ZIP+4
client.suggest("9021") # autocomplete -> result["matches"]
# Batch (up to 100; requires a paid subscription key)
client.zip_batch(["90210", "10001", "M5V"], include="timezone")
Errors
Failures raise typed exceptions carrying the API's code, status, and request_id:
from zip_codes_api import InsufficientCreditsError, RateLimitError, NotFoundError
try:
client.zip("90210", include=["acs_economic"])
except RateLimitError as e:
print("retry after", e.retry_after, "seconds")
except InsufficientCreditsError:
...
except NotFoundError:
...
ZipCodesClient retries 429 / 5xx automatically (honoring Retry-After), up to
max_retries (default 2).
Links
- API docs: https://www.zip-codes.com/api/docs
- Get a free key: https://www.zip-codes.com/api/signup
- Sample data + notebooks: https://github.com/ZIP-Codes-API/acs-by-zip
- Research/journalism/nonprofit credits: https://www.zip-codes.com/api/research-credits
License
MIT. Underlying demographic data is US Census Bureau ACS (public domain). Suggested acknowledgement:
Demographic data: US Census Bureau ACS 5-Year Estimates, accessed via ZIP Codes API (Zip-Codes.com), https://www.zip-codes.com/api/
Release files for zip-codes-api 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| zip_codes_api-0.1.0.tar.gz | 10.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| zip_codes_api-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 20.1 kB
Release files / zip_codes_api-0.1.0.tar.gz
| Download URL | zip_codes_api-0.1.0.tar.gz |
|---|---|
| Size | 10.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1176d357b988a2c3a431c918cafb9f2aa50c47882577efaaf6e69d3b54eb2c5d
|
|
BLAKE2b-256 checksum How to use checksums |
c82ebfbfd7e9a04101a26649bd8e9e9b8c015fd6eb3092b8df0ec2251bc135fb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.0
|
Release files / zip_codes_api-0.1.0-py3-none-any.whl
| Download URL | zip_codes_api-0.1.0-py3-none-any.whl |
|---|---|
| Size | 10.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5cedff75d699ab0db532963e796258092fc68f964000c064bf08dc1e9c45c9fa
|
|
BLAKE2b-256 checksum How to use checksums |
e6fa0fca6ca7df7972039f5e64820c4b2c3211980981074cd95c70726d47978d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.0
|