Skip to content

The 32 estados and their municipios, with official INEGI codes

Every Mexican address form starts with the same two dropdowns, and every system that has to talk to another one eventually has to agree on what to call a municipio. This is the layer underneath both problems.

Two jobs, one catalog

  • Cascading dropdowns that do not drift.

    Estado, then municipio, then ciudad. Hardcoding those lists is fine right up until a name changes and your copy and everybody else’s stop agreeing.

  • Speaking INEGI to systems that expect it.

    Invoicing, government filings, logistics partners and public datasets identify a municipio by its official numeric clave, not by its name. Matching on names across that boundary is how records go missing.

Start at the top

The states list is small, fixed and the natural first call. Each entry carries both identifiers: id is ours, code is the two-digit INEGI clave.

Request

curl
curl -H "Authorization: Bearer YOUR_API_KEY" \
  https://api.postalkit.mx/v1/states

Response

200 Success
{
  "data": [
    { "id": 2, "name": "Aguascalientes", "code": "01" },
    { "id": 1, "name": "Ciudad de México", "code": "09" }
  ]
}

Then drill down. Municipios come back with their own three-digit clave, which is the number that is unique within the state rather than across the country.

Request

curl
curl -H "Authorization: Bearer YOUR_API_KEY" \
  https://api.postalkit.mx/v1/states/1/municipalities

Response

200 Success
{
  "data": [
    { "id": 1, "name": "Álvaro Obregón", "code": "010" },
    { "id": 6, "name": "Cuauhtémoc", "code": "015" }
  ]
}

Ciudades hang off the estado rather than off the municipio, and a postal code does not always have one — the field comes back null when there is none. GET /v1/states/{id}/cities lists them for a state when your form needs that field.

Coming in from the INEGI side

If your records already carry the official state clave, you do not have to look up our id first, and you do not have to store our ids at all. Address the state by its code:

Request

curl
curl -H "Authorization: Bearer YOUR_API_KEY" \
  https://api.postalkit.mx/v1/states/by-code/09/municipalities

That endpoint exists for exactly one reason: so that a system built around INEGI numbering can use this API without adopting a second set of identifiers it would then have to keep in step.

Before you ship it

Codes are zero-padded strings

  • “01” is not 1, and “010” is not 10.

    State claves are two digits and municipio claves are three, both zero-padded, both strings. Cast either to an integer and the padding is gone for good, which breaks the join you added them for.

  • A municipio clave only means something with its state.

    “015” is Cuauhtémoc in Ciudad de México and something else in another state. The pair is the key; the municipio number alone is not.

  • Two identifiers, and both are stable.

    Ours survive the monthly refresh, so a stored id still resolves. Prefer the INEGI clave anyway if anything outside your system will ever read the value.

  • This list is the one thing worth copying wholesale.

    Thirty-two states and their municipios is a small, near-static table. Pull it once, keep it, and check GET /v1/account/db-version on a schedule rather than fetching it per page load.

Fetch the 32 states in one call.

100 requests a month, free, no card. The states list costs one of them.

curl -s https://api.postalkit.mx/v1/states -H "Authorization: Bearer YOUR_API_KEY"