Skip to main content
GET
Page through a country’s postcodes / ZIP codes, or narrow the list with a code/locality search, state, city, or type filter. Use this to build postcode discovery instead of downloading the full dataset.
Requires a Supporter+ plan — including a bare list request with no filters at all. This is intentional: it stops a Community or Starter key from paginating through and scraping the full hosted dataset. Get Postcode by Code (exact lookup) has no such gate and stays free on every plan.
This is informational postcode data, not an address verification or mail-deliverability service. Results confirm codes exist in the dataset — they do not confirm delivery points or standardize addresses.

Path parameters

string
required
ISO 3166-1 alpha-2 country code, case-insensitive (e.g., US, GB, IN). Numeric country IDs and ISO3 codes are not accepted on this endpoint.
Trim results: Add ?fields= to limit the columns returned. Requires Supporter+. There is no ?sort= on this endpoint — results are always ordered by code, then id, so cursor pagination stays stable. See the Field Filtering & Sorting guide for ?fields= syntax.

Authentication

string
required
Your API key.

Query parameters

string
Case-insensitive search: matches postcodes whose code starts with q, or whose locality name contains it. 2-100 characters. Optional — omit it to list the country’s postcodes instead of searching. Every request to this endpoint requires Supporter+ regardless of whether q is present.
string
Exact, case-insensitive filter on state/province code. 1-255 letters, digits, or hyphens.
string
Exact filter on the city ID. A positive integer, passed as a query string (e.g. ?city_id=129881).
string
Exact, case-insensitive filter on the postcode’s source classification. See Postcode types for the values currently in the dataset — this is not a fixed enum, so a well-formed but unrecognized value (letters, digits, _, -, 1-32 characters) just matches zero rows instead of returning a 400.
integer
default:"50"
Maximum records per page. Use a value from 1 to 100.
string
Opaque pagination token from a previous response’s pagination.next_cursor. Treat it as opaque — do not parse or construct it yourself. A cursor is tied to the filters it was issued with: resend the exact same state_code/city_id/type/q, or omit them entirely and paginate with the cursor alone.

Response

array
Matching postcode records for this page, ordered by code, then id.
string
Unique identifier for the postcode record, returned as a numeric string (not a JSON number) for 64-bit safety.
string
The postcode as stored, with original spacing and casing preserved.
string
ISO2 country code.
string | null
State/province code, when linked to one.
string | null
Human-readable place name associated with the postcode.
string | null
A source-provided classification of the postcode, not a fixed enum. See Postcode types.
string
Country ID, as a numeric string.
string | null
State ID, as a numeric string.
string | null
City ID, as a numeric string, when linked to a specific city.
number | null
Latitude of the postcode area.
number | null
Longitude of the postcode area.
string | null
Originating data source, for attribution and license tracking. Requires Professional+.
string | null
Wikidata Q-ID for cross-referencing. Requires Professional+.
integer
The limit used for this page.
string | null
Token for the next page, or null when this is the last page.
boolean
Whether another page is available.
There is no total-count field. Counting every match up front would mean a second expensive query on top of a 844k-row table, so check has_more and keep paging instead of expecting a total.
200 - Search with q (Supporter+)

Tier-based field availability

Every plan that can reach this endpoint at all already has at least Coordinates access — Community, Starter, and Legacy lack the searchEndpoint feature this endpoint requires, so the Basic row below is unreachable here (it only applies to Get Postcode by Code). See Pricing for plan details.

Caching and conditional requests

Every response sets ETag, Cache-Control (public, max-age=3600), and X-Cache (HIT/MISS), cached for 1 hour regardless of whether q is present. Send the last ETag back as If-None-Match to get a bodyless 304 when nothing changed instead of re-downloading the page:

Errors

400 - Invalid country code
400 - Cursor filters don't match this request
A cursor also 400s as "cursor belongs to a different country." when reused across countries, "cursor is invalid or has been tampered with." when it’s malformed or its signature doesn’t verify, and "cursor has expired. Start again without a cursor." after 24 hours.
403 - Requires Supporter+
This 403 fires on every request to this endpoint from a Community, Starter, or Legacy key — including a bare list with no q, state_code, city_id, or type at all. Only exact lookup (Get Postcode by Code) is free on those plans.
200 - Country with no postcode coverage
A country that exists but has no postcodes, or a filter that matches nothing, returns 200 with an empty data array — not a 404. The 404 cases (country_not_found) match Get Postcode by Code for an unknown country. See Errors & Rate Limits for the 401/429 shapes and usage headers common to every endpoint.
This endpoint requires a Supporter+ plan, for listing as well as searching. Compare plans to add it to your API key.

Get Postcode by Code

Exact lookup, free on every plan — start here before adding search.

Postcodes Reference

Coverage stats, postcode types, and self-hosted query examples.