Every ZIP code in the United States, with weather, radar, trivia and the numbers behind it. Five digits since 1963!

ZIP stands for Zone Improvement Plan. The codes went live on July 1, 1963.The lowest ZIP code is 00501 — the IRS in Holtsville, New York.The highest ZIP code is 99950, in Ketchikan, Alaska.Type 07734 into a calculator and turn it upside down: hELLO. It is Keansburg, New Jersey.12345 belongs to one company: General Electric in Schenectady, New York.The first digit is a region: 0 is New England and New Jersey, 9 is the West Coast, Alaska and Hawaii.Mr. ZIP, the cartoon mailman, was the mascot that sold the idea to America.ZIP+4 arrived in 1983 and can narrow a ZIP down to one side of one block.A ZIP code is a mail route, not a place: plenty of them cross county and even state lines.Play ZIP Hunt: guess the secret ZIP code of the day in six tries.
zipcodes.pro — API/DISTANCE

ZIP code distance API

GET /v1/distance?from=&to= returns the distance between two ZIP codes in miles and kilometres, with the city, state and coordinates of each end. For many pairs at once, the radius endpoint and bulk lookup return coordinates you can measure between yourself.

Get a free API key

1,000 requests a day, free · no card · the key appears on the next page

GET /v1/distance

Great-circle distance in miles and kilometres between the two ZIP codes' published centre points, with each end's city, state and coordinates.

curl "https://zipcodes.pro/v1/distance?from=10001&to=90210" \
  -H "Authorization: Bearer YOUR_API_KEY"
const res = await fetch("https://zipcodes.pro/v1/distance?from=10001&to=90210", {
  headers: { Authorization: "Bearer YOUR_API_KEY" },
});
if (!res.ok) throw new Error((await res.json()).message);
const data = await res.json();
import requests

r = requests.get(
    "https://zipcodes.pro/v1/distance",
    params={"from": "10001", "to": "90210"},
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    timeout=10,
)
r.raise_for_status()
data = r.json()

Response 200

{
  "from": {
    "zip": "10001",
    "city": "New York",
    "state": "NY",
    "lat": 40.750649,
    "lng": -73.997298
  },
  "to": {
    "zip": "90210",
    "city": "Beverly Hills",
    "state": "CA",
    "lat": 34.100517,
    "lng": -118.41463
  },
  "miles": 2453.414,
  "kilometers": 3948.387,
  "method": "great-circle distance between the ZIP codes' published centre points"
}
ParameterMeaning
from
query, required
Five digit ZIP code.
to
query, required
Five digit ZIP code.

What you get

  • Great-circle distance between the two ZIP codes' published centre points, to three decimals.
  • Each end comes back with its USPS city, state, latitude and longitude.
  • Use it for shipping estimates, "how far is" answers, mileage checks and matching people to the nearest location.
  • Errors say which ZIP code was wrong: a bad format is 400, an unknown one is 404.

ZIP codes within a radius: GET /v1/radius

Every ZIP code whose centre point is within the radius, nearest first, each with its distance in miles. Measure from a ZIP code or from any coordinate.

curl "https://zipcodes.pro/v1/radius?zip=95014&miles=5" \
  -H "Authorization: Bearer YOUR_API_KEY"
const res = await fetch("https://zipcodes.pro/v1/radius?zip=95014&miles=5", {
  headers: { Authorization: "Bearer YOUR_API_KEY" },
});
if (!res.ok) throw new Error((await res.json()).message);
const data = await res.json();
import requests

r = requests.get(
    "https://zipcodes.pro/v1/radius",
    params={"zip": "95014", "miles": "5"},
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    timeout=10,
)
r.raise_for_status()
data = r.json()

Response 200

{
  "origin": {
    "zip": "95014",
    "lat": 37.308354,
    "lng": -122.081882
  },
  "miles": 5,
  "count": 11,
  "zips": [
    {
      "zip": "95014",
      "type": "standard",
      "usps_city": "Cupertino",
      "state": "CA",
      "county_fips": "06085",
      "timezone": "America/Los_Angeles",
      "lat": 37.308354,
      "lng": -122.081882,
      "population": 60932,
      "median_household_income": 230913,
      "median_home_value": 2000001,
      "land_sqmi": 24.86,
      "density_per_sqmi": 2451,
      "miles": 0
    },
    {
      "zip": "95015",
      "type": "unknown",
      "usps_city": "Cupertino",
      "state": "CA",
      "county_fips": "06085",
      "timezone": "America/Los_Angeles",
      "lat": 37.323,
      "lng": -122.0527,
      "population": null,
      "median_household_income": null,
      "median_home_value": null,
      "land_sqmi": null,
      "density_per_sqmi": null,
      "miles": 1.896
    },
    {
      "zip": "94024",
      "type": "standard",
      "usps_city": "Los Altos",
      "state": "CA",
      "county_fips": "06085",
      "timezone": "America/Los_Angeles",
      "lat": 37.350388,
      "lng": -122.098686,
      "population": 23051,
      "median_household_income": 250001,
      "median_home_value": 2000001,
      "land_sqmi": 8.273,
      "density_per_sqmi": 2786.3,
      "miles": 3.047
    },
    "… 8 more"
  ]
}

Bulk lookup: POST /v1/bulk

Many ZIP codes in one request (100 on Free, 1,000 on paid plans). Results come back in the order you sent them, with null for a ZIP code that does not exist, and lists of what was not found or not valid.

curl -X POST "https://zipcodes.pro/v1/bulk" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"zips":["95014","10001","99999"]}'
const res = await fetch("https://zipcodes.pro/v1/bulk", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({"zips":["95014","10001","99999"]}),
});
const data = await res.json();
import requests

r = requests.post(
    "https://zipcodes.pro/v1/bulk",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={"zips":["95014","10001","99999"]},
    timeout=10,
)
r.raise_for_status()
data = r.json()

Response 200

{
  "requested": 3,
  "found": 2,
  "not_found": [
    "99999"
  ],
  "invalid": [],
  "results": [
    {
      "zip": "95014",
      "type": "standard",
      "type_source": "inferred",
      "city": "Cupertino",
      "other_place_names": [
        "San Jose",
        "Sunnyvale"
      ],
      "state": "CA",
      "state_name": null,
      "county": null,
      "counties": [
        {
          "county_fips": "06085",
          "name": "Santa Clara County",
          "short_name": "Santa Clara",
          "weight": 1,
          "basis": "land_area"
        }
      ],
      "location": {
        "lat": 37.308354,
        "lng": -122.081882,
        "source": "gazetteer_internal_point",
        "timezone": "America/Los_Angeles"
      },
      "is_zcta": true,
      "parent_zcta": null,
      "metro": {
        "cbsa_code": "41940",
        "name": "San Jose-Sunnyvale-Santa Clara, CA",
        "type": "metro",
        "csa_code": "488",
        "csa_name": "San Jose-San Francisco-Oakland, CA"
      },
      "demographics": {
        "population": 60932,
        "households": 21868,
        "housing_units": 23104,
        "median_age": 41,
        "median_household_income": 230913,
        "median_home_value": 2000001,
        "median_rent": 3501,
        "pct_bachelors_plus": 81.9,
        "mean_commute_min": 23.7,
        "density_per_sqmi": 2451
      },
      "business": {
        "establishments": 1615,
        "employees": 59243,
        "annual_payroll_thousands": 22133258
      },
      "tax": {
        "irs_returns": 27000,
        "irs_agi_thousands": 8673961
      },
      "area": {
        "land_sqmi": 24.86,
        "water_sqmi": 0.131
      },
      "nearest_zips": [
        {
          "zip": "95015",
          "miles": 1.9,
          "city": "Cupertino",
          "state": "CA"
        },
        {
          "zip": "94024",
          "miles": 3,
          "city": "Los Altos",
          "state": "CA"
        },
        {
          "zip": "94087",
          "miles": 3.9,
          "city": "Sunnyvale",
          "state": "CA"
        },
        "… 7 more"
      ],
      "release": "2026-10-22"
    },
    {
      "zip": "10001",
      "type": "standard",
      "type_source": "inferred",
      "city": "New York",
      "other_place_names": [],
      "state": "NY",
      "state_name": null,
      "county": null,
      "counties": [
        {
          "county_fips": "36061",
          "name": "New York County",
          "short_name": "New York",
          "weight": 1,
          "basis": "land_area"
        }
      ],
      "location": {
        "lat": 40.750649,
        "lng": -73.997298,
        "source": "gazetteer_internal_point",
        "timezone": "America/New_York"
      },
      "is_zcta": true,
      "parent_zcta": null,
      "metro": {
        "cbsa_code": "35620",
        "name": "New York-Newark-Jersey City, NY-NJ",
        "type": "metro",
        "csa_code": "408",
        "csa_name": "New York-Newark, NY-NJ-CT-PA"
      },
      "demographics": {
        "population": 30511,
        "households": 15737,
        "housing_units": 18356,
        "median_age": 35.8,
        "median_household_income": 129852,
        "median_home_value": 561100,
        "median_rent": 3361,
        "pct_bachelors_plus": 72.6,
        "mean_commute_min": 26,
        "density_per_sqmi": 48895.8
      },
      "business": {
        "establishments": 6325,
        "employees": 173194,
        "annual_payroll_thousands": 21557555
      },
      "tax": {
        "irs_returns": 16960,
        "irs_agi_thousands": 4479865
      },
      "area": {
        "land_sqmi": 0.624,
        "water_sqmi": 0
      },
      "nearest_zips": [
        {
          "zip": "10199",
          "miles": 0.1,
          "city": "New York",
          "state": "NY"
        },
        {
          "zip": "10119",
          "miles": 0.2,
          "city": "New York",
          "state": "NY"
        },
        {
          "zip": "10122",
          "miles": 0.3,
          "city": "New York",
          "state": "NY"
        },
        "… 7 more"
      ],
      "release": "2026-10-22"
    },
    null
  ]
}

Limits

The free plan includes 1,000 requests a day, reset at 00:00 UTC, and 60 a minute. Every response says where you stand:

HeaderMeaning
X-RateLimit-LimitRequests your plan includes in the current window (1,000 a day on Free).
X-RateLimit-RemainingRequests left in the window, after this one.
X-RateLimit-ResetWhen the window resets, ISO 8601 in UTC. Free resets at 00:00 UTC.
Retry-AfterSeconds to wait, on a 429 for the per-minute limit only.

Over the limit, the API answers 429 with the reset time; nothing is billed. Paid plans for higher volume (Starter 100,000 a month, Pro 500,000 a month, Business 3,000,000 a month) are listed on the pricing page and are not on sale yet.

Questions

Is this driving distance?

No. It is the straight-line (great-circle) distance between ZIP code centre points. Driving distance depends on a road network and is usually 15 to 30 percent longer.

How accurate is the distance between two ZIP codes?

Exact for the two centre points. A ZIP code covers an area, so two addresses can be closer or further apart than their ZIP codes' centres, most noticeably in large rural ZIP codes.

Can I measure many pairs in one request?

Use POST /v1/bulk to fetch up to 1,000 ZIP codes' coordinates in one call (100 on Free), then compute the distances locally with the haversine formula.

Kilometres or miles?

Both: miles and kilometers are in every response.

More