Try it Live — No Signup

API Documentation

Complete US & Canadian postal code data with optional demographic, census, and geographic enrichments.

https://api.zip-codes.com
Open in Postman → Download JSON Download OpenAPI Spec

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
Want to try it live? Use our Interactive Playground to make API calls directly from your browser.

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)

Request Header
X-Api-Key: your_api_key

Option 2: Query Parameter

Query String
GET /v2/quick-zip?code=90210&key=your_api_key
The header method is recommended for production use as it keeps your API key out of server logs and browser history.

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.

AspectDetails
Content-TypeAll 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 BodyNon-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.
CompressionThe API supports Brotli and Gzip response compression. Send Accept-Encoding: br or Accept-Encoding: gzip for smaller payloads.
CachingAll API responses include Cache-Control: no-store. Implement your own caching layer if needed.
CORSCORS allows any origin. Per-key IP and Origin allowlists are enforced when configured.
Request IDEvery response includes an X-Request-Id header and meta.request_id field (a ULID). Include this in support requests for faster troubleshooting.
include ParameterControls 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
curl -H "X-Api-Key: YOUR_API_KEY" \
  "https://api.zip-codes.com/v2/quick-zip?code=90210"
Python
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
JavaScript
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:

Response Envelope
{
  "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"
    }
  }
}
FieldTypeDescription
successbooleanWhether the request succeeded
requestobjectEcho of parsed request parameters
resultsarrayArray of result objects (varies by endpoint)
errorobject (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_idstringULID request identifier (also in X-Request-Id header)
meta.versionstringAPI version (currently "2.0.0")
meta.timing_msnumberTotal processing time in milliseconds
meta.creditsobjectCredit usage breakdown for this request
meta.noticesarrayInformational 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:

CodeDescription
INPUT_NORMALIZEDInput was reformatted (e.g., whitespace trimmed, case corrected)
FALLBACK_USEDOn quick-zip and distance only: Canadian postal code not found; FSA-level data returned instead
ENRICHMENT_UNAVAILABLERequested enrichment cannot be delivered (no credit charged for the unavailable flag)
VALIDATION_UNKNOWN_ENRICHMENTUnknown enrichment flags ignored without charge; a notice, not an HTTP 400 error
REVERSE_GEOCODECoordinate was reverse-geocoded to a postal code
BATCH_DUPLICATES_DETECTEDDuplicates 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.

GET /v2/address
POST/v2/address

Parameters

ParameterTypeRequiredDescription
addressstringRequiredRaw 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).
includestringOptionalComma-separated enrichments: coordinates, census, cd, state_leg, school_district, and the tract ACS flags below.
Flexible input: The parser handles a wide range of address formats. You can omit ZIP code, state, or both — the engine resolves the address from city and street alone when unambiguous. However, providing more detail improves match accuracy.

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.

Calculate your cost

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.

FlagWhat it addsPath below dataCredits
coordinatesZIP+4 point, latitude/longitude (6 decimals)location+1 whenever requested, including no match
censusCounties, subdivisions, places, tracts, block groups, metro areas/divisionscensus.current+1 when delivered
cdCongressional districtscongressional_district.current+1 when delivered
state_legState upper/lower legislative districtsstate_legislative.current.upper / lower+1 when delivered
school_districtNCES school districtsschool_district.current+1 when delivered
acs_tract_demographic[_2024|_2023|_2022]DP05 tract profileacs.tract.{current|2023|2022}.demographic+1 per delivered profile/year
acs_tract_social[_2024|_2023|_2022]DP02 tract profileacs.tract.{current|2023|2022}.social+1 per delivered profile/year
acs_tract_economic[_2024|_2023|_2022]DP03 tract profileacs.tract.{current|2023|2022}.economic+1 per delivered profile/year
acs_tract_housing[_2024|_2023|_2022]DP04 tract profileacs.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.

Captured batch response (trimmed)
{
  "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
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"
Open in Playground

Example Response

Captured response excerpt: fields and ACS profiles are trimmed; the original eight-credit charge is retained.

Response
{
  "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

FieldTypeDescription
inputstringThe raw address string you submitted
successbooleantrue if the address was matched
dataobject (optional)Matched address, including requested enrichments when available

Matched Address Data

FieldTypeDescription
formatted_addressstringUSPS-standardized full address with ZIP+4
address_line1stringStreet line (number, directional, street, suffix, secondary)
address_line2stringLast line (city, state, ZIP+4)
address_componentsobjectParsed address components (see table below)
confidencestringMatch confidence: high, medium, or low
detailsobjectUSPS delivery-point metadata
pbsa_indicatorboolean (optional)Included only when true
locationobject (optional)Requested latitude/longitude
censusobject (optional)Requested census geography under current
congressional_districtobject (optional)Requested congressional districts under current
state_legislativeobject (optional)Requested upper/lower state legislative districts under current
school_districtobject (optional)Requested school districts under current, with source and school_year
acsobjectRequested ACS by geography level (tract), then by year (current, 2023, 2022); omitted when no requested profile is delivered

Address Components

FieldTypeDescription
numberstring (optional)House/building number
pre_directionalstring (optional)Prefix directional (e.g., N, SW)
streetstring (optional)Street name
street_pre_typestring (optional)Street pre-type (e.g., AVE in AVE OF THE AMERICAS)
suffixstring (optional)Street suffix (e.g., ST, AVE, BLVD)
post_directionalstring (optional)Postfix directional (e.g., NW)
secondary_typestring (optional)Secondary address type (e.g., APT, STE, UNIT)
secondary_numberstring (optional)Secondary address number (e.g., 4B, 200)
citystringMatched city name
statestringTwo-letter state abbreviation
zipstring5-digit ZIP code
plus4string4-digit ZIP+4 suffix
countrystringCountry code (US)

Details (USPS Metadata)

FieldTypeDescription
record_typeobject (optional)USPS record type with code and description: S (Street), H (Highrise), P (PO Box), F (Firm), G (General Delivery), R (Rural Route)
carrier_routeobject (optional)USPS carrier route with code and description
countyobject (optional)County fips and name
congressional_districtstring (optional)Congressional district number
building_namestring (optional)Building or firm name (when available)
government_buildingobject (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
No match? When no match is found, 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.

GET /v2/suggest
POST /v2/suggest

Parameters

ParameterTypeRequiredDescription
qstringRequiredSearch query (1–200 characters). Case-insensitive.
limitintegerNoMax results to return. Default: 10. Free/test tiers: max 15. Paid tiers: max 500.
includestringNoComma-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.
statestringNoUS state or CA province abbreviation to filter results (e.g., CA, ON).
countrystringNoFilter by country: US or CA. Default: both.
proximitystringNoGeographic 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).
Proximity bias uses source-dependent weighting. Direct coordinates get 55% proximity weight; ZIP/FSA centroids get 50%; state centroids get 30% (gentle nudge). IP-based proximity (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

TypeCountDescriptionType-Specific Fields
zip~42KUS ZIP codescity, classification
place~30KUS Census places (cities, towns, CDPs)fips, geoid, associated_zips
county~3.2KUS counties (includes parishes, boroughs)fips, geoid
cbsa~1KMetropolitan & micropolitan statistical areascbsa_code, geoid, metro_micro
fsa~1.6KCanadian Forward Sortation Areascity, province, postal_code_count
state~67US states/territories & CA provinces (with abbreviation aliases)(none)
school_district—School districtsAvailable entity metadata
ca_postal—Canadian postal codesAvailable postal metadata
uspscity—USPS city namesAvailable city metadata

Credit Cost

Limit RangeCreditsAvailable To
1–151All tiers (including free)
16–502Paid only
51–1503Paid only
151–5005Paid 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.

Calculate your cost

Example Request

cURL
curl -H "X-Api-Key: YOUR_API_KEY" \
  "https://api.zip-codes.com/v2/suggest?q=spring&limit=3"

Example: With proximity bias

cURL
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
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

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

FieldTypeDescription
typestringEntity type: zip, place, county, cbsa, fsa, state, school_district, ca_postal, uspscity
namestringDisplay name (ZIP code number, place name, county name, etc.)
statestringUS state abbreviation (or province for FSA)
countrystringUS or CA
populationintegerPopulation (ACS estimate for US, Census for CA)
locationobject{ lat, lon } — centroid coordinates
bboxobject{ min_lat, max_lat, min_lon, max_lon } — bounding box (omitted for ZIPs)
fipsstringFIPS code (places, counties only)
geoidstringCensus GEOID (places, counties, CBSAs)
associated_zipsarrayZIP codes within a place (places only)
cbsa_codestringCBSA code (CBSAs only)
metro_microstringMetropolitan or Micropolitan (CBSAs only)
citystringPrimary city name (ZIPs and FSAs only)
classificationstringZIP type: Standard, PO Box, Military, Unique (ZIPs only)
provincestringCA 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.

GET /v2/quick-zip
POST /v2/quick-zip

Parameters

ParameterTypeRequiredDescription
codestringRequiredZIP code, ZIP+4, FSA, Canadian postal code, or coordinates (lat,lon)
includestringOptionalComma-separated enrichment flags. Only timezone is supported on this endpoint.

Supported Code Types

TypeFormatExampleCountryBase Cost
ZIP5 digits90210US1 credit
ZIP+49 digits (with or without dash)90210-1234US2 credits
FSA3 alphanumeric (A1A)M5VCA1 credit
Postal6 alphanumeric (A1A1A1)M5V2H1CA1 credit
Coordinateslat,lon (decimal degrees)34.1030,-118.4105US + CA2 or 4 credits (before timezone)
Coordinate credits perform a reverse geocode to find the nearest postal code. The extra credit cost reflects the spatial search required. Pass coordinates directly in the code parameter as lat,lon.

Available Enrichments

FlagAdds to ResponseCostAvailability
timezoneIANA 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.

Calculate your cost

Response Fields

FieldTypeDescription
countrystring"US" or "CA"
codestringThe postal code
code_typestringZIP, FSA, or Postal
parent_codestring (optional)Parent 5-digit ZIP or FSA (omitted for base codes)
citystringPrimary city name
state / state_namestringState/province abbreviation and full name
state_fipsstring (optional)2-digit state FIPS code (US only)
county / county_fipsstring (optional)County name and FIPS code (US only)
multi_countyboolean (optional)Whether ZIP spans multiple counties (US only)
classificationstring (optional)ZIP type code (US only)
classification_namestring (optional)ZIP type name: General, PO Box, Military, Unique
municipalitystring (optional)Municipality name (where applicable)
locationobject{"lat": ..., "lon": ...}
detailobject (optional)Street-level detail for ZIP+4 / CA postal codes
timezoneobject (optional)Present when include=timezone
Canadian postal fallback: If a full Canadian postal code is not found, the API automatically falls back to FSA-level data and includes a 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:

FieldTypeDescription
zip4stringThe 4-digit ZIP+4 suffix
record_typestringAddress record type (e.g., S = Street, P = PO Box, H = Highrise, F = Firm)
carrier_routestringUSPS carrier route code

Street Detail Fields

Street-level address range information within the detail.street object:

FieldTypeDescription
addr_lowstringLow end of primary address range
addr_highstringHigh end of primary address range
prefixstringStreet name prefix directional (e.g., N, SW)
namestringStreet name
suffixstringStreet suffix (e.g., St, Ave, Blvd)
postfixstringStreet name postfix directional
odd_evenstringAddress range parity: O (odd), E (even), B (both)
sec_addr_abbrstringSecondary address abbreviation (e.g., APT, STE, UNIT)
sec_addr_lowstringLow end of secondary address range
sec_addr_highstringHigh end of secondary address range
sec_addr_odd_evenstringSecondary address range parity: O, E, or B
building_namestringBuilding or firm name
addressstringFormatted full address line

Example Request

cURL
curl -H "X-Api-Key: YOUR_API_KEY" \
  "https://api.zip-codes.com/v2/quick-zip?code=90210&include=timezone"
Open in Playground

Example Response

Response — US ZIP
{
  "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"
  }
}
Response — Canadian FSA
{
  "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"
  }
}
Response — Not Found
{
  "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.

GET /v2/zip
POST /v2/zip

Parameters

ParameterTypeRequiredDescription
codestringRequiredUS ZIP code, Canadian postal code, or coordinates (lat,lon)
includestringOptionalComma-separated enrichment flags (see Data Enrichments)

Available Enrichments

FlagAdds to ResponseCostAvailability
timezoneIANA timezone name, UTC offsets, DST info. Multi-zone ZIPs return array with % coverage.+1US + CA
censusCounty, county subdivision, place, tract, block group, CBSA overlaps with % coverage+1US + CA
cdCongressional districts (US) / federal electoral districts (CA) with % coverage+1US + CA
state_legState senate (upper) and house (lower) legislative district overlaps+1US only
school_districtSchool districts (NCES) with office address, grade range, locale, area overlap+1US only
acs_demographicPopulation, sex, age distribution, race, ethnicity, citizenship (DP05 — 108 fields)+1US only
acs_socialHouseholds, education, language, ancestry, marital status, computers/internet (DP02 — 154 fields)+1US only
acs_economicEmployment, income, poverty, occupation, industry, health insurance, commute (DP03 — 137 fields)+1US only
acs_housingHousing units, occupancy, tenure, home value, rent, utilities, structure age (DP04 — 143 fields)+1US 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 eachUS only
demographicsPopulation, race, age, households, income, and business establishment counts+1US only
medicareMedicare CBSA code/name/type, rating area ID, SSA state/county code+1US only
Canadian availability: Requesting US-only enrichments for Canadian codes omits unavailable model fields (explicit census/ACS nulls may remain) and adds an 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.

Calculate your cost

Example Request

cURL
curl -H "X-Api-Key: YOUR_API_KEY" \
  "https://api.zip-codes.com/v2/zip?code=90210&include=timezone,demographics"
Open in Playground

Example Response

Response — Base + Timezone + Demographics
{
  "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)

FieldTypeDescription
countrystring"US" or "CA"
codestringThe postal code
code_typestringZIP, FSA, or Postal
parent_codestring (optional)Parent 5-digit ZIP (for ZIP+4 queries) or parent FSA (for CA postal queries). Omitted for base codes.
citystringPrimary city name
state / state_namestringState/province abbreviation and full name
state_fipsstring (optional)2-digit state FIPS code (US only)
county / county_fipsstringCounty name and FIPS code (US only)
multi_countyboolean (optional)Whether the ZIP spans multiple counties (US only)
municipalitystring (optional)Municipality name (where applicable)
locationobject{"lat": 34.10, "lon": -118.41}
area_codesstring[] (optional)Telephone area codes overlapping this postal code
elevationobject (optional){"ft": 719, "m": 219} — centroid elevation in feet and meters
metroobject (optional)MSA/CBSA statistical area info (US only, see sub-fields below)
zip_infoobject (optional)ZIP classification, facility code, land/water area, delivery points (US only)
postal_infoobject (optional)Canadian postal metadata: record type, address type, FSA stats (CA only)
city_aliasesarray (optional)Alternative city names with mailing status and intro date
detailobject (optional)ZIP+4 / CA postal street-level overlay (omitted for 5-digit ZIP / FSA queries)

metro Sub-Fields (US only)

FieldTypeDescription
regionstring (optional)Census region (e.g., West, Northeast)
divisionstring (optional)Census division (e.g., Pacific, Middle Atlantic)
csa / csa_namestring (optional)Combined Statistical Area code and name
msa / msa_namestring (optional)Metropolitan Statistical Area code and name
pmsa / pmsa_namestring (optional)Primary MSA code and name (where applicable)

postal_info Sub-Fields (CA only)

FieldTypeDescription
record_typestringRecord type code
address_typestringAddress type classification
fsastringParent FSA (3-character)
delivery_postal_codestringDelivery postal code
fsa_populationnumberFSA population
fsa_dwellingsnumberTotal dwellings in FSA
fsa_dwellings_occupiednumberOccupied dwellings in FSA
fsa_postal_code_countnumberNumber 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.

GET /v2/radius
POST /v2/radius

Parameters

ParameterTypeRequiredDescription
codestringRequiredCenter point — US ZIP (5-digit), ZIP+4, Canadian FSA, Canadian Postal Code, or lat,lon coordinates (e.g. 41.878,-87.629)
maxnumber or stringRequiredMaximum 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.
minnumberOptionalMinimum radius in miles for donut search: nonnegative and less than max. Default: 0
includestringOptionalComma-separated enrichment flags (see table below)
modestringOptionalcentroid (default) — fast haversine on centroids, returns US ZIP + CA Postal. spatial — precise boundary analysis with pct_inside, returns US ZIP + CA FSA.
limitnumberOptionalPositive integer maximum results; truncation reports summary.total_available. Centroid mode caps at 10,000 with RESULTS_CAPPED.

Available Enrichments

FlagAdds to ResponseCostAvailability
timezoneIANA timezone name, UTC offsets, DST abbreviations for each result+1 data layer (× base)US + CA
acs_demographicPopulation-weighted aggregate: population, sex, age, race, ethnicity (DP05)+1 data layer (× base)US only
acs_socialPopulation-weighted aggregate: households, education, language, ancestry (DP02)+1 data layer (× base)US only
acs_economicPopulation-weighted aggregate: employment, income, poverty, commute (DP03)+1 data layer (× base)US only
acs_housingPopulation-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
Territory enrichments not available on /radius. Boundary enrichments (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.
How Radius Credits Are Calculated

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.

Calculate your cost

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.

ModeBased OnRangeBest For
autoPopulation density: 341 ÷ density0.423–150 milesGeneral-purpose searches scaled to urbanity
auto-commuteACS commuting patterns: mean travel time × transport-weighted speed × 1.53–100 milesService-area and labor-market analysis
Fallback: If commute data is unavailable for a ZIP (no ACS coverage), 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
curl -H "X-Api-Key: YOUR_API_KEY" \
  "https://api.zip-codes.com/v2/radius?code=48226&max=25&include=timezone"
Open in Playground

Example Response

Response — 25mi Radius
{
  "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

FieldTypeDescription
search.center.codestringResolved center postal code
search.center.code_typestringZIP, FSA, or Postal
search.center.citystringCenter city name
search.center.statestringCenter state/province abbreviation
search.center.locationobject{"lat": ..., "lon": ...} — center coordinates
search.maxnumberResolved maximum radius in miles (numeric value, even when auto was requested)
search.minnumberMinimum radius in miles (donut inner ring)
search.modestring"centroid" or "spatial"
search.auto_modestring (optional)"density" when max=auto, "commute" when max=auto-commute, omitted for numeric radius

Match Fields

FieldTypeDescription
countrystring"US" or "CA"
codestringPostal code
code_typestringZIP, FSA, or Postal
citystringCity name
statestringState/province abbreviation
countystring (optional)County name (US only)
county_fipsstring (optional)County FIPS code (US only)
classificationstring (optional)ZIP type code (US only, e.g., G, P, M, U)
classification_namestring (optional)ZIP type name (e.g., General, PO Box, Military, Unique)
locationobject{"lat": ..., "lon": ...}
distance_milesnumberDistance from center point in miles
pct_insidenumber (optional)Percentage of the postal code area inside the search radius (spatial mode only; omitted in centroid mode)
area_sq_minumber (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.

GET /v2/distance
POST /v2/distance

Parameters

ParameterTypeRequiredDescription
fromstringRequiredOrigin point. Accepts: US ZIP (90210), ZIP+4 (90210-1234), Canadian FSA (M5V), Canadian postal code (M5V2H1), or lat,lon coordinates (34.103,-118.410)
tostringRequiredDestination point. Accepts: US ZIP (90210), ZIP+4 (90210-1234), Canadian FSA (M5V), Canadian postal code (M5V2H1), or lat,lon coordinates (40.758,-73.986)
You can mix any input types. For example: from=90210-1234&to=40.758,-73.9855

Credit Cost

Fixed 1 credit per pair. Timezone is always included at no extra cost.

Calculate your cost

Example Request

cURL
curl -H "X-Api-Key: YOUR_API_KEY" \
  "https://api.zip-codes.com/v2/distance?from=90210&to=10001"
Open in Playground

Example Response

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.

GET /v2/health

Three-state health: healthy (normal), degraded (DB latency >500ms), unhealthy (DB unreachable, returns HTTP 503).

Response
{
  "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).

Subscription required: Batch endpoints require a paid subscription (Developer tier or higher). Free tier accounts receive an 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

Batch 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
  }
}
Duplicate detection: Duplicate items are processed and billed individually, with a BATCH_DUPLICATES_DETECTED notice. Credits are reserved up front, unused credits are refunded, and disconnect/timeout refunds all credits.

Batch Endpoints

EndpointURLBody 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

Request
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:

Partial Failure Response
{
  "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.

About This Data

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.

About This Data

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.

FlagDescriptionEndpointsAdded costAvailability
timezoneIANA timezone with DST infoQuick ZIP, ZIP, RadiusOne data layer (× endpoint base)US + CA
censusCensus boundary overlapsZIP, Address+1US + CA
cdCongressional districts (US), federal electoral districts (CA /zip)ZIP, Address (US)+1US + CA
state_legState legislature districtsZIP, Address+1US only
school_districtSchool district boundaries (NCES)ZIP, Address+1US only
acs_demographicPopulation, age, sex, race (DP05)ZIP, RadiusOne data layer (× endpoint base)US only
acs_socialHouseholds, education, language (DP02)ZIP, RadiusOne data layer (× endpoint base)US only
acs_economicEmployment, income, industry (DP03)ZIP, RadiusOne data layer (× endpoint base)US only
acs_housingHousing units, occupancy, value (DP04)ZIP, RadiusOne 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, RadiusOne layer per tag (× endpoint base)US only
demographicsPopulation, race, age, households, income, businessZIP+1US only
medicareMedicare CBSA, rating area, SSA codeZIP+1US only
coordinatesZIP+4 point, latitude/longitude (6 decimals)Address+1 requestedUS
acs_tract_{demographic|social|economic|housing}[_2024|_2023|_2022]Containing-tract ACS; no suffix = 2024Address+1 per delivered tagUS
Canadian availability: Requesting US-only enrichments for Canadian codes omits unavailable model fields (explicit census/ACS nulls may remain) and adds an 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

FieldTypeDescription
sourcestringData source attribution
iana_namestringIANA timezone identifier (e.g., America/Los_Angeles)
namestringDisplay name (e.g., Pacific Standard Time)
abbreviationstringStandard time abbreviation (e.g., PST)
abbreviation_dststringDaylight saving abbreviation (e.g., PDT)
utc_offsetnumberStandard UTC offset in hours (e.g., -8)
utc_offset_dstnumberDST UTC offset in hours (e.g., -7)
observes_dstbooleanWhether this timezone observes daylight saving time
pct_of_zipnumber/v2/zip only — percentage of ZIP area in this timezone
On /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.
Timezone Object
{
  "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.

About This Data

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
GeographyFIPS LengthExample
State2 digits06 (California)
County5 digits06037 (Los Angeles Co.)
County Subdivision10 digits0603765000
Place7 digits0644000 (Los Angeles city)
Census Tract11 digits06037264000
Block Group12 digits060372640001
Congressional District4 digits0634

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

BoundaryDescription
countyCounty boundaries with FIPS codes
county_subdivisionCounty subdivisions (CCDs, MCDs)
placeCensus-designated places and incorporated cities
tractCensus tracts with GEOID
block_groupCensus block groups
metro_micro_cbsa_statistical_areaMetropolitan/Micropolitan statistical areas
metropolitan_cbsa_divisionMetro 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 Boundary Object (excerpt)
{
  "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)

FieldTypeDescription
congressnumberCongressional session number (e.g., 119)
primary.geoidstringGEOID of the primary (highest overlap) district
primary.statestringState abbreviation
primary.district_numberintegerDistrict number
districts[]arrayAll 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 Object
{
  "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

FieldTypeDescription
legislative_yearintegerLegislative year of the district plan (e.g., 2024)
upper[]arrayState Senate district overlaps
lower[]arrayState 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 Legislature Object
{
  "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

About This Data

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

FieldTypeDescription
leaidstringNCES Local Education Agency ID
namestringDistrict name
typestringDistrict type: unified, elementary, secondary, administrative, other
grade_low / grade_highstringGrade range served (e.g., PK to 12)
officeobjectOffice address, city, state, ZIP, county, lat/lon
localeobjectLocale classification code and description (city/suburb/town/rural)
pct_of_zip / pct_of_areanumberOverlap percentages
land_area_sq_minumberDistrict land area
School District Object
{
  "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.

Data freshness: Every ACS response includes a 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)

SectionKey Fields
Sex and AgeTotal population, male/female counts, age brackets (under 5 through 85+), median age
RaceWhite, Black, American Indian, Asian, Pacific Islander, other, two or more races
Hispanic or Latino and RaceHispanic/Latino totals, breakdown by race within Hispanic/non-Hispanic
Citizen, Voting Age PopulationCitizens 18+, total voting age population
Total Housing UnitsHousing unit count

acs_social — DP02 (154 fields)

SectionKey Fields
Households by TypeTotal households, family/nonfamily, married-couple, single-parent, average size
RelationshipHouseholder, spouse, child, other relatives, nonrelatives, unmarried partner
Marital StatusNever married, now married, separated, widowed, divorced
FertilityWomen 15–50 who had a birth in the past 12 months
GrandparentsGrandparents living with grandchildren, responsible for care
School EnrollmentNursery through graduate school, public/private breakdown
Educational AttainmentLess than 9th grade through doctorate, high school+, bachelor's+
Veteran StatusCivilian veterans 18+
Disability StatusCivilian noninstitutionalized population with a disability
Residence 1 Year AgoSame house, different house (same county, state, abroad)
Place of BirthNative vs. foreign-born, state of birth, world region
Language Spoken at HomeEnglish only, Spanish, Asian/Pacific Island, other, English proficiency
AncestryTop ancestral origins reported
Computers and Internet UseHouseholds with computer, broadband, smartphone, no internet

acs_economic — DP03 (137 fields)

SectionKey Fields
Employment StatusLabor force, employed, unemployed, unemployment rate, armed forces
Commuting to WorkDrove alone, carpooled, public transit, walked, work from home, mean travel time
OccupationManagement, service, sales, construction, production, transportation
IndustryAgriculture, manufacturing, retail, healthcare, education, finance, tech
Class of WorkerPrivate wage, government, self-employed, unpaid family
Income and BenefitsMedian household/family income, per capita, with earnings/Social Security/retirement
Health Insurance CoverageWith/without coverage, private, public, by employment status
Poverty LevelFamilies and people below poverty, by age, family type, education

acs_housing — DP04 (143 fields)

SectionKey Fields
Housing OccupancyTotal units, occupied, vacant, homeowner vacancy rate, rental vacancy rate
Units in StructureSingle-family detached/attached, 2–4 units, 5–19, 20+, mobile home, boat/RV
Year Structure Built2020+, 2010–2019, 2000–2009, through 1939 or earlier
Rooms / Bedrooms1 room through 9+, median rooms, bedroom count distribution
Housing TenureOwner-occupied, renter-occupied, average household size by tenure
Year Householder Moved In2021+, 2018–2020, 2010–2017, through 1989 or earlier
Vehicles AvailableNo vehicle, 1, 2, 3+ vehicles
House Heating FuelGas, electric, fuel oil, coal, wood, solar, other, no fuel
Selected CharacteristicsLacking plumbing, lacking kitchen, no telephone service
ValueOwner-occupied home value distribution, median value
Mortgage StatusWith/without mortgage, second mortgage, home equity loan
Monthly Owner CostsCost distribution, median, as percentage of household income
Gross RentRent 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.

YearACS 5-Year EstimatesFieldsCoverage
2024 (current)2020–202452897.4%
20232019–2023528100%
20222018–202252198.7%
20212017–202151898.1%
20202016–202051898.1%
20192015–201951797.9%
20182014–201848692.0%
20172013–201748391.5%
20162012–201646387.7%
20152011–201546387.7%
20142010–201444183.5%
20132009–201344183.5%
20122008–201239474.6%
20112007–201139474.6%
Coverage is relative to the 528-field canonical maximum. Earlier years have fewer fields because Census added new questions over time (e.g., cohabiting couples in 2019, tribal detail in 2022). Fields not available for a given year return null. 394 “universal” fields are available across all 14 years.
On /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 Data Structure
{
  "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

FieldTypeDescription
population
population.totalnumberTotal population (Census 2020)
population.estimatenumberCurrent population estimate
population.malenumberMale population
population.femalenumberFemale population
race
race.whitenumberWhite population
race.blacknumberBlack or African American population
race.hispanicnumberHispanic or Latino population
race.asiannumberAsian population
race.american_indiannumberAmerican Indian / Alaska Native population
race.hawaiian_pacific_islandernumberNative Hawaiian / Pacific Islander population
race.othernumberOther race population
age
age.mediannumberMedian age
age.median_malenumberMedian age (male)
age.median_femalenumberMedian age (female)
households
households.totalnumberTotal households
households.persons_per_householdnumberAverage persons per household
households.average_family_sizenumberAverage family size
households.median_incomenumberMedian household income (USD)
households.average_home_valuenumberAverage home value (USD)
business
business.establishmentsnumberNumber of business establishments
business.employeesnumberTotal employees
business.payroll_q1numberFirst quarter payroll (full USD)
business.payroll_annualnumberAnnual payroll (full USD)
business.employment_flagstringEmployment range flag when exact count is suppressed
This enrichment provides a compact demographic summary from Census and IRS data. For detailed survey-based estimates with margins of error, use the ACS enrichments.
Demographics Object
{
  "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

FieldTypeDescription
cbsa_codestringCore Based Statistical Area code used by CMS for Medicare payment
cbsa_namestringCBSA name (e.g., “Los Angeles-Long Beach-Anaheim, CA”)
cbsa_typestringMetropolitan or Micropolitan (omitted if rural)
rating_area_idstringACA marketplace rating area identifier
ssa_state_county_codestringSSA state/county code used in Medicare administrative systems
multi_county_noticestringPresent only when a ZIP spans multiple counties with different Medicare assignments
Medicare Object
{
  "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

How Credits Work

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.

EndpointBase Cost+ EnrichmentsPlain English
Address1 per request+ coordinates requested + delivered boundary/tract tags1 base; no match adds requested coordinates
Quick ZIP1 (ZIP/FSA/Postal), 2 (ZIP+4)× (1 + timezone + reverse_geocode)ZIP+4 + timezone = 4; coordinates to ZIP+4 + timezone = 6
ZIP Details1 (all code types)+ billable flags + reverse_geocodeZIP+4 + timezone = 2
Distance1 per pairtimezone freeAlways 1 credit
Suggest1–5 (by limit)N/A1 credit for ≤15 results
Radius1–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)
BatchPer-item costSame as singleSum of individual items
Health0N/AAlways 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
BandRadius RangeBaseNo Flags+ 1 flag+ 2 flags
11–100 mi1123
2101–200 mi2246
3201–300 mi3369
4301–400 mi44812
5401–500 mi551015
Spatial Mode — ceil(radius / 50), max 250mi
BandRadius RangeBaseNo Flags+ 1 flag+ 2 flags
11–50 mi1123
251–100 mi2246
3101–150 mi3369
4151–200 mi44812
5201–250 mi551015

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 credit
  • 25mi centroid, timezone → 1 × (1 + 1) = 2 credits
  • 100mi centroid, acs_demographic + timezone → 1 × (1 + 2) = 3 credits
  • 200mi centroid, 4 ACS flags → 2 × (1 + 4) = 10 credits
  • 500mi centroid, 4 ACS + timezone → 5 × (1 + 5) = 30 credits
  • 50mi spatial, no flags → ceil(50/50) × (1 + 0) = 1 credit
  • 100mi spatial, 2 ACS flags → 2 × (1 + 2) = 6 credits
  • 250mi 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.

Your Estimate
Base credit1

Total per call1 credit
calls/day = 100 credits/day

Free accounts receive 2,500 daily credits. Subscribers receive their monthly allowance and no daily free credits.

Subscription Plans

PlanMonthly CreditsPrice
Free2,500 / dayFree
Developer100,000$49/mo
Professional350,000$149/mo
Business1,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.

PackCreditsPricePer 1,000
Starter25,000$19$0.76
Standard65,000$49$0.75
Growth150,000$99$0.66
Pro (best value)300,000$179$0.60
Enterprise2,000,000$799$0.40

Purchased credits are used only after your free or subscription allowance is exhausted. Need a custom volume? Contact us.

Format validation failures are free. If input doesn't match a recognized format (e.g., not a 5-digit ZIP, 9-digit ZIP+4, or Canadian ANA NAN pattern), no credit is charged (HTTP 400). If the format is valid but the code doesn't exist in our database, 1 credit is charged (2 for quick-zip coordinate input). Address no-match costs 1, plus 1 if coordinates was requested.

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.

HTTPCodeMessage / variants
401AUTH_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."
401AUTH_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_..."
401AUTH_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."
403AUTH_INACTIVE_KEY"API key has been deactivated." / "API key has expired."
403AUTH_INACTIVE_ACCOUNT"Account has been suspended. Visit https://www.zip-codes.com/api/account for assistance."
403AUTH_IP_RESTRICTED / AUTH_ORIGIN_RESTRICTED"Access denied: IP address not in allowlist." / "Access denied: origin domain not in allowlist."
403AUTH_IP_BLOCKED"Too many invalid authentication attempts. Try again later."
403AUTH_BATCH_REQUIRES_SUBSCRIPTION"Batch endpoints require a paid subscription. Upgrade at https://www.zip-codes.com/api/pricing."
403AUTH_FREE_TIER_RADIUS_EXCEEDED"Free tier is limited to {n}-mile radius in {mode} mode. Upgrade at https://www.zip-codes.com/api/pricing."
402CREDIT_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.")
429RATE_LIMIT_MINUTE"Rate limit exceeded. Please retry after 60 seconds." + meta.rate_limit {limit, window:"minute", retry_after:60}
429RATE_LIMIT_MINUTE (unauthenticated flood)"Too many unauthenticated requests. Retry after 60 seconds."
400VALIDATION_MISSING_PARAM"Missing required parameter: {p}" (alias variant adds ". Found '{alias}' in query — use '{p}' instead.")
400VALIDATION_INVALID_PARAM"Parameter '{p}' cannot be empty."
400VALIDATION_INVALID_ZIP / VALIDATION_INVALID_FSA / VALIDATION_INVALID_POSTAL"Invalid postal code format: '{raw}'."
400VALIDATION_INVALID_COORDINATES"Coordinates out of range: lat must be -90..90, lon must be -180..180."
400VALIDATION_INVALID_REQUEST"Malformed or unreadable request. Check that the request body is valid JSON and all fields have the correct types."
400MISSING_VERSION"API version required. Use /v2/ prefix."
400UNKNOWN_VERSION"Unknown API version. Use /v2/ prefix." (/v3 and later)
500INTERNAL_ERROR"An unexpected error occurred. Please try again later."
403AUTH_TEST_KEY_RESTRICTEDTest API keys are restricted to demo codes only. Code '{code}' is not a demo code. (Demo help suffix appended.)
403AUTH_TEST_KEY_RADIUS_EXCEEDEDTest API keys are limited to a {n}-mile radius. Requested: {r} miles. (Auto variant: Auto-resolved: {r} miles.)
400VALIDATION_BATCH_TOO_LARGEBatch size {n} exceeds maximum of {max}
400VALIDATION_INPUT_TOO_LONGAddress input exceeds maximum length of 500 characters. / Address input exceeds maximum length of 300 characters after cleanup.
400VALIDATION_INPUT_TOO_SHORTAddress input is too short to parse (minimum 9 characters after cleanup).
400NOT_FOUND_COORDS_NO_BOUNDARY (auto-radius)No ZIP or FSA boundary found for these coordinates. Auto radius requires coordinates within a known boundary.
400SPATIAL_MODE_DISABLED_BATCHSpatial mode is not available for batch radius searches. Use mode=centroid (default) or make individual /v2/radius requests with mode=spatial.
503SERVICE_POOL_EXHAUSTEDService temporarily at capacity. Please retry in a few seconds. (Retry-After: 5)
503SERVICE_UNAVAILABLEService temporarily unavailable (default configurable maintenance message; Retry-After: 300). Address variant: Address matching service became unavailable during request.
504SERVICE_TIMEOUTThe request timed out. Please try again or reduce the search radius.
405METHOD_NOT_ALLOWED{method} is not supported for {path}. Check the API documentation for allowed methods.
413REQUEST_TOO_LARGERequest body exceeds the maximum allowed size.
415UNSUPPORTED_MEDIA_TYPEContent-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)

CodeMessage
NOT_FOUND_ZIPZIP code {zip} not found.
NOT_FOUND_FSAFSA {fsa} not found.
NOT_FOUND_POSTALPostal code {postal} not found.
NOT_FOUND_COORDS_NO_BOUNDARYNo ZIP or postal code boundary found for coordinates {lat},{lon}.
NOT_FOUND_FROM / NOT_FOUND_TOCode '{input}' not found in any boundary table
INSUFFICIENT_INPUTNot enough information to locate the address. Include a city and state, or a ZIP code.
AMBIGUOUSMore than one address matches. Add detail such as a unit number, directional or ZIP code.
NOT_FOUNDThe 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

401 Response
{
  "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

TierRequests per minute
Free (default)60
Restricted20
Developer300
Professional300
Business600
Enterprise1800
Demo (per IP)5
429 Response (Free tier)
{
  "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

CountryCode TypesCensus BoundariesACS DataPolitical 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:

CodeMeaningWhen
200OKProcessed lookup, including not-found. Check result errors; single address no-match has success:false. Batch item failures also return 200.
400Bad RequestMissing or invalid parameters, malformed JSON body, empty batch
401UnauthorizedMissing or invalid API key
402Payment RequiredInsufficient credits or daily limit reached
403ForbiddenInactive key/account, allowlist restriction, or plan/demo restriction
405Method Not AllowedWrong HTTP method (e.g., PUT on a GET/POST endpoint)
413Payload Too LargeRequest body exceeds the maximum allowed size
415Unsupported Media TypeUnsupported media type; /v2 POST requests are normalized to JSON
429Too Many RequestsRate limit exceeded. Check Retry-After header.
500Internal Server ErrorUnexpected server error. Include X-Request-Id when reporting.
504Gateway TimeoutRequest timed out
503Service UnavailableServer 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, v2 will 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.

ResourceURLUse 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
Using Postman? Click Open in Postman to land directly in our live workspace — fork the collection into your own workspace in one click, with every endpoint, parameter, and example pre-configured. If you use a different tool (Insomnia, Bruno, an AI coding assistant), import the OpenAPI spec URL above instead.

Changelog

Notable API changes, data updates, and new features.

October 2026

  • Boundary families (response shape change): on /v2/zip and /v2/address, congressional and state legislative districts moved out of census.current into their own top-level objects, congressional_district.current and state_legislative.current (with upper and lower), and school districts are now school_district.current. Canadian cd returns federal_electoral_district.current. Each family is keyed so historical periods can be added beside current. A requested family with nothing found returns {"current": null}. Flags and prices are unchanged.
  • Congressional primary basis: congressional_district.current.primary now includes basis. On /v2/zip the primary is the district with the largest share of the ZIP’s area; on /v2/address it is the USPS ZIP+4 congressional district.
  • Autocomplete notices: /v2/suggest now 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.txt and sitemap.xml.
  • Faster ACS enrichments: ACS profiles on /v2/zip, /v2/address and /v2/radius are 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/radius now 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 250000 for “250,000+”), and values Census could not compute return null rather than 0.
  • ACS year availability on /v2/zip: each ACS year block now includes published. When Census published no data for the ZIP’s ZCTA in a requested year (ZCTAs are redrawn every decade), published is false, the profiles are null, and a note says so. Year blocks are returned newest first.

September 2026

  • New address engine: /v2/address now 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_CAPPED notices 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/address now 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?
No. Our ZIP code boundaries are a commercial product built from USPS carrier routes and delivery data. Boundaries are updated quarterly and reflect current USPS delivery routes, not Census-derived approximations. ZCTAs (ZIP Code Tabulation Areas) are Census Bureau constructs used only for geographic joins when mapping ACS demographic data to ZIP codes. The boundaries you see in our API are real, current ZIP code boundaries.
How often is the data updated?
Different data layers update on different schedules: US ZIP base data is updated monthly, ZIP boundaries quarterly, ACS census data annually (each December/January release), Canadian postal codes monthly, and school districts yearly. When data is updated, it is reflected in the API without any action needed on your part.
Can I try the API without signing up?
Yes. Our interactive demo let's you see the functionality of the API. Get a free API Key for 2,500 credits/day, no credit card, no committment. Finally, our Interactive Playground lets you work with all functionality of the API with full access to every endpoint and enrichment so you can evaluate the API before committing.
Do you support Canadian postal codes?
Yes. We support both FSA (Forward Sortation Area, 3 characters like 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?
Quick ZIP (/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?
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. 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?
You will receive an HTTP 429 response with a 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?
Yes. Pass coordinates as 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?
On /zip and /radius we offer 14 years of ACS 5-Year Estimates (2011–2024) across all four profiles: Demographic (DP05), Social (DP02), Economic (DP03), and Housing (DP04). The default 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?
Yes: Quick ZIP, ZIP Details, Radius, Distance (100 items each), and Address (250). Paid subscription required. There is no suggest batch. Duplicates are processed and billed individually. See Batch Requests for body formats.
Why does one ZIP return multiple counties, tracts, or school districts?
ZIP code boundaries and census/administrative boundaries are drawn independently — they almost never align. A single ZIP frequently spans multiple counties (even states), dozens of census tracts, and several school districts. The 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?
Centroid (default) uses haversine distance between centroids — fast, supports up to 500mi, returns US ZIP codes + full Canadian postal codes. 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.