Introduction
The ZIP Codes API v2 provides comprehensive postal code data for the United States and Canada. Look up ZIP codes, calculate distances, search by radius, and enrich results with census demographics, political districts, school districts, and more.
Base URL: https://api.zip-codes.com. All API endpoints live under the /v2/ prefix. Responses use a consistent JSON envelope with built-in error handling and credit tracking.
Key Features
- US ZIP & ZIP+4 lookups with demographics, delivery points, and business data
- Canadian FSA & postal code lookups with province-level data
- Radius search with cross-border support (US + Canada)
- Distance calculation between any combination of ZIP codes, FSAs, postal codes, and coordinates
- Opt-in enrichments including ACS demographics, census boundaries, political districts, school districts, timezone, and more
- Five batch routes: up to 250 addresses or 100 items on each other route
Authentication
Get a key and review plans at API pricing. Lookup requests require a valid API key. Health, documentation, OpenAPI, Swagger and Postman are public. You can pass it in two ways:
Option 1: HTTP Header (recommended)
X-Api-Key: your_api_key
Option 2: Query Parameter
GET /v2/quick-zip?code=90210&key=your_api_key
Request & Response Format
Code inputs (including distance from/to) are strings of at most 50 characters: 5-digit ZIP, ZIP+4 with or without a dash, FSA, full Canadian postal code with an optional space, or lat,lon (latitude -90..90, longitude -180..180). Include flags are split on commas, trimmed, lowercased, normalized from hyphens to underscores, and de-duplicated. Single POST include fields are strings. Authorization: Bearer is not accepted; use X-Api-Key.
| Aspect | Details |
|---|---|
| Content-Type | All responses are application/json; charset=utf-8. Send Content-Type: application/json; POST bodies under /v2 are treated as JSON even if this header is omitted. |
| POST Body | Non-batch endpoints accept GET query parameters or POST with a JSON body containing the same parameter names. Body values win; missing body fields fall back to the query. Batch endpoints are POST-only. |
| Compression | The API supports Brotli and Gzip response compression. Send Accept-Encoding: br or Accept-Encoding: gzip for smaller payloads. |
| Caching | All API responses include Cache-Control: no-store. Implement your own caching layer if needed. |
| CORS | CORS allows any origin. Per-key IP and Origin allowlists are enforced when configured. |
| Request ID | Every response includes an X-Request-Id header and meta.request_id field (a ULID). Include this in support requests for faster troubleshooting. |
include Parameter | Controls what data appears in the response. On /zip and /radius, it adds enrichment data (e.g. include=timezone,census). On /suggest, it filters which entity types are returned (e.g. include=zip,place) — all types are included by default. |
Quick Start
Make your first API call in seconds:
curl -H "X-Api-Key: YOUR_API_KEY" \ "https://api.zip-codes.com/v2/quick-zip?code=90210"
import requests
resp = requests.get(
"https://api.zip-codes.com/v2/quick-zip",
params={"code": "90210"},
headers={"X-Api-Key": "YOUR_API_KEY"}
)
data = resp.json()
print(data["results"][0]["city"]) # Beverly Hills
const resp = await fetch(
"https://api.zip-codes.com/v2/quick-zip?code=90210",
{ headers: { "X-Api-Key": "YOUR_API_KEY" } }
);
const data = await resp.json();
console.log(data.results[0].city); // Beverly Hills
Your Dashboard
The API Portal dashboard gives you full control over your account:
- API Keys — Create, rotate, and configure keys with per-key IP whitelisting and CORS origin restrictions.
- Usage Analytics — Daily and monthly usage charts, per-key breakdowns, and CSV export for your records.
- Billing — Manage your subscription tier, purchase credit packs, and download invoices.
- Settings — Update account details and notification preferences.
Free tier accounts start with 2,500 credits/day. Sign in to get started →
Null model fields are omitted, except explicitly preserved nulls such as census sections and ACS values. Postal, radius, distance and suggest items are flattened: {success,input?,error?,notices?,...fields}, with no data wrapper. Address retains data; health uses a top-level data object. A well-formed lookup with no match returns HTTP 200 and a per-item error. Single address no-match uses top-level success:false and an error inside results[0].
Response Format
Every API response follows a consistent envelope structure:
{
"success": true,
"request": {
"code": "90210",
"include": [
"timezone"
]
},
"results": [
"..."
],
"meta": {
"request_id": "01M3SX2V9NY9MRRAMWVJG0C09E",
"version": "2.0.0",
"timing_ms": 45,
"credits": {
"used": 2,
"remaining": 74998,
"breakdown": {
"base": 1,
"enrichments": {
"timezone": 1
}
},
"source": "subscription"
}
}
}
| Field | Type | Description |
|---|---|---|
success | boolean | Whether the request succeeded |
request | object | Echo of parsed request parameters |
results | array | Array of result objects (varies by endpoint) |
error | object (optional) | Omitted on success; whole-request failures contain {code,message,retryable?,url}. Lookup failures may instead have an error inside a result item. |
meta.request_id | string | ULID request identifier (also in X-Request-Id header) |
meta.version | string | API version (currently "2.0.0") |
meta.timing_ms | number | Total processing time in milliseconds |
meta.credits | object | Credit usage breakdown for this request |
meta.notices | array | Informational messages (see Notices) |
Notices
The meta.notices array contains non-error informational messages about request processing. Notices may also appear on result items. Only FREE_TIER_LIMIT_CAPPED includes an optional url, linking to pricing; all other notices omit it:
| Code | Description |
|---|---|
INPUT_NORMALIZED | Input was reformatted (e.g., whitespace trimmed, case corrected) |
FALLBACK_USED | On quick-zip and distance only: Canadian postal code not found; FSA-level data returned instead |
ENRICHMENT_UNAVAILABLE | Requested enrichment cannot be delivered (no credit charged for the unavailable flag) |
VALIDATION_UNKNOWN_ENRICHMENT | Unknown enrichment flags ignored without charge; a notice, not an HTTP 400 error |
REVERSE_GEOCODE | Coordinate was reverse-geocoded to a postal code |
BATCH_DUPLICATES_DETECTED | Duplicates are processed and billed individually |
Address Matching
Parse and validate a raw US street address against USPS ZIP+4 delivery-point data. Returns the standardized address, ZIP+4 code, address components, and delivery metadata. Handles partial input — with a ZIP code, the city and state are optional; without one, give the city and state.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
address | string | Required | Raw street address to match: at most 500 raw characters and 9–300 after cleanup. Accepts full or partial addresses (e.g., 1600 Pennsylvania Ave NW, Washington DC 20500 or 350 5th Ave, New York). |
include | string | Optional | Comma-separated enrichments: coordinates, census, cd, state_leg, school_district, and the tract ACS flags below. |
Credit Cost
Base 1 credit per request, whether or not a match is found. Requesting coordinates adds 1 credit. Each boundary flag and each tract ACS profile and year adds 1 credit only when delivered. Credit availability is checked against the requested enrichments before matching.
Include Flags
Paths below are relative to results[0].data for single calls and results[i].data for batch. GET takes a comma-separated list; POST /v2/address requires a string (an array returns HTTP 400); batch accepts a string or array. All flags are optional; the default is no enrichments.
| Flag | What it adds | Path below data | Credits |
|---|---|---|---|
| coordinates | ZIP+4 point, latitude/longitude (6 decimals) | location | +1 whenever requested, including no match |
| census | Counties, subdivisions, places, tracts, block groups, metro areas/divisions | census.current | +1 when delivered |
| cd | Congressional districts | congressional_district.current | +1 when delivered |
| state_leg | State upper/lower legislative districts | state_legislative.current.upper / lower | +1 when delivered |
| school_district | NCES school districts | school_district.current | +1 when delivered |
| acs_tract_demographic[_2024|_2023|_2022] | DP05 tract profile | acs.tract.{current|2023|2022}.demographic | +1 per delivered profile/year |
| acs_tract_social[_2024|_2023|_2022] | DP02 tract profile | acs.tract.{current|2023|2022}.social | +1 per delivered profile/year |
| acs_tract_economic[_2024|_2023|_2022] | DP03 tract profile | acs.tract.{current|2023|2022}.economic | +1 per delivered profile/year |
| acs_tract_housing[_2024|_2023|_2022] | DP04 tract profile | acs.tract.{current|2023|2022}.housing | +1 per delivered profile/year |
Boundary Enrichments
Use census for counties, county subdivisions, places, tracts, block groups, metro/micro statistical areas, and metropolitan divisions; cd for congressional districts; state_leg for upper and lower state legislative districts; and school_district for school districts. Flags accept either dashes or underscores and are case-insensitive; duplicate flags count once.
All four flags use a spatial lookup for one point: the matched ZIP+4 record's centroid. You do not need to request coordinates; without that flag, data.location is omitted. With coordinates, it contains latitude and longitude rounded to 6 decimals.
Each flag fills its own family beside the others in data, in the same names and order as /v2/zip: census, congressional_district, state_legislative, and school_district. Each family holds its data under current; a requested family with nothing found is present with current: null, and an unrequested family is absent. data.census.current holds arrays county (with is_usps_primary), county_subdivision, place, tract, and block_group; metro_micro_cbsa_statistical_area and metropolitan_cbsa_division are single objects. data.congressional_district.current contains congress, districts, and primary:{geoid,state,district_number} with an integer district number. data.state_legislative.current contains legislative_year, upper, and lower arrays. These three carry source Census Bureau TIGER/Line Cartographic Boundaries, year 2024, vintage "2024". Point rows have no pct_of_zip, pct_of_area, or intersection-area fields. details.congressional_district is a different field: the USPS congressional district code string from the match details, independent of the cd flag.
A boundary flag costs one credit only when a usable point exists and all its lookups complete. Empty lookups are null and still count as delivered. No match, a ZIP-level answer without a location, or a failed boundary read makes the affected flag unavailable and uncharged. One ENRICHMENT_UNAVAILABLE notice names all unavailable boundary and tract enrichments; the address answer is still returned.
Tract ACS Enrichments
Use acs_tract_demographic, acs_tract_social, acs_tract_economic, or acs_tract_housing. Unsuffixed flags select the latest ACS year (2024). Append _2023 or _2022 for earlier years; _2024 is also accepted. Supported years are 2022–2024. An unsuffixed flag and its latest-year alias count as one enrichment, for 12 distinct tract profile/year tags.
Profiles describe the census tract that contains the matched address's location. They appear under the geography level, results[].data.acs.tract: current for the latest year, then 2023 and 2022 for earlier years. Each year block uses the same ACS field names as /v2/zip, with geography_level: "tract" and geo_id of 1400000US followed by its 11-digit tract GEOID. The same containing tract is used for every year. Each block includes source, product, year, vintage ({year-4}-{year}), and tables.
If the address is unmatched, the match has no location, no tract contains it, or a requested profile has no row for that year, that enrichment is not charged. One ENRICHMENT_UNAVAILABLE notice in meta.notices names the unavailable flags and explains why. A missing profile may be null within a block; data.acs is omitted if no requested profile was delivered. Unsupported tract flags or years are ignored without charge and reported through VALIDATION_UNKNOWN_ENRICHMENT. Tract flags are only available on the address endpoints.
data.school_district.current contains source, school_year, and districts:[{leaid,name,type,grade_low,grade_high,state_fips,land_area_sq_mi,water_area_sq_mi,centroid?,office?,locale?,nces_codes}]. ACS blocks identify source:"U.S. Census Bureau", product:"ACS 5-Year Estimates Data Profiles", and a five-year vintage. Unknown flags (including timezone, acs_demographic, and unsupported tract years) are ignored free with VALIDATION_UNKNOWN_ENRICHMENT: Unknown enrichment flag(s) ignored: {flags}.
Batch Address Enrichment
POST /v2/address/batch accepts up to 250 addresses and the same flags in the body include (a comma-separated string or array). A paid plan is required. Credits are reserved for every requested enrichment, then unused credits are refunded. Each successfully processed item costs the base credit, requested coordinates, and only its delivered boundary flags and tract profiles; rejected or failed items are not charged. Matched items carry data.census, data.congressional_district, data.state_legislative, data.school_district, and data.acs in the same shapes as the single endpoint. One envelope ENRICHMENT_UNAVAILABLE notice counts processed addresses missing requested enrichments, including unmatched addresses. Unknown flags are ignored without charge and named in VALIDATION_UNKNOWN_ENRICHMENT.
{
"addresses": [
"1600 Pennsylvania Ave NW, Washington DC 20500",
"not a real address 99999"
],
"include": [
"coordinates",
"acs_tract_economic"
]
}Items are {success,input:{address},matched,data?,notices?}. An unmatched item is {success:true,input:{address},matched:false}, with no engine reason code; it counts in meta.batch.succeeded. Rejected or failed items have success:false, input, and error, and cost 0 credits. The batch timeout is 120 seconds.
{
"success": true,
"request": {
"addresses_count": 2
},
"results": [
{
"success": true,
"input": {
"address": "1600 Pennsylvania Ave NW, Washington DC 20500"
},
"matched": true,
"data": {
"confidence": "high",
"formatted_address": "1600 PENNSYLVANIA AVE NW, WASHINGTON, DC 20500-0005",
"location": {
"latitude": 38.898704,
"longitude": -77.036497
},
"acs": {
"tract": {
"current": {
"source": "U.S. Census Bureau",
"product": "ACS 5-Year Estimates Data Profiles",
"year": 2024,
"vintage": "2020-2024",
"geo_id": "1400000US11001980000",
"geography_level": "tract",
"tables": {
"economic": "DP03"
},
"economic": {
"commuting": {
"drove_alone": {
"column": "DP03_0019",
"est": 12,
"moe": 18,
"pct": 70.6,
"pct_moe": 8.0
},
"public_transportation": {
"column": "DP03_0021",
"est": 5,
"moe": 8,
"pct": 29.4,
"pct_moe": 8.0
}
}
}
}
}
}
},
"notices": [
{
"code": "MATCHED",
"message": "Address matched.",
"class": "match"
}
]
},
{
"success": true,
"input": {
"address": "not a real address 99999"
},
"matched": false
}
],
"meta": {
"request_id": "01M3SX2VE1BEM6ACR6DME1GXK2",
"version": "2.0.0",
"timing_ms": 53,
"credits": {
"used": 5,
"source": "subscription",
"remaining": 1485722,
"breakdown": {
"base": 0,
"enrichments": {},
"note": "2 addresses x 1 base + 3 enrichment = 5 credits"
}
},
"notices": [
{
"code": "ENRICHMENT_UNAVAILABLE",
"message": "Enrichment(s) unavailable: acs_tract_economic for 1 of 2 processed addresses; matched location or requested enrichment data is unavailable; not charged."
}
],
"batch": {
"requested": 2,
"succeeded": 2,
"failed": 0
}
}
}Example Request
curl -H "X-Api-Key: YOUR_API_KEY" \ "https://api.zip-codes.com/v2/address?address=9641+Sunset+Blvd%2C+Beverly+Hills%2C+CA+90210&include=coordinates,census,cd,state_leg,school_district,acs_tract_demographic,acs_tract_housing_2023"
Example Response
Captured response excerpt: fields and ACS profiles are trimmed; the original eight-credit charge is retained.
{
"success": true,
"request": {
"address": "9641 Sunset Blvd, Beverly Hills, CA 90210",
"include": "coordinates,census,cd,state_leg,school_district,acs_tract_demographic,acs_tract_housing_2023"
},
"results": [
{
"input": "9641 Sunset Blvd, Beverly Hills, CA 90210",
"success": true,
"data": {
"confidence": "medium",
"formatted_address": "9641 SUNSET BLVD, BEVERLY HILLS, CA 90210-2938",
"address_line1": "9641 SUNSET BLVD",
"address_line2": "BEVERLY HILLS, CA 90210-2938",
"address_components": {
"number": "9641",
"street": "SUNSET",
"suffix": "BLVD",
"city": "BEVERLY HILLS",
"state": "CA",
"zip": "90210",
"plus4": "2938",
"country": "US"
},
"location": {
"latitude": 34.081348,
"longitude": -118.412499
},
"acs": {
"tract": {
"current": {
"source": "U.S. Census Bureau",
"product": "ACS 5-Year Estimates Data Profiles",
"year": 2024,
"vintage": "2020-2024",
"geo_id": "1400000US06037700700",
"geography_level": "tract",
"tables": {
"demographic": "DP05"
},
"demographic": {
"sex_and_age": {
"total_population": {
"column": "DP05_0001",
"est": 2935,
"moe": 578,
"pct": 2935.0,
"pct_moe": null
},
"median_age": {
"column": "DP05_0018",
"est": 56.4,
"moe": 8.7
}
}
}
},
"2023": {
"source": "U.S. Census Bureau",
"product": "ACS 5-Year Estimates Data Profiles",
"year": 2023,
"vintage": "2019-2023",
"geo_id": "1400000US06037700700",
"geography_level": "tract",
"tables": {
"housing": "DP04"
},
"housing": {
"occupancy": {
"total": {
"column": "DP04_0001",
"est": 1303,
"moe": 144,
"pct": 1303.0,
"pct_moe": null
},
"occupied": {
"column": "DP04_0002",
"est": 1170,
"moe": 149,
"pct": 89.8,
"pct_moe": 7.9
}
}
}
}
}
},
"census": {
"current": {
"source": "Census Bureau TIGER/Line Cartographic Boundaries",
"year": 2024,
"vintage": "2024",
"county": [
{
"fips": "06037",
"name": "Los Angeles",
"is_usps_primary": true
}
],
"county_subdivision": [
{
"geoid": "0603791750",
"name": "Los Angeles"
}
],
"place": [
{
"geoid": "0606308",
"name": "Beverly Hills"
}
],
"tract": [
{
"geoid": "06037700700",
"name": "7007"
}
],
"block_group": [
{
"geoid": "060377007002",
"name": "2"
}
],
"metro_micro_cbsa_statistical_area": {
"cbsa_code": "31080",
"name": "Los Angeles-Long Beach-Anaheim, CA"
},
"metropolitan_cbsa_division": {
"metdiv_code": "31084",
"name": "Los Angeles-Long Beach-Glendale, CA",
"cbsa_code": "31080"
}
}
},
"congressional_district": {
"current": {
"source": "Census Bureau TIGER/Line Cartographic Boundaries",
"year": 2024,
"vintage": "2024",
"congress": 119,
"districts": [
{
"geoid": "0636",
"state": "CA",
"district_number": 36,
"name": "Congressional District 36",
"land_area_sq_mi": 97.11,
"water_area_sq_mi": 97.51
}
],
"primary": {
"geoid": "0636",
"state": "CA",
"district_number": 36
}
}
},
"state_legislative": {
"current": {
"source": "Census Bureau TIGER/Line Cartographic Boundaries",
"year": 2024,
"vintage": "2024",
"legislative_year": 2024,
"upper": [
{
"geoid": "06024",
"name": "24"
}
],
"lower": [
{
"geoid": "06051",
"name": "51"
}
]
}
},
"school_district": {
"current": {
"source": "National Center for Education Statistics (NCES)",
"school_year": "2024-2025",
"districts": [
{
"leaid": "0604830",
"name": "Beverly Hills Unified School District",
"type": "unified",
"grade_low": "KG",
"grade_high": "12"
}
]
}
}
},
"notices": [
{
"code": "PARTIAL_MATCH",
"message": "Address matched; some details could not be confirmed.",
"class": "match"
}
]
}
],
"meta": {
"request_id": "01M3SX2V9NY9MRRAMWVJG0C09E",
"version": "2.0.0",
"timing_ms": 77,
"credits": {
"used": 8,
"source": "subscription",
"remaining": 1485728,
"breakdown": {
"base": 1,
"enrichments": {
"coordinates": 1,
"acs_tract_demographic": 1,
"acs_tract_housing_2023": 1,
"census": 1,
"cd": 1,
"state_leg": 1,
"school_district": 1
}
}
}
}
}
Result Fields
| Field | Type | Description |
|---|---|---|
input | string | The raw address string you submitted |
success | boolean | true if the address was matched |
data | object (optional) | Matched address, including requested enrichments when available |
Matched Address Data
| Field | Type | Description |
|---|---|---|
formatted_address | string | USPS-standardized full address with ZIP+4 |
address_line1 | string | Street line (number, directional, street, suffix, secondary) |
address_line2 | string | Last line (city, state, ZIP+4) |
address_components | object | Parsed address components (see table below) |
confidence | string | Match confidence: high, medium, or low |
details | object | USPS delivery-point metadata |
pbsa_indicator | boolean (optional) | Included only when true |
location | object (optional) | Requested latitude/longitude |
census | object (optional) | Requested census geography under current |
congressional_district | object (optional) | Requested congressional districts under current |
state_legislative | object (optional) | Requested upper/lower state legislative districts under current |
school_district | object (optional) | Requested school districts under current, with source and school_year |
acs | object | Requested ACS by geography level (tract), then by year (current, 2023, 2022); omitted when no requested profile is delivered |
Address Components
| Field | Type | Description |
|---|---|---|
number | string (optional) | House/building number |
pre_directional | string (optional) | Prefix directional (e.g., N, SW) |
street | string (optional) | Street name |
street_pre_type | string (optional) | Street pre-type (e.g., AVE in AVE OF THE AMERICAS) |
suffix | string (optional) | Street suffix (e.g., ST, AVE, BLVD) |
post_directional | string (optional) | Postfix directional (e.g., NW) |
secondary_type | string (optional) | Secondary address type (e.g., APT, STE, UNIT) |
secondary_number | string (optional) | Secondary address number (e.g., 4B, 200) |
city | string | Matched city name |
state | string | Two-letter state abbreviation |
zip | string | 5-digit ZIP code |
plus4 | string | 4-digit ZIP+4 suffix |
country | string | Country code (US) |
Details (USPS Metadata)
| Field | Type | Description |
|---|---|---|
record_type | object (optional) | USPS record type with code and description: S (Street), H (Highrise), P (PO Box), F (Firm), G (General Delivery), R (Rural Route) |
carrier_route | object (optional) | USPS carrier route with code and description |
county | object (optional) | County fips and name |
congressional_district | string (optional) | Congressional district number |
building_name | string (optional) | Building or firm name (when available) |
government_building | object (optional) | USPS government building indicator as code and description: A (City Government Building), B (Federal Government Building), C (State Government Building), D (Firm Only), E (City Government Building and Firm Only), F (Federal Government Building and Firm Only), G (State Government Building and Firm Only), or an empty code with "Not a Government Building". Omitted when no ZIP+4 record was matched |
success is false and data is omitted. The base credit and requested coordinates still apply; unavailable boundary flags and tract profiles are not charged. The per-item error identifies insufficient input, ambiguity, or no match.Address item notices include class and codes MATCHED, PARTIAL_MATCH, ZIP_CORRECTED, CITY_CORRECTED, STATE_CORRECTED, STREET_CORRECTED, SECONDARY_NEEDED, SECONDARY_NOT_VERIFIED, and INPUT_NOT_USED. Test keys accept only configured demo addresses.
No Match, Ambiguous, or Insufficient Input
HTTP 200, top-level success:false, no top-level error. results[0] contains input, success:false, and error:{code,message,url}. No candidate list is returned.
INSUFFICIENT_INPUT: Not enough information to locate the address. Include a city and state, or a ZIP code.AMBIGUOUS: More than one address matches. Add detail such as a unit number, directional or ZIP code.NOT_FOUND: The address could not be matched.
No match costs 1 credit, or 2 with coordinates. Requested boundary/tract flags produce one ENRICHMENT_UNAVAILABLE notice and are not charged. On a matched address, unavailable enrichment notices explain that the matched location or requested enrichment data is unavailable.
{
"success": false,
"request": {
"address": "123 Nowhere Lane Faketown ZZ",
"include": "coordinates,census"
},
"results": [
{
"input": "123 Nowhere Lane Faketown ZZ",
"success": false,
"error": {
"code": "INSUFFICIENT_INPUT",
"message": "Not enough information to locate the address. Include a city and state, or a ZIP code.",
"url": "https://www.zip-codes.com/api/"
}
}
],
"meta": {
"request_id": "01M3SX2VHP0M9TXH8WFHW7ZM3G",
"version": "2.0.0",
"timing_ms": 5,
"credits": {
"used": 2,
"source": "subscription",
"remaining": 1485721,
"breakdown": {
"base": 1,
"enrichments": {
"coordinates": 1
}
}
},
"notices": [
{
"code": "ENRICHMENT_UNAVAILABLE",
"message": "Enrichment(s) unavailable: census; address was not matched; not charged."
}
]
}
}Geographic Suggest
Typeahead search for geographic entities. Returns ZIP codes, cities/places, counties, metro areas (CBSAs), states/provinces, and Canadian FSAs/postal codes, school districts and USPS city names matching a query. Results include authoritative identifiers (FIPS, GEOID), coordinates, bounding boxes, and population data.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
q | string | Required | Search query (1–200 characters). Case-insensitive. |
limit | integer | No | Max results to return. Default: 10. Free/test tiers: max 15. Paid tiers: max 500. |
include | string | No | Comma-separated entity types to include: zip, place, county, cbsa, fsa, state, school_district, ca_postal, uspscity. Default: all nine types. Unlike /zip and /radius where include adds enrichment data, here it filters which entity types are returned. |
state | string | No | US state or CA province abbreviation to filter results (e.g., CA, ON). |
country | string | No | Filter by country: US or CA. Default: both. |
proximity | string | No | Geographic bias for ranking. Accepts multiple formats: lat,lon (coordinates), auto (caller IP), IP address, 5-digit ZIP, 3-char FSA, or 2-letter state/province. Nearby results rank higher (soft bias, not a filter). |
auto or explicit IP) resolves coordinates for the response echo but does not currently influence scoring. Numeric queries (ZIP prefixes) now benefit from proximity bias.Entity Types
| Type | Count | Description | Type-Specific Fields |
|---|---|---|---|
zip | ~42K | US ZIP codes | city, classification |
place | ~30K | US Census places (cities, towns, CDPs) | fips, geoid, associated_zips |
county | ~3.2K | US counties (includes parishes, boroughs) | fips, geoid |
cbsa | ~1K | Metropolitan & micropolitan statistical areas | cbsa_code, geoid, metro_micro |
fsa | ~1.6K | Canadian Forward Sortation Areas | city, province, postal_code_count |
state | ~67 | US states/territories & CA provinces (with abbreviation aliases) | (none) |
school_district | — | School districts | Available entity metadata |
ca_postal | — | Canadian postal codes | Available postal metadata |
uspscity | — | USPS city names | Available city metadata |
Credit Cost
| Limit Range | Credits | Available To |
|---|---|---|
| 1–15 | 1 | All tiers (including free) |
| 16–50 | 2 | Paid only |
| 51–150 | 3 | Paid only |
| 151–500 | 5 | Paid only |
Billing based on requested limit, not results returned. Free/test tier requests above 15 are clamped with a FREE_TIER_LIMIT_CAPPED notice. Validation errors (missing q, invalid include) cost 0 credits.
Example Request
curl -H "X-Api-Key: YOUR_API_KEY" \ "https://api.zip-codes.com/v2/suggest?q=spring&limit=3"
Example: With proximity bias
curl -H "X-Api-Key: YOUR_API_KEY" \ "https://api.zip-codes.com/v2/suggest?q=spring&proximity=40.7128,-74.006&limit=3"
Example: Filtered by type and state
curl -H "X-Api-Key: YOUR_API_KEY" \ "https://api.zip-codes.com/v2/suggest?q=cook&include=county&state=IL&limit=3"
Example Response
{
"success": true,
"request": {
"q": "cook",
"limit": 3,
"include": [
"county"
],
"state": "IL"
},
"results": [
{
"success": true,
"total_matched": 5,
"matches": [
{
"type": "county",
"name": "Cook County",
"state": "IL",
"country": "US",
"fips": "17031",
"geoid": "17031",
"population": 5182090,
"location": {
"lat": 41.8440477,
"lon": -87.820797
},
"bbox": {
"min_lat": 41.46971,
"max_lat": 42.154265,
"min_lon": -88.263641,
"max_lon": -87.524165
}
},
{
"type": "county",
"name": "Rock Island County",
"state": "IL",
"country": "US",
"fips": "17161",
"geoid": "17161",
"population": 142757,
"location": {
"lat": 41.5511206,
"lon": -90.4512621
},
"bbox": {
"min_lat": 41.326838,
"max_lat": 41.7829645,
"min_lon": -91.0719555,
"max_lon": -90.159878
}
},
{
"type": "county",
"name": "Boone County",
"state": "IL",
"country": "US",
"fips": "17007",
"geoid": "17007",
"population": 53230,
"location": {
"lat": 42.3297656,
"lon": -88.849764
},
"bbox": {
"min_lat": 42.15232,
"max_lat": 42.495046,
"min_lon": -88.940992,
"max_lon": -88.70541
}
}
]
}
],
"meta": {
"version": "2.0.0",
"timing_ms": 2,
"credits": {
"used": 1,
"remaining": 74999,
"breakdown": {
"base": 1,
"enrichments": {}
},
"source": "subscription"
},
"request_id": "01M3SX2V9NY9MRRAMWVJG0C09E"
}
}
Match Object Fields
| Field | Type | Description |
|---|---|---|
type | string | Entity type: zip, place, county, cbsa, fsa, state, school_district, ca_postal, uspscity |
name | string | Display name (ZIP code number, place name, county name, etc.) |
state | string | US state abbreviation (or province for FSA) |
country | string | US or CA |
population | integer | Population (ACS estimate for US, Census for CA) |
location | object | { lat, lon } — centroid coordinates |
bbox | object | { min_lat, max_lat, min_lon, max_lon } — bounding box (omitted for ZIPs) |
fips | string | FIPS code (places, counties only) |
geoid | string | Census GEOID (places, counties, CBSAs) |
associated_zips | array | ZIP codes within a place (places only) |
cbsa_code | string | CBSA code (CBSAs only) |
metro_micro | string | Metropolitan or Micropolitan (CBSAs only) |
city | string | Primary city name (ZIPs and FSAs only) |
classification | string | ZIP type: Standard, PO Box, Military, Unique (ZIPs only) |
province | string | CA province abbreviation (FSAs and CA states only) |
Quick ZIP Lookup
Fast postal code lookup returning basic location data with optional timezone enrichment. Supports US ZIP codes (5-digit), US ZIP+4 codes, Canadian FSAs (3-character), full Canadian postal codes (6-character), and latitude/longitude coordinates for reverse geocoding.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
code | string | Required | ZIP code, ZIP+4, FSA, Canadian postal code, or coordinates (lat,lon) |
include | string | Optional | Comma-separated enrichment flags. Only timezone is supported on this endpoint. |
Supported Code Types
| Type | Format | Example | Country | Base Cost |
|---|---|---|---|---|
| ZIP | 5 digits | 90210 | US | 1 credit |
| ZIP+4 | 9 digits (with or without dash) | 90210-1234 | US | 2 credits |
| FSA | 3 alphanumeric (A1A) | M5V | CA | 1 credit |
| Postal | 6 alphanumeric (A1A1A1) | M5V2H1 | CA | 1 credit |
| Coordinates | lat,lon (decimal degrees) | 34.1030,-118.4105 | US + CA | 2 or 4 credits (before timezone) |
code parameter as lat,lon.Available Enrichments
| Flag | Adds to Response | Cost | Availability |
|---|---|---|---|
timezone | IANA timezone name, UTC offsets, DST abbreviations | +1 data layer (× base) | US + CA |
Credit Cost
Quick ZIP credits = base × (1 + timezone + reverse_geocode). Base is 2 for ZIP+4 and 1 for ZIP, FSA, or Postal. Coordinates use the resolved type and add a reverse-geocode layer. ZIP+4 with timezone costs 4; coordinates resolving to ZIP+4 cost 4, or 6 with timezone. Unknown flags have no effect.
Response Fields
| Field | Type | Description |
|---|---|---|
country | string | "US" or "CA" |
code | string | The postal code |
code_type | string | ZIP, FSA, or Postal |
parent_code | string (optional) | Parent 5-digit ZIP or FSA (omitted for base codes) |
city | string | Primary city name |
state / state_name | string | State/province abbreviation and full name |
state_fips | string (optional) | 2-digit state FIPS code (US only) |
county / county_fips | string (optional) | County name and FIPS code (US only) |
multi_county | boolean (optional) | Whether ZIP spans multiple counties (US only) |
classification | string (optional) | ZIP type code (US only) |
classification_name | string (optional) | ZIP type name: General, PO Box, Military, Unique |
municipality | string (optional) | Municipality name (where applicable) |
location | object | {"lat": ..., "lon": ...} |
detail | object (optional) | Street-level detail for ZIP+4 / CA postal codes |
timezone | object (optional) | Present when include=timezone |
FALLBACK_USED notice. No additional credit is charged.ZIP+4 Detail Fields
When a ZIP+4 code is looked up, the detail object is populated with delivery-point data:
| Field | Type | Description |
|---|---|---|
zip4 | string | The 4-digit ZIP+4 suffix |
record_type | string | Address record type (e.g., S = Street, P = PO Box, H = Highrise, F = Firm) |
carrier_route | string | USPS carrier route code |
Street Detail Fields
Street-level address range information within the detail.street object:
| Field | Type | Description |
|---|---|---|
addr_low | string | Low end of primary address range |
addr_high | string | High end of primary address range |
prefix | string | Street name prefix directional (e.g., N, SW) |
name | string | Street name |
suffix | string | Street suffix (e.g., St, Ave, Blvd) |
postfix | string | Street name postfix directional |
odd_even | string | Address range parity: O (odd), E (even), B (both) |
sec_addr_abbr | string | Secondary address abbreviation (e.g., APT, STE, UNIT) |
sec_addr_low | string | Low end of secondary address range |
sec_addr_high | string | High end of secondary address range |
sec_addr_odd_even | string | Secondary address range parity: O, E, or B |
building_name | string | Building or firm name |
address | string | Formatted full address line |
Example Request
curl -H "X-Api-Key: YOUR_API_KEY" \ "https://api.zip-codes.com/v2/quick-zip?code=90210&include=timezone"
Example Response
{
"success": true,
"request": {
"code": "90210",
"include": [
"timezone"
]
},
"results": [
{
"code": "90210",
"code_type": "ZIP",
"country": "US",
"city": "Beverly Hills",
"state": "CA",
"state_name": "California",
"state_fips": "06",
"county": "Los Angeles",
"county_fips": "06037",
"classification": "G",
"classification_name": "General",
"location": {
"lat": 34.103131,
"lon": -118.416253
},
"timezone": {
"source": "IANA Time Zone Database / timezone-boundary-builder",
"iana_name": "America/Los_Angeles",
"name": "Pacific",
"abbreviation": "PST",
"abbreviation_dst": "PDT",
"utc_offset": -8,
"utc_offset_dst": -7,
"observes_dst": true
},
"success": true
}
],
"meta": {
"version": "2.0.0",
"timing_ms": 23,
"credits": {
"used": 2,
"remaining": 74998,
"breakdown": {
"base": 1,
"enrichments": {
"timezone": 1
}
},
"source": "subscription"
},
"request_id": "01M3SX2V9NY9MRRAMWVJG0C09E"
}
}
{
"success": true,
"request": {
"code": "M5V",
"include": [
"timezone"
]
},
"results": [
{
"code": "M5V",
"code_type": "FSA",
"country": "CA",
"city": "Toronto",
"state": "ON",
"state_name": "Ontario",
"location": {
"lat": 43.638388,
"lon": -79.40428
},
"timezone": {
"source": "IANA Time Zone Database / timezone-boundary-builder",
"iana_name": "America/Toronto",
"name": "Eastern",
"abbreviation": "EST",
"abbreviation_dst": "EDT",
"utc_offset": -5,
"utc_offset_dst": -4,
"observes_dst": true
},
"success": true
}
],
"meta": {
"version": "2.0.0",
"timing_ms": 15,
"credits": {
"used": 2,
"remaining": 74998,
"breakdown": {
"base": 1,
"enrichments": {
"timezone": 1
}
},
"source": "subscription"
},
"request_id": "01M3SX2V9NY9MRRAMWVJG0C09E"
}
}
{
"success": true,
"request": {
"code": "99999"
},
"results": [
{
"success": false,
"input": {
"code": "99999"
},
"error": {
"code": "NOT_FOUND_ZIP",
"message": "ZIP code 99999 not found.",
"url": "https://www.zip-codes.com/api/"
}
}
],
"meta": {
"version": "2.0.0",
"timing_ms": 8,
"credits": {
"used": 1,
"remaining": 74999,
"breakdown": {
"base": 0,
"enrichments": {},
"note": "Not found (1 credit charged)."
},
"source": "subscription"
},
"request_id": "01M3SX2V9NY9MRRAMWVJG0C09E"
}
}
ZIP Code Details
Unknown include flags are ignored free with a VALIDATION_UNKNOWN_ENRICHMENT notice on this single endpoint. /v2/zip/batch ignores unknown flags without that notice.
Comprehensive postal code lookup with rich data including demographics, business statistics, delivery points, and optional enrichments and historical ACS profiles. Returns detailed information for US ZIP codes and Canadian postal codes.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
code | string | Required | US ZIP code, Canadian postal code, or coordinates (lat,lon) |
include | string | Optional | Comma-separated enrichment flags (see Data Enrichments) |
Available Enrichments
| Flag | Adds to Response | Cost | Availability |
|---|---|---|---|
timezone | IANA timezone name, UTC offsets, DST info. Multi-zone ZIPs return array with % coverage. | +1 | US + CA |
census | County, county subdivision, place, tract, block group, CBSA overlaps with % coverage | +1 | US + CA |
cd | Congressional districts (US) / federal electoral districts (CA) with % coverage | +1 | US + CA |
state_leg | State senate (upper) and house (lower) legislative district overlaps | +1 | US only |
school_district | School districts (NCES) with office address, grade range, locale, area overlap | +1 | US only |
acs_demographic | Population, sex, age distribution, race, ethnicity, citizenship (DP05 — 108 fields) | +1 | US only |
acs_social | Households, education, language, ancestry, marital status, computers/internet (DP02 — 154 fields) | +1 | US only |
acs_economic | Employment, income, poverty, occupation, industry, health insurance, commute (DP03 — 137 fields) | +1 | US only |
acs_housing | Housing units, occupancy, tenure, home value, rent, utilities, structure age (DP04 — 143 fields) | +1 | US only |
acs_{profile}_{YYYY} | Historical ACS for any year from 2011–2024 (14 years). Append _YYYY to any ACS flag (e.g., acs_housing_2022). 528 fields in recent years, 394 in earliest. See ACS Data. | +1 each | US only |
demographics | Population, race, age, households, income, and business establishment counts | +1 | US only |
medicare | Medicare CBSA code/name/type, rating area ID, SSA state/county code | +1 | US only |
ENRICHMENT_UNAVAILABLE notice. No credit is charged.Credit Cost
ZIP Details credits = 1 + billable flags + reverse_geocode. Base is 1 for every code type, including ZIP+4 and Postal. Canadian unavailable flags cost 0 with a notice. Example: include=timezone,census,cd on a ZIP = 4 credits.
Example Request
curl -H "X-Api-Key: YOUR_API_KEY" \ "https://api.zip-codes.com/v2/zip?code=90210&include=timezone,demographics"
Example Response
{
"success": true,
"request": {
"code": "90210",
"include": [
"timezone",
"demographics"
]
},
"results": [
{
"country": "US",
"code": "90210",
"code_type": "ZIP",
"city": "Beverly Hills",
"state": "CA",
"state_name": "California",
"state_fips": "06",
"county": "Los Angeles",
"county_fips": "06037",
"multi_county": false,
"location": {
"lat": 34.102823,
"lon": -118.414661
},
"area_codes": [
"310",
"323",
"424",
"738"
],
"elevation": {
"ft": 719,
"m": 219
},
"metro": {
"region": "West",
"division": "Pacific",
"csa": "348",
"csa_name": "Los Angeles-Long Beach, CA",
"msa": "31080",
"msa_name": "Los Angeles-Long Beach-Anaheim, CA"
},
"zip_info": {
"classification": "G",
"classification_name": "General",
"facility_code": "P",
"city_delivery_indicator": "Y",
"intro_date": "<2004-10",
"land_area_sq_mi": 10.9748,
"water_area_sq_mi": 0.054,
"zip4_count": 3515,
"delivery_points": {
"total_active": 10634,
"business": 1478,
"residential": 9289,
"po_box": 0,
"single_family": 6775,
"multi_family": 2421
}
},
"demographics": {
"population": {
"total": 21134,
"estimate": 22943,
"male": 10099,
"female": 11035
},
"race": {
"white": 17130,
"black": 366,
"hispanic": 1296,
"asian": 1406,
"american_indian": 25,
"hawaiian_pacific_islander": 12,
"other": 481
},
"age": {
"median": 49.3,
"median_male": 49.3,
"median_female": 49.2
},
"households": {
"total": 8553,
"persons_per_household": 2.47,
"average_family_size": 3.13,
"median_income": 190382,
"average_home_value": 2000000
},
"business": {
"establishments": 2536,
"employees": 32353,
"payroll_q1": 648013000,
"payroll_annual": 2653591000
}
},
"timezone": {
"source": "IANA Time Zone Database / timezone-boundary-builder",
"zones": [
{
"iana_name": "America/Los_Angeles",
"name": "Pacific",
"abbreviation": "PST",
"abbreviation_dst": "PDT",
"utc_offset": -8,
"utc_offset_dst": -7,
"observes_dst": true,
"pct_of_zip": 100.0
}
]
},
"success": true
}
],
"meta": {
"version": "2.0.0",
"timing_ms": 87,
"credits": {
"used": 3,
"remaining": 74997,
"breakdown": {
"base": 1,
"enrichments": {
"timezone": 1,
"demographics": 1
}
},
"source": "subscription"
},
"request_id": "01M3SX2V9NY9MRRAMWVJG0C09E"
}
}
Base Fields (no include flag required)
| Field | Type | Description |
|---|---|---|
country | string | "US" or "CA" |
code | string | The postal code |
code_type | string | ZIP, FSA, or Postal |
parent_code | string (optional) | Parent 5-digit ZIP (for ZIP+4 queries) or parent FSA (for CA postal queries). Omitted for base codes. |
city | string | Primary city name |
state / state_name | string | State/province abbreviation and full name |
state_fips | string (optional) | 2-digit state FIPS code (US only) |
county / county_fips | string | County name and FIPS code (US only) |
multi_county | boolean (optional) | Whether the ZIP spans multiple counties (US only) |
municipality | string (optional) | Municipality name (where applicable) |
location | object | {"lat": 34.10, "lon": -118.41} |
area_codes | string[] (optional) | Telephone area codes overlapping this postal code |
elevation | object (optional) | {"ft": 719, "m": 219} — centroid elevation in feet and meters |
metro | object (optional) | MSA/CBSA statistical area info (US only, see sub-fields below) |
zip_info | object (optional) | ZIP classification, facility code, land/water area, delivery points (US only) |
postal_info | object (optional) | Canadian postal metadata: record type, address type, FSA stats (CA only) |
city_aliases | array (optional) | Alternative city names with mailing status and intro date |
detail | object (optional) | ZIP+4 / CA postal street-level overlay (omitted for 5-digit ZIP / FSA queries) |
metro Sub-Fields (US only)
| Field | Type | Description |
|---|---|---|
region | string (optional) | Census region (e.g., West, Northeast) |
division | string (optional) | Census division (e.g., Pacific, Middle Atlantic) |
csa / csa_name | string (optional) | Combined Statistical Area code and name |
msa / msa_name | string (optional) | Metropolitan Statistical Area code and name |
pmsa / pmsa_name | string (optional) | Primary MSA code and name (where applicable) |
postal_info Sub-Fields (CA only)
| Field | Type | Description |
|---|---|---|
record_type | string | Record type code |
address_type | string | Address type classification |
fsa | string | Parent FSA (3-character) |
delivery_postal_code | string | Delivery postal code |
fsa_population | number | FSA population |
fsa_dwellings | number | Total dwellings in FSA |
fsa_dwellings_occupied | number | Occupied dwellings in FSA |
fsa_postal_code_count | number | Number of postal codes in the FSA |
Radius Search
Find all postal codes within a given radius of a center point. Specify the center via a single code parameter (ZIP, FSA, Postal Code, or lat,lon coordinates). Cross-border searches include Canadian postal codes in centroid mode and FSAs in spatial mode. Supports donut searches (min radius) and result limiting.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
code | string | Required | Center point — US ZIP (5-digit), ZIP+4, Canadian FSA, Canadian Postal Code, or lat,lon coordinates (e.g. 41.878,-87.629) |
max | number or string | Required | Maximum radius in miles (e.g. 25), or "auto" (density-based) / "auto-commute" (commute-behavior-based). Numeric max must be greater than zero: centroid up to 500, spatial up to 250. Free tier: 100 centroid / 50 spatial; test keys: 10 miles. See Auto Radius. |
min | number | Optional | Minimum radius in miles for donut search: nonnegative and less than max. Default: 0 |
include | string | Optional | Comma-separated enrichment flags (see table below) |
mode | string | Optional | centroid (default) — fast haversine on centroids, returns US ZIP + CA Postal. spatial — precise boundary analysis with pct_inside, returns US ZIP + CA FSA. |
limit | number | Optional | Positive integer maximum results; truncation reports summary.total_available. Centroid mode caps at 10,000 with RESULTS_CAPPED. |
Available Enrichments
| Flag | Adds to Response | Cost | Availability |
|---|---|---|---|
timezone | IANA timezone name, UTC offsets, DST abbreviations for each result | +1 data layer (× base) | US + CA |
acs_demographic | Population-weighted aggregate: population, sex, age, race, ethnicity (DP05) | +1 data layer (× base) | US only |
acs_social | Population-weighted aggregate: households, education, language, ancestry (DP02) | +1 data layer (× base) | US only |
acs_economic | Population-weighted aggregate: employment, income, poverty, commute (DP03) | +1 data layer (× base) | US only |
acs_housing | Population-weighted aggregate: occupancy, tenure, home value, rent (DP04) | +1 data layer (× base) | US only |
acs_{profile}_{YYYY} | Historical ACS aggregate for any year from 2011–2024. Append _YYYY to any ACS flag (e.g., acs_economic_2019). See ACS Data for year-by-year coverage. | +1 layer each (× base) | US only |
census, cd, state_leg, school_district) are available on /v2/zip and /v2/address. If requested on /v2/radius, these flags are silently ignored — no credit is charged and an ENRICHMENT_UNAVAILABLE notice is included in the response. Use /v2/zip for territory enrichments on individual codes.Every radius search starts with a base cost determined by how far you're searching — bigger search = more work for the server.
Each enrichment you add (timezone, demographics, etc.) multiplies that base cost, because the API has to gather that data for every result in your radius.
Think of it as: “search cost × number of data layers”
Quick worked example
Searching 25 miles with timezone: base cost is 1 (short search) × 2 data layers (the search itself + timezone) = 2 credits.
Credit Cost
Centroid mode (default, faster): Wider bands — the first 100 miles costs 1 base credit, the next 100 costs 2, and so on up to 500 miles.
Spatial mode (precise boundaries): Narrower bands — the first 50 miles costs 1 base credit, the next 50 costs 2, and so on up to 250 miles.
Cost = base × (1 + distinct timezone/ACS flags + auto_radius); auto_radius is 1 for either auto option, otherwise 0.
Auto Radius
Instead of specifying a numeric radius, pass max=auto or max=auto-commute to let the API calculate an appropriate search radius for the center point. This accepts a ZIP, ZIP+4, FSA, Postal code, or lat/lon coordinate center.
| Mode | Based On | Range | Best For |
|---|---|---|---|
auto | Population density: 341 ÷ density0.42 | 3–150 miles | General-purpose searches scaled to urbanity |
auto-commute | ACS commuting patterns: mean travel time × transport-weighted speed × 1.5 | 3–100 miles | Service-area and labor-market analysis |
auto-commute automatically falls back to density-based auto and includes an AUTO_COMMUTE_FALLBACK notice in the response. The resolved radius appears in results[].search.max and the resolution method in results[].search.auto_mode ("density" or "commute").Credit cost: Using auto-radius counts as one additional data layer in the cost calculation. Example: max=auto with include=timezone = base × 3 data layers = 3 credits for a short-range search.
Example Request
curl -H "X-Api-Key: YOUR_API_KEY" \ "https://api.zip-codes.com/v2/radius?code=48226&max=25&include=timezone"
Example Response
{
"success": true,
"request": {
"code": "48226",
"max": 25,
"include": [
"timezone"
],
"mode": "centroid"
},
"results": [
{
"search": {
"center": {
"code": "48226",
"code_type": "ZIP",
"city": "DETROIT",
"state": "MI",
"location": {
"lat": 42.329997,
"lon": -83.051206
}
},
"max": 25,
"min": 0,
"mode": "centroid"
},
"matches": [
{
"country": "US",
"code": "48226",
"code_type": "ZIP",
"city": "Detroit",
"state": "MI",
"county": "Wayne",
"county_fips": "26163",
"classification": "G",
"classification_name": "General",
"location": {
"lat": 42.329997,
"lon": -83.051206
},
"distance_miles": 0.0,
"area_sq_mi": 1.53,
"timezone": {
"source": "IANA Time Zone Database / timezone-boundary-builder",
"iana_name": "America/Detroit",
"name": "Eastern",
"abbreviation": "EST",
"abbreviation_dst": "EDT",
"utc_offset": -5,
"utc_offset_dst": -4,
"observes_dst": true
}
},
{
"country": "US",
"code": "48233",
"code_type": "ZIP",
"city": "Detroit",
"state": "MI",
"county": "Wayne",
"county_fips": "26163",
"classification": "P",
"classification_name": "PO Box",
"location": {
"lat": 42.325858,
"lon": -83.058515
},
"distance_miles": 0.47,
"timezone": {
"source": "IANA Time Zone Database / timezone-boundary-builder",
"iana_name": "America/Detroit",
"name": "Eastern",
"abbreviation": "EST",
"abbreviation_dst": "EDT",
"utc_offset": -5,
"utc_offset_dst": -4,
"observes_dst": true
}
}
],
"success": true
}
],
"meta": {
"version": "2.0.0",
"timing_ms": 312,
"credits": {
"used": 2,
"remaining": 74998,
"breakdown": {
"base": 1,
"enrichments": {
"timezone": 1
},
"calculation": "1 x (1 + 1) = 2"
},
"source": "subscription"
},
"request_id": "01M3SX2V9NY9MRRAMWVJG0C09E"
}
}
The radius summary contains total_count, us_zip_count, ca_fsa_count, ca_postal_count, and optional total_available. Examples are trimmed.
Search Fields
| Field | Type | Description |
|---|---|---|
search.center.code | string | Resolved center postal code |
search.center.code_type | string | ZIP, FSA, or Postal |
search.center.city | string | Center city name |
search.center.state | string | Center state/province abbreviation |
search.center.location | object | {"lat": ..., "lon": ...} — center coordinates |
search.max | number | Resolved maximum radius in miles (numeric value, even when auto was requested) |
search.min | number | Minimum radius in miles (donut inner ring) |
search.mode | string | "centroid" or "spatial" |
search.auto_mode | string (optional) | "density" when max=auto, "commute" when max=auto-commute, omitted for numeric radius |
Match Fields
| Field | Type | Description |
|---|---|---|
country | string | "US" or "CA" |
code | string | Postal code |
code_type | string | ZIP, FSA, or Postal |
city | string | City name |
state | string | State/province abbreviation |
county | string (optional) | County name (US only) |
county_fips | string (optional) | County FIPS code (US only) |
classification | string (optional) | ZIP type code (US only, e.g., G, P, M, U) |
classification_name | string (optional) | ZIP type name (e.g., General, PO Box, Military, Unique) |
location | object | {"lat": ..., "lon": ...} |
distance_miles | number | Distance from center point in miles |
pct_inside | number (optional) | Percentage of the postal code area inside the search radius (spatial mode only; omitted in centroid mode) |
area_sq_mi | number (optional) | Total area of the postal code in square miles (omitted for point-only codes) |
Distance Calculation
Calculate the great-circle distance between two points. Supports any combination of ZIP codes, ZIP+4 codes, FSAs, full Canadian postal codes, and lat/lon coordinates. Timezone data is always included at no extra cost. Each endpoint in the response includes an input_type field ("code" or "coordinates") indicating how the point was resolved.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
from | string | Required | Origin point. Accepts: US ZIP (90210), ZIP+4 (90210-1234), Canadian FSA (M5V), Canadian postal code (M5V2H1), or lat,lon coordinates (34.103,-118.410) |
to | string | Required | Destination point. Accepts: US ZIP (90210), ZIP+4 (90210-1234), Canadian FSA (M5V), Canadian postal code (M5V2H1), or lat,lon coordinates (40.758,-73.986) |
from=90210-1234&to=40.758,-73.9855Credit Cost
Fixed 1 credit per pair. Timezone is always included at no extra cost.
Calculate your costExample Request
curl -H "X-Api-Key: YOUR_API_KEY" \ "https://api.zip-codes.com/v2/distance?from=90210&to=10001"
Example Response
{
"success": true,
"request": {
"from": "90210",
"to": "10001"
},
"results": [
{
"from": {
"country": "US",
"code": "90210",
"code_type": "ZIP",
"city": "BEVERLY HILLS",
"state": "CA",
"county": "LOS ANGELES",
"location": {
"lat": 34.102823,
"lon": -118.414661
},
"timezone": {
"source": "IANA Time Zone Database / timezone-boundary-builder",
"iana_name": "America/Los_Angeles",
"name": "Pacific",
"abbreviation": "PST",
"abbreviation_dst": "PDT",
"utc_offset": -8,
"utc_offset_dst": -7,
"observes_dst": true
},
"input_type": "code"
},
"to": {
"country": "US",
"code": "10001",
"code_type": "ZIP",
"city": "NEW YORK",
"state": "NY",
"county": "NEW YORK",
"location": {
"lat": 40.750177,
"lon": -73.997078
},
"timezone": {
"source": "IANA Time Zone Database / timezone-boundary-builder",
"iana_name": "America/New_York",
"name": "Eastern",
"abbreviation": "EST",
"abbreviation_dst": "EDT",
"utc_offset": -5,
"utc_offset_dst": -4,
"observes_dst": true
},
"input_type": "code"
},
"distance": {
"miles": 2453.39,
"km": 3948.3
},
"bearing": 65.9,
"success": true
}
],
"meta": {
"version": "2.0.0",
"timing_ms": 31,
"credits": {
"used": 1,
"remaining": 74999,
"breakdown": {
"base": 1,
"enrichments": {}
},
"source": "subscription"
},
"request_id": "01M3SX2V9NY9MRRAMWVJG0C09E"
}
}
Health Check
Returns API and database health status. No authentication required.
Three-state health: healthy (normal), degraded (DB latency >500ms), unhealthy (DB unreachable, returns HTTP 503).
{
"success": true,
"data": {
"status": "healthy",
"database": {
"connected": true,
"latencyMs": 3
},
"version": "2.0.0"
},
"meta": {
"version": "2.0.0",
"timing_ms": 5,
"request_id": "01M3SX2V9NY9MRRAMWVJG0C09E"
}
}
Batch Requests
Five routes support batch processing via POST: quick-zip, zip, radius, distance, and address. Address accepts 250 items; the other four accept 100 items. There is no suggest batch: POST /v2/suggest is a single call. Individual items can succeed or fail independently (the overall HTTP status is 200 even if some items fail).
AUTH_BATCH_REQUIRES_SUBSCRIPTION error.Each batch request uses its route-specific array (codes, searches, pairs, or addresses); request echoes the corresponding count. Failed items contain {success:false,input:{...},error:{code,message,url}}. Credit totals include source, remaining, and breakdown.
Batch Response Meta
{
"meta": {
"batch": {
"requested": 3,
"succeeded": 2,
"failed": 1
},
"credits": {
"used": 5,
"source": "subscription",
"remaining": 74995,
"breakdown": {
"base": 0,
"enrichments": {},
"note": "2 codes, 5 total credits"
}
},
"request_id": "01M3SX2V9NY9MRRAMWVJG0C09E",
"version": "2.0.0",
"timing_ms": 1
}
}
BATCH_DUPLICATES_DETECTED notice. Credits are reserved up front, unused credits are refunded, and disconnect/timeout refunds all credits.Batch Endpoints
| Endpoint | URL | Body Format |
|---|---|---|
| Quick ZIP | POST /v2/quick-zip/batch |
{"codes": ["90210", "M5V"], "include": "timezone"} |
| ZIP Details | POST /v2/zip/batch |
{"codes": ["90210", "10001"], "include": "timezone,census"} |
| Radius | POST /v2/radius/batch |
{"searches": [{"code": "90210", "max": 25}]} |
| Distance | POST /v2/distance/batch |
{"pairs": [{"from": "90210", "to": "10001"}]} |
| Address (250 max) | POST /v2/address/batch | {"addresses":["1600 Pennsylvania Ave NW, Washington DC 20500"],"include":["coordinates","acs_tract_economic"]} |
All other routes allow 100 items. include accepts a comma-separated string or array of up to 50 strings. Radius searches accept {code,max,min,include,limit}; top-level include, max, and min supply defaults overridden by per-search values. mode is batch-level only; default centroid, while spatial returns HTTP 400 SPATIAL_MODE_DISABLED_BATCH. Radius item input is {index,code,max}. Missing body/fields and oversized batches return HTTP 400; subscription/test-key restrictions 403; insufficient credits 402. Valid batches return HTTP 200.
Example: Quick ZIP Batch
curl -X POST "https://api.zip-codes.com/v2/quick-zip/batch" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"codes": ["90210", "M5V", "99999"], "include": "timezone"}'
Partial Failure
When some items fail, the overall HTTP status is still 200. Failed items appear in the results array with success: false and a per-item error object. The meta.batch summary tells you how many succeeded and failed:
{
"success": true,
"results": [
{
"success": true,
"code": "90210",
"city": "Beverly Hills",
"state": "CA",
"input": {
"code": "90210"
}
},
{
"success": true,
"code": "M5V",
"city": "Toronto",
"state": "ON",
"input": {
"code": "M5V"
}
},
{
"success": false,
"error": {
"code": "NOT_FOUND_ZIP",
"message": "Code 99999 not found.",
"url": "https://www.zip-codes.com/api/"
},
"input": {
"code": "99999"
}
}
],
"meta": {
"batch": {
"requested": 3,
"succeeded": 2,
"failed": 1
},
"credits": {
"used": 5,
"source": "subscription",
"remaining": 74995,
"breakdown": {
"base": 0,
"enrichments": {},
"note": "2 codes, 5 total credits"
}
},
"request_id": "01M3SX2V9NY9MRRAMWVJG0C09E",
"version": "2.0.0",
"timing_ms": 1
},
"request": {
"codes_count": 3,
"include": "timezone"
}
}
Data Enrichments
All enrichments are opt-in. Add them to the include parameter as a comma-separated list. On /zip each billable flag adds 1 credit; quick-zip and radius multiply their base by the number of data layers. Address charges requested coordinates plus delivered boundary flags and tract tags. See Credit Costs.
US ZIP code boundaries come from a commercial boundary provider, updated quarterly. The dataset includes ~33,400 polygon boundaries plus ~7,600 point-only entries (PO Box, Military, and Unique ZIP types that have no geographic area).
Census geographies (counties, tracts, places, etc.) are drawn independently of ZIP codes and almost never align. Where they overlap, each result includes two percentages: pct_of_zip and pct_of_area.
Understanding pct_of_zip vs. pct_of_area
pct_of_zip = intersection area ÷ ZIP area — "What percentage of this ZIP does the geography cover?" Use this for demographic weighting: if a county covers 60% of a ZIP, roughly 60% of that ZIP's population lives in that county.
pct_of_area = intersection area ÷ geography area — "What percentage of the geography falls within this ZIP?" Use this to gauge significance: a large county may overlap a ZIP but that ZIP is only a tiny sliver of the county.
Example: A county covers 40% of a ZIP (pct_of_zip = 40.0), but that overlap is only 2% of the county's total area (pct_of_area = 2.0). The county is meaningful to the ZIP, but the ZIP is insignificant to the county.
Canadian FSAs (Forward Sortation Areas, ~1,643): The first 3 characters of a postal code. Polygon boundaries from Statistics Canada, updated with each census cycle (every 5 years).
Full Canadian postal codes (~876,000): All 6 characters. Point coordinates only — Canada Post provides centroids but postal code polygon boundaries are not publicly available. Included in /v2/radius centroid mode (default). Not available in spatial mode.
US ZIP+4 (~40M codes): Uses the ZIP+4 centroid when available. ZIP+4 areas change monthly with carrier route reassignment and have no stable polygon boundary.
| Flag | Description | Endpoints | Added cost | Availability |
|---|---|---|---|---|
timezone | IANA timezone with DST info | Quick ZIP, ZIP, Radius | One data layer (× endpoint base) | US + CA |
census | Census boundary overlaps | ZIP, Address | +1 | US + CA |
cd | Congressional districts (US), federal electoral districts (CA /zip) | ZIP, Address (US) | +1 | US + CA |
state_leg | State legislature districts | ZIP, Address | +1 | US only |
school_district | School district boundaries (NCES) | ZIP, Address | +1 | US only |
acs_demographic | Population, age, sex, race (DP05) | ZIP, Radius | One data layer (× endpoint base) | US only |
acs_social | Households, education, language (DP02) | ZIP, Radius | One data layer (× endpoint base) | US only |
acs_economic | Employment, income, industry (DP03) | ZIP, Radius | One data layer (× endpoint base) | US only |
acs_housing | Housing units, occupancy, value (DP04) | ZIP, Radius | One data layer (× endpoint base) | US only |
acs_{profile}_{YYYY} | Historical ACS for years 2011–2024. Append year to any ACS flag (e.g., acs_housing_2022). 4 profiles × 14 years = 56 flags. See ACS Data for year-by-year coverage. | ZIP, Radius | One layer per tag (× endpoint base) | US only |
demographics | Population, race, age, households, income, business | ZIP | +1 | US only |
medicare | Medicare CBSA, rating area, SSA code | ZIP | +1 | US only |
coordinates | ZIP+4 point, latitude/longitude (6 decimals) | Address | +1 requested | US |
acs_tract_{demographic|social|economic|housing}[_2024|_2023|_2022] | Containing-tract ACS; no suffix = 2024 | Address | +1 per delivered tag | US |
ENRICHMENT_UNAVAILABLE notice. No credit is charged for unavailable enrichments.Timezone
Returns IANA timezone data including standard and daylight saving abbreviations and UTC offsets. In the /v2/zip endpoint, returns an object with source and a zones array with percentage overlap when a ZIP code spans multiple timezones. On other endpoints, timezone is a flat object per result.
Fields Returned
| Field | Type | Description |
|---|---|---|
source | string | Data source attribution |
iana_name | string | IANA timezone identifier (e.g., America/Los_Angeles) |
name | string | Display name (e.g., Pacific Standard Time) |
abbreviation | string | Standard time abbreviation (e.g., PST) |
abbreviation_dst | string | Daylight saving abbreviation (e.g., PDT) |
utc_offset | number | Standard UTC offset in hours (e.g., -8) |
utc_offset_dst | number | DST UTC offset in hours (e.g., -7) |
observes_dst | boolean | Whether this timezone observes daylight saving time |
pct_of_zip | number | /v2/zip only — percentage of ZIP area in this timezone |
/v2/zip, the timezone object contains a zones[] array (sorted by coverage descending); there is no primary shortcut. On other endpoints, a single timezone object is returned based on centroid point-in-polygon.{
"source": "IANA Time Zone Database / timezone-boundary-builder",
"zones": [
{
"iana_name": "America/Los_Angeles",
"name": "Pacific",
"abbreviation": "PST",
"abbreviation_dst": "PDT",
"utc_offset": -8,
"utc_offset_dst": -7,
"observes_dst": true,
"pct_of_zip": 100.0
}
]
}
Census Boundaries
Canadian census.current uses source Statistics Canada 2021 Census, year 2021. Sections include census_division, census_subdivision, tract, metro_area, economic_region, population_centre, consolidated_subdivision, and designated_place. FSA lookups also include province and overlap percentages (pct_of_fsa); postal lookups use pre-assigned areas and add dissemination_area/dissemination_block.
US sections are under results[i].census.current: county, county_subdivision, place, tract, and block_group are arrays; metro_micro_cbsa_statistical_area and metropolitan_cbsa_division are single objects. Empty lookups are null.
Boundary families. Each boundary flag returns its own top-level family: census, congressional_district (cd), state_legislative (state_leg), and school_district; on Canadian codes cd returns federal_electoral_district. Each family holds its data under current and will gain period keys beside it on its own cycle: boundary vintage for census (e.g. "2023"), Congress number for congressional_district (e.g. "118"), legislative year for state_legislative, and school year for school_district. A requested family with nothing found is present with current: null; an unrequested family is absent.
Returns all census geographic boundaries that overlap the ZIP code with percentage overlap calculations. Data sourced from Census Bureau TIGER/Line Cartographic Boundaries.
Census boundaries are hierarchical areas defined for statistical reporting — they are not drawn to follow ZIP code boundaries. A single ZIP almost always overlaps multiple tracts, places, and other geographies.
FIPS code structure and geography details
| Geography | FIPS Length | Example |
|---|---|---|
| State | 2 digits | 06 (California) |
| County | 5 digits | 06037 (Los Angeles Co.) |
| County Subdivision | 10 digits | 0603765000 |
| Place | 7 digits | 0644000 (Los Angeles city) |
| Census Tract | 11 digits | 06037264000 |
| Block Group | 12 digits | 060372640001 |
| Congressional District | 4 digits | 0634 |
Counties (~3,200): Primary legal division of every state. Connecticut replaced its 8 counties with 9 Planning Regions in 2022 (Census Bureau adopted these starting with 2024 data). Louisiana has parishes, Alaska has boroughs, and some cities in Virginia and Maryland are independent of any county.
County Subdivisions: Minor Civil Divisions (MCDs) in ~29 states represent legal townships and towns. In other states, Census-defined County Divisions (CCDs) serve as statistical equivalents.
Places: Incorporated places (cities, towns, villages with legal boundaries) and Census Designated Places (CDPs — statistical areas for unincorporated communities).
Census Tracts (~85,000): Designed for 2,500–8,000 people with socioeconomic homogeneity. The tract code has an implied decimal: 046300 = tract 463.00.
Block Groups: The smallest geography with ACS data, containing 600–3,000 people. GEOID = parent tract code + 1 digit.
CBSAs: Metropolitan Statistical Areas (core city 50K+ population) or Micropolitan (10K–50K). Rural areas have no CBSA. Metropolitan Divisions subdivide the largest metros into component areas.
Included Boundary Types
| Boundary | Description |
|---|---|
county | County boundaries with FIPS codes |
county_subdivision | County subdivisions (CCDs, MCDs) |
place | Census-designated places and incorporated cities |
tract | Census tracts with GEOID |
block_group | Census block groups |
metro_micro_cbsa_statistical_area | Metropolitan/Micropolitan statistical areas |
metropolitan_cbsa_division | Metro divisions (where applicable) |
Boundary identifiers use fips for counties, cbsa_code for CBSAs, or geoid as applicable; other fields include, name, land_area_sq_mi, water_area_sq_mi, pct_of_zip (% of ZIP this boundary covers), and pct_of_area (% of boundary this ZIP covers).
{
"census": {
"current": {
"county": [
{
"name": "Los Angeles County",
"land_area_sq_mi": 4058.05,
"water_area_sq_mi": 693.72,
"pct_of_zip": 100.0,
"pct_of_area": 0.3,
"fips": "06037"
}
],
"place": [
{
"geoid": "0606000",
"name": "Beverly Hills city",
"land_area_sq_mi": 5.69,
"water_area_sq_mi": 0.01,
"pct_of_zip": 49.3,
"pct_of_area": 95.1
}
],
"tract": [
{
"geoid": "06037700900",
"name": "Census Tract 7009",
"land_area_sq_mi": 1.12,
"water_area_sq_mi": 0.0,
"pct_of_zip": 10.2,
"pct_of_area": 100.0
}
],
"metro_micro_cbsa_statistical_area": {
"name": "Los Angeles-Long Beach-Anaheim, CA Metro Area",
"land_area_sq_mi": 4849.89,
"water_area_sq_mi": 698.63,
"pct_of_zip": 100.0,
"pct_of_area": 0.2,
"cbsa_code": "31080"
},
"source": "Census Bureau TIGER/Line Cartographic Boundaries",
"year": 2024,
"vintage": "2024"
}
}
}
Congressional Districts
Returns congressional district overlaps for the current Congress session, with primary district identification and area percentages. Fields sit under congressional_district.current, beside the boundary file's source, year, and vintage.
Fields Returned (US)
| Field | Type | Description |
|---|---|---|
congress | number | Congressional session number (e.g., 119) |
primary.geoid | string | GEOID of the primary (highest overlap) district |
primary.state | string | State abbreviation |
primary.district_number | integer | District number |
districts[] | array | All overlapping districts with geoid, name, state, district_number, land_area_sq_mi, water_area_sq_mi, pct_of_zip, pct_of_area |
Fields Returned (CA)
Canadian codes return federal_electoral_district.current instead, with source (Statistics Canada 2021 Census), year 2021, and a districts array. Full postal codes use assigned UIDs/names; FSA boundary overlaps include pct_of_fsa. Canadian codes never return congressional_district, state_legislative, or school_district.
{
"congressional_district": {
"current": {
"source": "Census Bureau TIGER/Line Cartographic Boundaries",
"year": 2024,
"vintage": "2024",
"congress": 119,
"districts": [
{
"geoid": "0632",
"state": "CA",
"district_number": 32,
"name": "Congressional District 32",
"land_area_sq_mi": 296.24,
"water_area_sq_mi": 92.38,
"pct_of_zip": 62.9,
"pct_of_area": 2.3
},
{
"geoid": "0636",
"state": "CA",
"district_number": 36,
"name": "Congressional District 36",
"land_area_sq_mi": 97.11,
"water_area_sq_mi": 97.51,
"pct_of_zip": 37.1,
"pct_of_area": 4.2
}
],
"primary": {
"geoid": "0632",
"state": "CA",
"district_number": 32
}
}
}
}
State Legislature
Returns state senate (upper chamber) and assembly/house (lower chamber) district overlaps with area percentages, under state_legislative.current beside source, year, and vintage. US only
Fields Returned
| Field | Type | Description |
|---|---|---|
legislative_year | integer | Legislative year of the district plan (e.g., 2024) |
upper[] | array | State Senate district overlaps |
lower[] | array | State House/Assembly district overlaps |
Each district includes: geoid, name, district_code, state, state_fips, legislative_session_year, land_area_sq_mi, water_area_sq_mi, pct_of_zip, pct_of_area.
{
"state_legislative": {
"current": {
"source": "Census Bureau TIGER/Line Cartographic Boundaries",
"year": 2024,
"vintage": "2024",
"legislative_year": 2024,
"upper": [
{
"geoid": "06024",
"name": "24",
"name_full": "State Senate District 24",
"state": "CA",
"state_fips": "06",
"district_code": "024",
"legislative_session_year": "2024",
"land_area_sq_mi": 327.54,
"pct_of_zip": 92.9
}
],
"lower": [
{
"geoid": "06051",
"name": "51",
"name_full": "Assembly District 51",
"state": "CA",
"state_fips": "06",
"district_code": "051",
"legislative_session_year": "2024",
"land_area_sq_mi": 56.4,
"pct_of_zip": 63.5
}
]
}
}
}
School Districts
Returns NCES school district data with boundary overlaps, under school_district.current with source, school_year, and a districts array. US only
District boundaries are from the National Center for Education Statistics (NCES). A single ZIP can overlap multiple school districts because different district types serve the same geographic area at different grade levels.
District type breakdown
Unified: Serves all grades K–12. The most common type nationwide.
Elementary / Secondary: Grade-banded districts that overlap geographically. Elementary districts cover lower grades (K–6 or K–8), while secondary districts cover upper grades (7–12 or 9–12).
Administrative: Supervisory unions (52 records, all in Vermont). The leaid field is a 7-character NCES Local Education Agency ID.
Locale codes: Range from 11 (City—Large) to 43 (Rural—Remote). Returned in the locale object as both a numeric code and description.
Fields Returned per District
| Field | Type | Description |
|---|---|---|
leaid | string | NCES Local Education Agency ID |
name | string | District name |
type | string | District type: unified, elementary, secondary, administrative, other |
grade_low / grade_high | string | Grade range served (e.g., PK to 12) |
office | object | Office address, city, state, ZIP, county, lat/lon |
locale | object | Locale classification code and description (city/suburb/town/rural) |
pct_of_zip / pct_of_area | number | Overlap percentages |
land_area_sq_mi | number | District land area |
{
"school_district": {
"current": {
"source": "National Center for Education Statistics (NCES)",
"school_year": "2024-2025",
"districts": [
{
"leaid": "0604830",
"name": "Beverly Hills Unified School District",
"type": "unified",
"grade_low": "KG",
"grade_high": "12",
"state_fips": "06",
"land_area_sq_mi": 6.02,
"pct_of_zip": 39.9,
"pct_of_area": 72.8,
"centroid": {
"lat": 34.07923,
"lon": -118.4024374
},
"office": {
"address": "624 N. Rexford Dr.",
"city": "Beverly Hills",
"state": "CA",
"zip": "90210",
"county": "Los Angeles County",
"location": {
"lat": 34.078986,
"lon": -118.40392
}
},
"locale": {
"code": "21",
"description": "Suburb - Large"
},
"nces_codes": {
"mtfcc": "G5420",
"mtfcc_desc": "Unified School District",
"funcstat": "E",
"funcstat_desc": "Active"
}
}
]
}
}
}
ACS Data
American Community Survey 5-year estimates from the Census Bureau. Four separate data profiles available, each activated by its own flag. US only
ACS metrics include an estimate (est) and margin of error (moe). Percentage fields also include pct and pct_moe. Suppressed Census values are returned as null.
year field and a vintage field indicating the exact dataset. Current ACS flags (e.g., acs_demographic) return the most recent year (2020–2024). Historical flags (e.g., acs_demographic_2022) return the specified year's dataset. You can request current and historical simultaneously — they appear under acs.current and acs["2022"] respectively. 14 years available: 2011–2024.acs_demographic — DP05 (108 fields)
| Section | Key Fields |
|---|---|
| Sex and Age | Total population, male/female counts, age brackets (under 5 through 85+), median age |
| Race | White, Black, American Indian, Asian, Pacific Islander, other, two or more races |
| Hispanic or Latino and Race | Hispanic/Latino totals, breakdown by race within Hispanic/non-Hispanic |
| Citizen, Voting Age Population | Citizens 18+, total voting age population |
| Total Housing Units | Housing unit count |
acs_social — DP02 (154 fields)
| Section | Key Fields |
|---|---|
| Households by Type | Total households, family/nonfamily, married-couple, single-parent, average size |
| Relationship | Householder, spouse, child, other relatives, nonrelatives, unmarried partner |
| Marital Status | Never married, now married, separated, widowed, divorced |
| Fertility | Women 15–50 who had a birth in the past 12 months |
| Grandparents | Grandparents living with grandchildren, responsible for care |
| School Enrollment | Nursery through graduate school, public/private breakdown |
| Educational Attainment | Less than 9th grade through doctorate, high school+, bachelor's+ |
| Veteran Status | Civilian veterans 18+ |
| Disability Status | Civilian noninstitutionalized population with a disability |
| Residence 1 Year Ago | Same house, different house (same county, state, abroad) |
| Place of Birth | Native vs. foreign-born, state of birth, world region |
| Language Spoken at Home | English only, Spanish, Asian/Pacific Island, other, English proficiency |
| Ancestry | Top ancestral origins reported |
| Computers and Internet Use | Households with computer, broadband, smartphone, no internet |
acs_economic — DP03 (137 fields)
| Section | Key Fields |
|---|---|
| Employment Status | Labor force, employed, unemployed, unemployment rate, armed forces |
| Commuting to Work | Drove alone, carpooled, public transit, walked, work from home, mean travel time |
| Occupation | Management, service, sales, construction, production, transportation |
| Industry | Agriculture, manufacturing, retail, healthcare, education, finance, tech |
| Class of Worker | Private wage, government, self-employed, unpaid family |
| Income and Benefits | Median household/family income, per capita, with earnings/Social Security/retirement |
| Health Insurance Coverage | With/without coverage, private, public, by employment status |
| Poverty Level | Families and people below poverty, by age, family type, education |
acs_housing — DP04 (143 fields)
| Section | Key Fields |
|---|---|
| Housing Occupancy | Total units, occupied, vacant, homeowner vacancy rate, rental vacancy rate |
| Units in Structure | Single-family detached/attached, 2–4 units, 5–19, 20+, mobile home, boat/RV |
| Year Structure Built | 2020+, 2010–2019, 2000–2009, through 1939 or earlier |
| Rooms / Bedrooms | 1 room through 9+, median rooms, bedroom count distribution |
| Housing Tenure | Owner-occupied, renter-occupied, average household size by tenure |
| Year Householder Moved In | 2021+, 2018–2020, 2010–2017, through 1989 or earlier |
| Vehicles Available | No vehicle, 1, 2, 3+ vehicles |
| House Heating Fuel | Gas, electric, fuel oil, coal, wood, solar, other, no fuel |
| Selected Characteristics | Lacking plumbing, lacking kitchen, no telephone service |
| Value | Owner-occupied home value distribution, median value |
| Mortgage Status | With/without mortgage, second mortgage, home equity loan |
| Monthly Owner Costs | Cost distribution, median, as percentage of household income |
| Gross Rent | Rent distribution, median rent, as percentage of household income |
Historical ACS Data (2011–2024)
Append _YYYY to any ACS profile flag to request a specific year. Example: include=acs_housing_2022 returns the 2018–2022 5-Year Estimates for housing. You can request multiple years simultaneously (e.g., include=acs_economic,acs_economic_2019). Each flag adds one data layer: +1 credit on /zip, multiplied by the distance-band base on /radius. The current year's suffix is the same request as the unsuffixed flag (acs_economic and acs_economic_2024 return one block under current and are charged once) — on every endpoint, including the address tract flags. When Census publishes the next release, current moves to it and 2024 is requested as _2024. On /v2/zip, a year Census published no data for at that ZCTA comes back with published: false and is not charged.
| Year | ACS 5-Year Estimates | Fields | Coverage |
|---|---|---|---|
| 2024 (current) | 2020–2024 | 528 | 97.4% |
| 2023 | 2019–2023 | 528 | 100% |
| 2022 | 2018–2022 | 521 | 98.7% |
| 2021 | 2017–2021 | 518 | 98.1% |
| 2020 | 2016–2020 | 518 | 98.1% |
| 2019 | 2015–2019 | 517 | 97.9% |
| 2018 | 2014–2018 | 486 | 92.0% |
| 2017 | 2013–2017 | 483 | 91.5% |
| 2016 | 2012–2016 | 463 | 87.7% |
| 2015 | 2011–2015 | 463 | 87.7% |
| 2014 | 2010–2014 | 441 | 83.5% |
| 2013 | 2009–2013 | 441 | 83.5% |
| 2012 | 2008–2012 | 394 | 74.6% |
| 2011 | 2007–2011 | 394 | 74.6% |
null. 394 “universal” fields are available across all 14 years./v2/address, tract profiles use data.acs.tract.current or data.acs.tract["2023"]/["2022"], with the same profile field names. On /v2/zip, ACS returns per-ZIP data under acs.current.{section} (or acs["2022"].{section} for historical), newest year first. Each /v2/zip year block carries published: false means Census published no data for that ZIP's ZCTA in that year (ZCTAs are redrawn each decade), so its profiles are null and a note says so. On /v2/radius, returns population-weighted aggregates under stats.acs.current.{section} — the stats object appears at the top level of each radius result alongside search, matches, and summary. Current dataset: 2020–2024 5-Year Estimates. Historical: 2011–2024 (14 years total).{
"acs": {
"current": {
"geo_id": "860Z200US90210",
"published": true,
"year": 2024,
"product": "ACS 5-Year Estimates Data Profiles",
"vintage": "2020-2024",
"geography_level": "zcta",
"tables": {
"demographic": "DP05"
},
"demographic": {
"sex_and_age": {
"male": {
"est": 10099,
"moe": 523,
"pct": 47.8,
"pct_moe": 2.1
},
"female": {
"est": 11035,
"moe": 523,
"pct": 52.2,
"pct_moe": 2.1
},
"median_age": {
"est": 49.3,
"moe": 1.8
},
"total_population": {
"est": 21134,
"moe": 82,
"column": "DP05_0001"
}
},
"race": {
"one_race": {
"white": {
"est": 17130,
"moe": 655,
"pct": 81.1,
"pct_moe": 2.4
},
"black": {
"est": 366,
"moe": 175,
"pct": 1.7,
"pct_moe": 0.8
},
"asian": {
"total": {
"est": 1406,
"moe": 320,
"pct": 6.7,
"pct_moe": 1.5
}
}
}
}
},
"source": "U.S. Census Bureau"
}
}
}
Demographics
Returns population, race, age, household, and business establishment data. Sourced from US Census Bureau and IRS Business Master File data.
Fields Returned
| Field | Type | Description |
|---|---|---|
| population | ||
population.total | number | Total population (Census 2020) |
population.estimate | number | Current population estimate |
population.male | number | Male population |
population.female | number | Female population |
| race | ||
race.white | number | White population |
race.black | number | Black or African American population |
race.hispanic | number | Hispanic or Latino population |
race.asian | number | Asian population |
race.american_indian | number | American Indian / Alaska Native population |
race.hawaiian_pacific_islander | number | Native Hawaiian / Pacific Islander population |
race.other | number | Other race population |
| age | ||
age.median | number | Median age |
age.median_male | number | Median age (male) |
age.median_female | number | Median age (female) |
| households | ||
households.total | number | Total households |
households.persons_per_household | number | Average persons per household |
households.average_family_size | number | Average family size |
households.median_income | number | Median household income (USD) |
households.average_home_value | number | Average home value (USD) |
| business | ||
business.establishments | number | Number of business establishments |
business.employees | number | Total employees |
business.payroll_q1 | number | First quarter payroll (full USD) |
business.payroll_annual | number | Annual payroll (full USD) |
business.employment_flag | string | Employment range flag when exact count is suppressed |
{
"demographics": {
"population": {
"total": 21134,
"estimate": 22943,
"male": 10099,
"female": 11035
},
"race": {
"white": 17130,
"black": 366,
"hispanic": 1296,
"asian": 1406,
"american_indian": 25,
"hawaiian_pacific_islander": 12,
"other": 481
},
"age": {
"median": 49.3,
"median_male": 49.3,
"median_female": 49.2
},
"households": {
"total": 8792,
"persons_per_household": 2.2,
"average_family_size": 2.86,
"median_income": 136490,
"average_home_value": 1953100
},
"business": {
"establishments": 3142,
"employees": 28853,
"payroll_q1": 625981000,
"payroll_annual": 2690487000
}
}
}
Medicare
Returns Medicare geographic identifiers used in healthcare pricing, insurance rating areas, and CMS administrative boundaries.
Fields Returned
| Field | Type | Description |
|---|---|---|
cbsa_code | string | Core Based Statistical Area code used by CMS for Medicare payment |
cbsa_name | string | CBSA name (e.g., “Los Angeles-Long Beach-Anaheim, CA”) |
cbsa_type | string | Metropolitan or Micropolitan (omitted if rural) |
rating_area_id | string | ACA marketplace rating area identifier |
ssa_state_county_code | string | SSA state/county code used in Medicare administrative systems |
multi_county_notice | string | Present only when a ZIP spans multiple counties with different Medicare assignments |
{
"medicare": {
"cbsa_code": "31080",
"cbsa_name": "Los Angeles-Long Beach-Anaheim, CA",
"cbsa_type": "Metropolitan",
"rating_area_id": "16",
"ssa_state_county_code": "05210"
}
}
Credit Costs
Lookup calls use credits from your plan; health and demo calls are not billed. Simple lookups cost 1. Adding enrichments (extra data like demographics or timezone) adds to the cost. The radius endpoint scales with search distance. This section breaks down exactly what each call costs — no surprises.
| Endpoint | Base Cost | + Enrichments | Plain English |
|---|---|---|---|
| Address | 1 per request | + coordinates requested + delivered boundary/tract tags | 1 base; no match adds requested coordinates |
| Quick ZIP | 1 (ZIP/FSA/Postal), 2 (ZIP+4) | × (1 + timezone + reverse_geocode) | ZIP+4 + timezone = 4; coordinates to ZIP+4 + timezone = 6 |
| ZIP Details | 1 (all code types) | + billable flags + reverse_geocode | ZIP+4 + timezone = 2 |
| Distance | 1 per pair | timezone free | Always 1 credit |
| Suggest | 1–5 (by limit) | N/A | 1 credit for ≤15 results |
| Radius | 1–5 (by distance) | × (1 + flags + auto_radius) | Distinct timezone/ACS requests, including historical years (the current year's suffix and the unsuffixed flag count once) |
| Batch | Per-item cost | Same as single | Sum of individual items |
| Health | 0 | N/A | Always free |
Address Matching
1 base + requested coordinates + each delivered boundary flag + each delivered tract tag. No match costs 1 (+1 for coordinates); unavailable boundary/tract flags are not charged.
Quick ZIP & ZIP Details
Quick ZIP credits = base × (1 + timezone + reverse_geocode). Base is 2 for ZIP+4 and 1 for ZIP, FSA, or Postal. Coordinates use the resolved type and add a reverse-geocode layer. ZIP+4 with timezone costs 4; coordinates resolving to ZIP+4 cost 4, or 6 with timezone. Unknown flags have no effect. ZIP Details credits = 1 + billable flags + reverse_geocode. Base is 1 for every code type, including ZIP+4 and Postal. Canadian unavailable flags cost 0 with a notice.
Examples: quick-zip ZIP+4 with timezone = 4. Full /zip ZIP+4 with timezone + demographics = 3.
Radius Search
Base cost scales with distance (banded pricing). Each enrichment multiplies the base rather than adding to it. Auto-radius counts as one additional data layer.
Examples: 25mi with no flags = 1. 25mi with timezone = 2. 200mi centroid with 4 ACS flags = 10.
Distance
Fixed 1 credit per pair. Timezone data is always included at no extra cost. Mix any input types freely.
Suggest
Cost scales with the requested limit: 1–15 results = 1 credit, 16–50 = 2, 51–150 = 3, 151–500 = 5. Billed on requested limit, not results returned.
Radius Credit Costs
Formula: base × (1 + enrichment_count + auto_radius). Base bands differ by mode.
Centroid Mode (default) — ceil(radius / 100), max 500mi
| Band | Radius Range | Base | No Flags | + 1 flag | + 2 flags |
|---|---|---|---|---|---|
| 1 | 1–100 mi | 1 | 1 | 2 | 3 |
| 2 | 101–200 mi | 2 | 2 | 4 | 6 |
| 3 | 201–300 mi | 3 | 3 | 6 | 9 |
| 4 | 301–400 mi | 4 | 4 | 8 | 12 |
| 5 | 401–500 mi | 5 | 5 | 10 | 15 |
Spatial Mode — ceil(radius / 50), max 250mi
| Band | Radius Range | Base | No Flags | + 1 flag | + 2 flags |
|---|---|---|---|---|---|
| 1 | 1–50 mi | 1 | 1 | 2 | 3 |
| 2 | 51–100 mi | 2 | 2 | 4 | 6 |
| 3 | 101–150 mi | 3 | 3 | 6 | 9 |
| 4 | 151–200 mi | 4 | 4 | 8 | 12 |
| 5 | 201–250 mi | 5 | 5 | 10 | 15 |
Band boundaries are inclusive at the top: max=50 = band 1, max=51 = band 2. Decimal values are accepted: max=50.5 = band 2.
Formula Examples
25mi centroid, no flags→ ceil(25/100) × (1 + 0) = 1 credit25mi centroid, timezone→ 1 × (1 + 1) = 2 credits100mi centroid, acs_demographic + timezone→ 1 × (1 + 2) = 3 credits200mi centroid, 4 ACS flags→ 2 × (1 + 4) = 10 credits500mi centroid, 4 ACS + timezone→ 5 × (1 + 5) = 30 credits50mi spatial, no flags→ ceil(50/50) × (1 + 0) = 1 credit100mi spatial, 2 ACS flags→ 2 × (1 + 2) = 6 credits250mi spatial, 4 ACS + timezone→ 5 × (1 + 5) = 30 credits
Credit Estimator
Select an endpoint and configure options to estimate credits assuming the selected enrichments are delivered. Actual usage appears in meta.credits.
Free accounts receive 2,500 daily credits. Subscribers receive their monthly allowance and no daily free credits.
Subscription Plans
| Plan | Monthly Credits | Price |
|---|---|---|
| Free | 2,500 / day | Free |
| Developer | 100,000 | $49/mo |
| Professional | 350,000 | $149/mo |
| Business | 1,500,000 | $499/mo |
Credit Packs
Pre-purchase credits that never expire. Works alongside any plan — free or paid. If you exceed your daily free allowance or monthly subscription, purchased credits kick in automatically.
| Pack | Credits | Price | Per 1,000 |
|---|---|---|---|
| Starter | 25,000 | $19 | $0.76 |
| Standard | 65,000 | $49 | $0.75 |
| Growth | 150,000 | $99 | $0.66 |
| Pro (best value) | 300,000 | $179 | $0.60 |
| Enterprise | 2,000,000 | $799 | $0.40 |
Purchased credits are used only after your free or subscription allowance is exhausted. Need a custom volume? Contact us.
Error Codes
Every error, including per-item failures, includes a public url for next steps. AUTH_MISSING_KEY, AUTH_INVALID_KEY, AUTH_INACTIVE_KEY, AUTH_INACTIVE_ACCOUNT, AUTH_TEST_KEY_RESTRICTED, AUTH_TEST_KEY_RADIUS_EXCEEDED, AUTH_IP_RESTRICTED, AUTH_ORIGIN_RESTRICTED, and CREDIT_INSUFFICIENT link to your account. AUTH_BATCH_REQUIRES_SUBSCRIPTION, AUTH_FREE_TIER_RADIUS_EXCEEDED, and RATE_LIMIT_MINUTE link to pricing. All VALIDATION_* errors, MISSING_VERSION, UNKNOWN_VERSION, BAD_REQUEST, SPATIAL_MODE_DISABLED_BATCH, and NOT_FOUND_COORDS_NO_BOUNDARY link to documentation. Other errors link to the general API page. The missing-key response for a key sent in Authorization: Bearer instead links to authentication documentation.
Whole-request failures use {success:false,request?,error:{code,message,retryable?,url},meta}; results is omitted. Middleware echoes request:{method,path} and marks 429/503/504 as retryable. Braces in messages are placeholders; validation can return additional parameter-specific messages.
| HTTP | Code | Message / variants |
|---|---|---|
| 401 | AUTH_MISSING_KEY | "API key is required. Provide via X-Api-Key header or ?key= query parameter. Get a key at https://www.zip-codes.com/api/account." |
| 401 | AUTH_MISSING_KEY (key in Authorization) | "API key detected in Authorization header. This API uses the X-Api-Key header, not Bearer authentication. Move your key to: X-Api-Key: zc_..." |
| 401 | AUTH_INVALID_KEY | "Invalid API key format. Keys are 32 characters. Manage your keys at https://www.zip-codes.com/api/account." (<16 chars) / "Invalid API key. Manage your keys at https://www.zip-codes.com/api/account." |
| 403 | AUTH_INACTIVE_KEY | "API key has been deactivated." / "API key has expired." |
| 403 | AUTH_INACTIVE_ACCOUNT | "Account has been suspended. Visit https://www.zip-codes.com/api/account for assistance." |
| 403 | AUTH_IP_RESTRICTED / AUTH_ORIGIN_RESTRICTED | "Access denied: IP address not in allowlist." / "Access denied: origin domain not in allowlist." |
| 403 | AUTH_IP_BLOCKED | "Too many invalid authentication attempts. Try again later." |
| 403 | AUTH_BATCH_REQUIRES_SUBSCRIPTION | "Batch endpoints require a paid subscription. Upgrade at https://www.zip-codes.com/api/pricing." |
| 403 | AUTH_FREE_TIER_RADIUS_EXCEEDED | "Free tier is limited to {n}-mile radius in {mode} mode. Upgrade at https://www.zip-codes.com/api/pricing." |
| 402 | CREDIT_INSUFFICIENT | "Insufficient credits. This request costs {n} credits but only {m} available. Buy credits at https://www.zip-codes.com/api/account." (batch: "Insufficient credits. This batch costs ~{n} credits but only {m} available. Buy credits at https://www.zip-codes.com/api/account.") |
| 429 | RATE_LIMIT_MINUTE | "Rate limit exceeded. Please retry after 60 seconds." + meta.rate_limit {limit, window:"minute", retry_after:60} |
| 429 | RATE_LIMIT_MINUTE (unauthenticated flood) | "Too many unauthenticated requests. Retry after 60 seconds." |
| 400 | VALIDATION_MISSING_PARAM | "Missing required parameter: {p}" (alias variant adds ". Found '{alias}' in query — use '{p}' instead.") |
| 400 | VALIDATION_INVALID_PARAM | "Parameter '{p}' cannot be empty." |
| 400 | VALIDATION_INVALID_ZIP / VALIDATION_INVALID_FSA / VALIDATION_INVALID_POSTAL | "Invalid postal code format: '{raw}'." |
| 400 | VALIDATION_INVALID_COORDINATES | "Coordinates out of range: lat must be -90..90, lon must be -180..180." |
| 400 | VALIDATION_INVALID_REQUEST | "Malformed or unreadable request. Check that the request body is valid JSON and all fields have the correct types." |
| 400 | MISSING_VERSION | "API version required. Use /v2/ prefix." |
| 400 | UNKNOWN_VERSION | "Unknown API version. Use /v2/ prefix." (/v3 and later) |
| 500 | INTERNAL_ERROR | "An unexpected error occurred. Please try again later." |
| 403 | AUTH_TEST_KEY_RESTRICTED | Test API keys are restricted to demo codes only. Code '{code}' is not a demo code. (Demo help suffix appended.) |
| 403 | AUTH_TEST_KEY_RADIUS_EXCEEDED | Test API keys are limited to a {n}-mile radius. Requested: {r} miles. (Auto variant: Auto-resolved: {r} miles.) |
| 400 | VALIDATION_BATCH_TOO_LARGE | Batch size {n} exceeds maximum of {max} |
| 400 | VALIDATION_INPUT_TOO_LONG | Address input exceeds maximum length of 500 characters. / Address input exceeds maximum length of 300 characters after cleanup. |
| 400 | VALIDATION_INPUT_TOO_SHORT | Address input is too short to parse (minimum 9 characters after cleanup). |
| 400 | NOT_FOUND_COORDS_NO_BOUNDARY (auto-radius) | No ZIP or FSA boundary found for these coordinates. Auto radius requires coordinates within a known boundary. |
| 400 | SPATIAL_MODE_DISABLED_BATCH | Spatial mode is not available for batch radius searches. Use mode=centroid (default) or make individual /v2/radius requests with mode=spatial. |
| 503 | SERVICE_POOL_EXHAUSTED | Service temporarily at capacity. Please retry in a few seconds. (Retry-After: 5) |
| 503 | SERVICE_UNAVAILABLE | Service temporarily unavailable (default configurable maintenance message; Retry-After: 300). Address variant: Address matching service became unavailable during request. |
| 504 | SERVICE_TIMEOUT | The request timed out. Please try again or reduce the search radius. |
| 405 | METHOD_NOT_ALLOWED | {method} is not supported for {path}. Check the API documentation for allowed methods. |
| 413 | REQUEST_TOO_LARGE | Request body exceeds the maximum allowed size. |
| 415 | UNSUPPORTED_MEDIA_TYPE | Content-Type must be application/json for this endpoint. (A body that is not valid JSON returns 400.) |
Test-key restriction messages append this suffix: Demo US ZIPs: 90210, 10001, 10118, 32504, 00601, 96950, 33139, 60601, 98101, 30301. Demo CA: M5V, K1A, V6B, T2P, H3A, M1R0E9, V5K0A1, K1A0A1, T1X0L3, H1A0A1. Address restrictions read Test API keys are restricted to demo addresses only. Use a real API key to look up any address. followed by a suffix naming demo addresses. The full demo address list (matched ignoring case, commas, periods and extra spaces) is in llms-full.txt; every address example on this page is on it.
Address service-not-ready messages are Address matching service is not ready. Binary files are still loading, please retry shortly. or Address matching service is not ready. Address matching is not enabled on this server.
401 responses include WWW-Authenticate: ApiKey realm="zip-codes-api". Missing-key, invalid-key, and insufficient-credit messages also include the account link in their text. VALIDATION_UNKNOWN_ENRICHMENT is a notice on HTTP 200, not an error.
Per-Item Not Found (HTTP 200)
| Code | Message |
|---|---|
NOT_FOUND_ZIP | ZIP code {zip} not found. |
NOT_FOUND_FSA | FSA {fsa} not found. |
NOT_FOUND_POSTAL | Postal code {postal} not found. |
NOT_FOUND_COORDS_NO_BOUNDARY | No ZIP or postal code boundary found for coordinates {lat},{lon}. |
NOT_FOUND_FROM / NOT_FOUND_TO | Code '{input}' not found in any boundary table |
INSUFFICIENT_INPUT | Not enough information to locate the address. Include a city and state, or a ZIP code. |
AMBIGUOUS | More than one address matches. Add detail such as a unit number, directional or ZIP code. |
NOT_FOUND | The address could not be matched. |
quick-zip coordinate variant: No ZIP or FSA boundary found for coordinates {coordinates}. /zip can also report Coordinates {lat},{lon} landed in FSA {fsa} but no postal code could be resolved. Use /quick-zip for FSA-level lookups.
Postal lookup envelopes keep success:true with {success:false,input:{code},error:{code,message,url}} in results. Codes: NOT_FOUND_ZIP, NOT_FOUND_FSA, NOT_FOUND_POSTAL, NOT_FOUND_COORDS_NO_BOUNDARY, and distance NOT_FOUND_FROM/NOT_FOUND_TO. ZIP: ZIP code {zip} not found.; quick-zip batch: Code {code} not found.; FSA: FSA {fsa} not found.; radius: Center code '{code}' not found.; distance: Code '{input}' not found in any boundary table. Unknown ZIP+4 with a known parent ZIP succeeds with detail:{zip4,valid:false}.
See Address Matching for INSUFFICIENT_INPUT, AMBIGUOUS, and NOT_FOUND, also HTTP 200. Address batch validation messages: Address exceeds maximum length of 500 characters., Address exceeds maximum length of 300 characters after cleanup., Address too short to parse (minimum 9 characters).; item INTERNAL_ERROR: Address matching failed for this item.
Error Response Format
{
"success": false,
"request": {
"method": "GET",
"path": "/v2/quick-zip"
},
"error": {
"code": "AUTH_MISSING_KEY",
"message": "API key is required. Provide via X-Api-Key header or ?key= query parameter. Get a key at https://www.zip-codes.com/api/account.",
"retryable": false,
"url": "https://www.zip-codes.com/api/account"
},
"meta": {
"request_id": "01M3SX2VHP0M9TXH8WFHW7ZM3G",
"version": "2.0.0",
"timing_ms": 0
}
}Rate Limiting
Limits use a one-minute sliding window (six 10-second segments). There are no hourly or daily request limits; daily free credits are a separate allowance.
Allowed authenticated API requests carry X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset (Unix timestamp, now + 60 seconds), and X-RateLimit-Window: minute. These headers are absent on health, docs, swagger, OPTIONS and auth-rejected requests. A 429 adds Retry-After: 60. X-Request-Id is a ULID; X-Api-Version is 2.0.
Limits by Rate Tier
| Tier | Requests per minute |
|---|---|
| Free (default) | 60 |
| Restricted | 20 |
| Developer | 300 |
| Professional | 300 |
| Business | 600 |
| Enterprise | 1800 |
| Demo (per IP) | 5 |
{
"success": false,
"request": {
"method": "GET",
"path": "/v2/quick-zip"
},
"error": {
"code": "RATE_LIMIT_MINUTE",
"message": "Rate limit exceeded. Please retry after 60 seconds.",
"retryable": true,
"url": "https://www.zip-codes.com/api/pricing"
},
"meta": {
"request_id": "01M3SX2VHP0M9TXH8WFHW7ZM3G",
"version": "2.0.0",
"timing_ms": 0,
"rate_limit": {
"limit": 60,
"window": "minute",
"retry_after": 60
}
}
}Supported Countries
| Country | Code Types | Census Boundaries | ACS Data | Political Districts |
|---|---|---|---|---|
| United States | ZIP (5-digit), ZIP+4 (9-digit) | Full (county, tract, block group, place, CBSA) | Full (DP02–DP05) | Congressional, State Senate, State House |
| Canada | FSA (3-char), Postal (6-char) | Statistics Canada census geographies (FSA overlaps or postal pre-assigned areas) | Not available | Federal electoral districts via cd |
HTTP Status Codes
Summary of all HTTP status codes the API can return:
| Code | Meaning | When |
|---|---|---|
| 200 | OK | Processed lookup, including not-found. Check result errors; single address no-match has success:false. Batch item failures also return 200. |
| 400 | Bad Request | Missing or invalid parameters, malformed JSON body, empty batch |
| 401 | Unauthorized | Missing or invalid API key |
| 402 | Payment Required | Insufficient credits or daily limit reached |
| 403 | Forbidden | Inactive key/account, allowlist restriction, or plan/demo restriction |
| 405 | Method Not Allowed | Wrong HTTP method (e.g., PUT on a GET/POST endpoint) |
| 413 | Payload Too Large | Request body exceeds the maximum allowed size |
| 415 | Unsupported Media Type | Unsupported media type; /v2 POST requests are normalized to JSON |
| 429 | Too Many Requests | Rate limit exceeded. Check Retry-After header. |
| 500 | Internal Server Error | Unexpected server error. Include X-Request-Id when reporting. |
| 504 | Gateway Timeout | Request timed out |
| 503 | Service Unavailable | Server maintenance or temporary overload |
Versioning
The API uses path-based versioning. All current endpoints are under /v2/. The version is also returned in API response metadata as meta.version.
- Backward-compatible changes (new fields, new enrichments, new endpoints) are added without a version bump.
- Breaking changes (removed fields, changed response structure) will only occur in a new version (e.g.,
/v3/). - The current version (
v2) is stable and actively maintained. There are no plans to deprecate it. - If a future version is released,
v2will continue to operate for a minimum of 12 months after deprecation notice. - See our Service Level Agreement and Terms of Service for uptime and usage commitments.
OpenAPI Specification
A machine-readable OpenAPI 3.0 specification is auto-generated from the API and always reflects the current endpoints, parameters, and response schemas.
| Resource | URL | Use For |
|---|---|---|
| Postman Workspace | /postman |
One-click fork in Postman — live, versioned collection |
| Swagger UI | /swagger |
Interactive exploration and testing |
| OpenAPI JSON | /swagger/v2/swagger.json |
Generate SDKs, import into Insomnia/Bruno/AI coding tools |
| Download Spec | /v2/openapi.json |
Download the OpenAPI spec file directly |
Changelog
Notable API changes, data updates, and new features.
October 2026
- Boundary families (response shape change): on
/v2/zipand/v2/address, congressional and state legislative districts moved out ofcensus.currentinto their own top-level objects,congressional_district.currentandstate_legislative.current(withupperandlower), and school districts are nowschool_district.current. Canadiancdreturnsfederal_electoral_district.current. Each family is keyed so historical periods can be added besidecurrent. A requested family with nothing found returns{"current": null}. Flags and prices are unchanged. - Congressional primary basis:
congressional_district.current.primarynow includesbasis. On/v2/zipthe primary is the district with the largest share of the ZIP’s area; on/v2/addressit is the USPS ZIP+4 congressional district. - Autocomplete notices:
/v2/suggestnow says “Showing results for” only when the results come from a spelling correction, not on correctly spelled words. - Agent documentation: a redesigned llms.txt and llms-full.txt, an AGENTS.md with credit-safety notes for AI agents, plus
robots.txtandsitemap.xml. - Faster ACS enrichments: ACS profiles on
/v2/zip,/v2/addressand/v2/radiusare now served from in-memory Census data files instead of database queries, so requests with many ACS years and profiles return significantly faster. Every historical year on/v2/radiusnow aggregates as quickly as the current year. - ACS values match Census exactly: every ACS value is now taken directly from the Census Bureau’s published files. Open-ended medians return the Census threshold (for example
250000for “250,000+”), and values Census could not compute returnnullrather than0. - ACS year availability on
/v2/zip: each ACS year block now includespublished. When Census published no data for the ZIP’s ZCTA in a requested year (ZCTAs are redrawn every decade),publishedisfalse, the profiles arenull, and anotesays so. Year blocks are returned newest first.
September 2026
- New address engine:
/v2/addressnow runs on a new matching engine that is faster and more accurate, with the same request and response format. - Address enrichments: coordinates, census, congressional and state legislative boundaries, school districts, and tract ACS profiles for 2022–2024, charged only for the boundary and tract data actually delivered.
- Error next steps: every error includes a public
url;FREE_TIER_LIMIT_CAPPEDnotices link to pricing, and key and credit messages include account links. - Reference corrections: batch formats and limits, HTTP 200 not-found behavior, emitted errors, per-minute rate limits, and credit formulas in this reference now match the API.
August 2026
- Improved address matching:
/v2/addressnow runs on a rebuilt matching engine that resolves more real-world input to a deliverable ZIP+4. Notably better on addresses that were previously hard to place: misspelled or heavily abbreviated street names, missing or incorrect ZIP codes, alternate and historical street names, and apartment or suite designators. - Relocated addresses: an address whose delivery point has been moved by the USPS now returns its current ZIP+4 instead of the retired one.
- No charge for undelivered responses: if a request is cancelled or times out before a response reaches you, no credits are charged.
March 2026
- New endpoint:
/v2/address— Address matching. Parse and validate raw US street addresses against USPS ZIP+4 delivery-point data. Returns standardized address, ZIP+4, parsed components, and delivery metadata. Launched with a 1-credit base; see September 2026 for enrichments.
Frequently Asked Questions
Do you use ZCTA boundaries?
How often is the data updated?
Can I try the API without signing up?
Do you support Canadian postal codes?
M5V) and full postal codes (6 characters like M5V2H1) on postal lookup, radius, distance, and suggest routes; address matching is US-only. Canadian codes work with timezone enrichment, and radius searches automatically include cross-border results. Some enrichments (ACS demographic data, state legislative districts, school districts) are US-only and unavailable for Canadian codes, with a notice and no credit charged; cd returns Canadian federal electoral districts.What is the difference between Quick ZIP and ZIP Details?
/v2/quick-zip) is a lightweight lookup returning core postal code info (city, state, coordinates, code type) with only timezone as an optional enrichment. It is optimized for fast, high-volume lookups like form validation or address autocomplete. ZIP Details (/v2/zip) returns comprehensive data including demographics, business statistics, delivery points, and multiple enrichments (census boundaries, ACS data, congressional districts, school districts, and more).How are credit costs calculated?
base × (1 + timezone + reverse_geocode). Base is 2 for ZIP+4 and 1 for ZIP, FSA, or Postal. Coordinates use the resolved type and add a reverse-geocode layer. ZIP+4 with timezone costs 4; coordinates resolving to ZIP+4 cost 4, or 6 with timezone. Unknown flags have no effect. ZIP Details credits = 1 + billable flags + reverse_geocode. Base is 1 for every code type, including ZIP+4 and Postal. Canadian unavailable flags cost 0 with a notice. Address: 1 + coordinates + delivered boundary/tract tags. Radius: distance-band base × (1 + flags + auto_radius). Distance: 1 per pair. Suggest limit bands: 1/2/3/5 credits. See Credit Costs.What happens if I exceed my rate limit?
Retry-After header indicating how many seconds to wait. Rate limits are enforced on a per-minute window and vary by subscription tier. Rate limit headers (X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset) are present on allowed authenticated API responses; health, docs, swagger, OPTIONS and auth-rejected requests do not carry them.Can I do reverse geocoding with coordinates?
lat,lon in the code parameter (e.g., code=34.1030,-118.4105) on any lookup endpoint. The API uses a two-step spatial search: first, it identifies which ZIP or FSA boundary polygon contains the coordinate (not just the nearest centroid — a point in rural Montana will correctly resolve to the ZIP that actually covers that location, not a distant one). Then, it finds the closest ZIP+4 or full postal code centroid within that parent boundary for precise sub-code resolution. Coordinates add one data layer on quick-zip (× its resolved base), and one credit on /zip. This works in both the US and Canada.What ACS data years are available?
acs_* flags return the most recent year (2024, covering 2020–2024 estimates). To request a specific historical year, append _YYYY to any ACS flag (e.g., include=acs_demographic_2022). You can request multiple years in the same call. Address tract ACS instead supports 2022–2024 with acs_tract_* flags. Field availability varies by year; see the ACS coverage table, as Census added new questions over time. New ACS releases are added annually, typically within weeks of the Census Bureau publication.Is there a batch/bulk endpoint?
Why does one ZIP return multiple counties, tracts, or school districts?
pct_of_zip and pct_of_area fields on each overlap quantify how much of each area is shared.What is the difference between centroid and spatial mode on /radius?
pct_inside is omitted; area_sq_mi is present when available. Spatial uses precise polygon intersection (STBuffer/STIntersects) — slower but includes pct_inside and area_sq_mi, supports up to 250mi, returns US ZIP codes + Canadian FSAs (no full postal codes). Use mode=spatial when you need overlap precision.