# Geocodio API Reference

> Markdown version of https://www.geocod.io/docs. Index of Geocodio documentation for agents: https://www.geocod.io/llms.txt

# Introduction

Geocodio's RESTful [geocoding API](#geocoding) endpoints allows you to perform forward and reverse geocoding lookups for the US, Canada, Mexico, and the United Kingdom as well as simultaneously enrich your address data. Geocodio's geocoding API supports individual, batch, and list (CSV) geocoding.

Data appends (`fields`) include Census geographies and data, electoral districts, timezones, school districts, and more.

The base API url is `https://api.geocod.io/v2/`.

Geocodio's [distance API](#distance) endpoints allow you to calculate driving time, driving distance, and straight line (as the crow flies/haversine) distance between addresses or coordinates. One-to-one, one-to-many, and many-to-many matrices are supported, and you can limit results to a specified radius.

All HTTP responses (including errors) are returned with [JSON-formatted](http://www.json.org) output.

We may add additional properties to the output in the future, but existing properties will never be changed or removed without a new API version release.

> **Note:** Note the versioning prefix in the base url, which is required for all requests.

# Supported Countries

| | Forward geocoding | Reverse geocoding | Distance                    |
|---|---|---|-----------------------------|
| United States | Yes | Yes | Yes |
| Canada | Yes | Yes | Yes |
| Mexico | Yes | Yes | Yes |
| United Kingdom | Yes | Yes | Yes |

## Specifying Country

### Default Behavior
* Individual lookups: Inferred from address format
* Fallback: United States

### Explicit `country` Parameter
```shell
# US address (explicit)
curl "https://api.geocod.io/v2/geocode?q=1109+N+Highland+St,+Arlington+VA&country=USA&api_key=YOUR_API_KEY"

# Canadian address (explicit)
curl "https://api.geocod.io/v2/geocode?q=525+University+Ave,+Toronto+ON&country=Canada&api_key=YOUR_API_KEY"

# Mexican address (explicit)
curl "https://api.geocod.io/v2/geocode?q=Avenida+Paseo+De+La+Reforma+489,+06500+Ciudad+De+M%C3%A9xico,+CMX&country=Mexico&api_key=YOUR_API_KEY"

# UK address (explicit)
curl "https://api.geocod.io/v2/geocode?q=10+Downing+Street,+London+SW1A+2AA&country=GB&api_key=YOUR_API_KEY"
```

**Supported Country Values:** USA, Canada, Mexico, or GB. Additional values are accepted here as Geocodio adds country coverage, so check this table rather than hardcoding the list.

> **Note:** The United Kingdom is identified by its ISO code `GB`. Values such as `UK`, `United Kingdom`, `England`, `Scotland`, and `Wales` are also accepted and normalized to `GB`.

## Address Format Differences

### United States
* State: 2-letter abbreviation (e.g., `VA`, `CA`)
* ZIP Code: 5 or 9 digits (e.g., `22201` or `22201-1234`)

### Canada
* Province: 2-letter abbreviation (e.g., `ON`, `BC`)
* Postal Code: full postal code (e.g., `M5G 1X8`) or 3-character FSA (e.g., `M5G`). Canadian results return only the FSA (full postal codes cannot be redistributed under Canada Post licensing), but a full postal code you supply is echoed back when its FSA matches the geocoded result. See [Migrating to API v2](#migrating-to-api-v2)

### Mexico
* State: Input is flexible (e.g., `CDMX`, `CMX`, `Jal.`, `Jalisco`). Results return the short code, e.g. `CMX` for Ciudad De México
* Postal Code: 5 digits (e.g., `06500`)
* Ordering: the house number follows the street name (`Avenida Paseo De La Reforma 489`), and the postal code precedes the city (`06500 Ciudad De México, CMX`)

### United Kingdom
* Nation: GB results return the constituent country in the `nation` field as a full name — `England`, `Scotland`, `Wales`, or `Northern Ireland` (the `state` field is `null` for GB addresses).
* Postcode: 5–8 characters with a space before the final three (e.g., `SW1A 2AA`, `EH2 4DR`). Geocodio normalizes the spacing, so `SW1A2AA` and `sw1a 2aa` are both accepted.
* Outward code: the first half of a postcode (e.g., `SW1A`, `M1`, `EH2`). A query containing only an outward code resolves to the place candidates within it — see [postcode-only queries](#coverage-notes-edge-cases) below.

> **Note:** Geocodio returns UK addresses with a single formatted address line, the postcode, and a country of `GB`.

# Libraries

## Official libraries

These libraries are officially written and maintained by Geocodio. Have an issue? Please email us at support@geocod.io.

GitHub pull requests and issues are also more than welcome.

| Platform | Library |
| --- | --- |
| **PHP** | [Geocodio/geocodio-library-php](https://github.com/Geocodio/geocodio-library-php) |
| **Node.js** | [Geocodio/geocodio-library-node](https://github.com/Geocodio/geocodio-library-node) |
| **Ruby** | [Geocodio/geocodio-gem](https://github.com/Geocodio/geocodio-gem) |
| **Python** | [Geocodio/geocodio-library-python](https://github.com/Geocodio/geocodio-library-python) |

## Third-party libraries

Thanks to the wonderful open-source community, we have language bindings for several additional languages and platforms.

We will do our best to assist via email, but may not be able to help in all cases with these libraries.

Some of the libraries are featured here with basic examples, but please make sure to check out the full documentation for the individual libraries (linked below).

| Platform | Library | Featured in documentation |
| --- | --- | --- |
| **Ruby** | [alexreisner/geocoder](https://github.com/alexreisner/geocoder) supports Geocodio thanks to PR by [@dblockdotorg](https://twitter.com/dblockdotorg) | No |
| **Ruby** | [davidcelis/geocodio](https://github.com/davidcelis/geocodio) by [@davidcelis](https://twitter.com/davidcelis) | No |
| **Python** | [bennylope/pygeocodio](https://github.com/bennylope/pygeocodio) by [@bennylope](https://twitter.com/bennylope) | Yes |
| **Clojure** | [jboverfelt/rodeo](https://github.com/jboverfelt/rodeo) by [@jboverfelt](https://twitter.com/jboverfelt) | Yes |
| **Perl** | [mrallen1/WebService-Geocodio](https://github.com/mrallen1/WebService-Geocodio) by [@bytemeorg](https://twitter.com/bytemeorg) | No |
| **Go** | [stevepartridge/geocodio](https://github.com/stevepartridge/geocodio) by [stevepartridge](https://github.com/stevepartridge) | No |
| **R** | [hrbrmstr/rgeocodio](https://github.com/hrbrmstr/rgeocodio) by [hrbrmstr](https://github.com/hrbrmstr) | No |
| **R** | [jessecambon/tidygeocoder](https://jessecambon.github.io/tidygeocoder) by [jessecambon](https://github.com/jessecambon) | No |
| **C#** | [snake-plissken/cSharpGeocodio](https://github.com/snake-plissken/cSharpGeocodio) by [Frank Deasey](https://github.com/snake-plissken) | No |
| **C#** | [arex388/Arex388.Geocodio](https://github.com/arex388/Arex388.Geocodio) by [arex388](https://github.com/arex388) | No |
| **Rust** | [Cosiamo/geocodio_lib_rust](https://github.com/Cosiamo/geocodio_lib_rust) by [Cosiamo](https://github.com/Cosiamo) | No |
| **Java** | [deansg/jeocodio](https://github.com/deansg/jeocodio) by [Dean Gurvitz](https://github.com/deansg) | No |

> Installing the library:

```shell
# Make sure to have `curl` installed to test the API in your terminal
```

```ruby
# Add the following to your Gemfile:
gem 'geocodio-gem'

# And then run:
bundle install
```

```python
pip install geocodio-library-python
```

```php
# Install via Composer
composer require geocodio/geocodio-library-php

<?php
require('vendor/autoload.php');

# Don't fancy Composer? Not a problem!
# Check out our sample code here: https://github.com/Geocodio/php-samples
```

```javascript
# Install via npm
$ npm install --save geocodio-library-node

# Install via Yarn
$ yarn add geocodio-library-node
```

# AI agents

Geocodio publishes plain-markdown versions of its documentation, along with a set of files written for AI agents and coding assistants. If you are building with an agent, point it at these rather than the HTML docs.

| Resource | What it covers |
| --- | --- |
| [AGENTS.md](https://www.geocod.io/AGENTS.md) | A guide for agents on how to run geocoding jobs without unnecessarily running up the bill: counting lookups, testing on a sample, setting a usage limit, and storing results so the same address is never geocoded twice. Have your agent read this before pointing it at a large file. |
| [llms.txt](https://www.geocod.io/llms.txt) | The API and pricing reference in a single file. Endpoints, limits, data appends, plans, and what you can do with results. |
| [Markdown docs](https://www.geocod.io/docs/index.md) | This full API reference as markdown. |
| [OpenAPI spec](https://api.geocod.io/openapi-spec.json) | Machine-readable API description. Also available as [YAML](https://api.geocod.io/openapi-spec.yml). |
| [CLI](https://github.com/Geocodio/geocodio-cli) | Command line tool for geocoding, distance, and spreadsheet jobs. Includes an `--agent` output mode that returns markdown tables meant for showing results to a person. Installable as an agent skill with `npx skills add geocodio/geocodio-cli`. |

## Migrating with an agent

Moving an existing integration to API v2? See [Upgrade with an AI assistant](#upgrade-with-an-ai-assistant).

# Authentication

> To set the `API_KEY`:

```shell
# With curl, you can pass the query parameter with each request
curl "https://api.geocod.io/v2/api_endpoint_here?api_key=YOUR_API_KEY"

# or use the Authorization header
curl "https://api.geocod.io/v2/api_endpoint_here" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")
```

```php
<?php
$geocoder = new Geocodio\Geocodio();
$geocoder->setApiKey('YOUR_API_KEY');
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocoder = new Geocodio('YOUR_API_KEY');

// You can also leave out the parameter and define the "GEOCODIO_API_KEY" environment variable instead
```

All requests require an API key. You can [register here](https://dash.geocod.io) to get your own API key.

The API key must be included in all requests using the `api_key` query parameter. It is also possible to supply the API key via the `Authorization` header.

Accounts can have multiple API keys. This can be useful if you're working on several projects and want to be able to revoke access using the API key for a single project in the future or if you want to keep track of usage per API key.

You can also download a CSV of usage and fees per API key [on the dashboard](https://dash.geocod.io/usage).

> **Warning:** Make sure to replace YOUR_API_KEY with your personal API key found on the [Geocodio dashboard](https://dash.geocod.io).

## Using query parameter

The simplest way to authenticate is using the `api_key` query parameter. The API key must be included in all requests using the `&api_key=YOUR_API_KEY` query parameter.

## Using Authorization header

Alternatively, the API key can be supplied via an HTTP request header:

> `Authorization: Bearer YOUR_API_KEY`

# Permissions

> A `403 Forbidden` HTTP status code is returned if the API key is valid, but does not have permission to access the requested endpoint

```json
{
  "error": "This API key does not have permission to access this feature. API key permissions can be changed in the Geocodio dashboard at https:\/\/dash.geocod.io\/apikey"
}
```

Per default, an API key can only access the single and batch geocoding API endpoints. These endpoints are write-only which means that a lost API key can not be used to retrieve geocoded data from your account.

You must specifically enable permissions for the [lists API](#geocoding-lists) and the [distance API endpoints](#distance). This can be done on the [Geocodio dashboard](https://dash.geocod.io/apikey). We recommend creating separate API keys for single/batch endpoints and for `GET`/`DELETE` access to lists/jobs.

[![List of API key permissions with default values selected](img/apikeypermissions.png)](https://dash.geocod.io/apikey)

*List of API key permissions with default values selected*

# Overview

Geocodio's **geocoding API** supports three different methods for processing your data. Geocodio is designed to make high-volume geocoding and data enrichment easier, yet we also support real-time single requests.

Single and batch geocoding methods are synchronous, meaning that you have to wait for the data to be fully processed and will receive it directly in your API response. The [list geocoding](#geocoding-lists) method is asynchronous and requires a second request to be made to download the data once it is ready.

The method you choose will largely depend on your workflow and the amount of addresses or coordinates that you are looking to process. If in doubt, [single geocoding](#geocoding) is the simplest choice for many use cases.

Name                                  | Batch size         | Type         | Format           | Supports data appends (fields)             | Supports forward & reverse geocoding
------------------------------------- | ------------------ | ------------ | ---------------- | --------------------------- | --------------------------------------
[Single geocoding](#geocoding)        | 1                  | Synchronous  | JSON             | Yes | Yes
[Batch geocoding](#batch-geocoding)   | Up to 10,000       | Synchronous  | JSON             | Yes | Yes
[List geocoding](#geocoding-lists)    | Up to 10,000,000+  | Asynchronous | CSV/TSV/Excel    | Yes | Yes

Geocodio's **distance API** endpoints allow you to calculate driving time, driving distance, and straight line (as the crow flies/haversine) distance between addresses or coordinates. One-to-one, one-to-many, and many-to-many matrices are supported, and you can limit results to a specified radius.

Like the geocoding API, the method you choose depends on your use case.

For distance, *batch size* is the total number of calculations (origins × destinations).

Name                                  | Batch size (calculations)         | Type         | Format           | Supports addresses & coordinates |
------------------------------------- | ------------------ | ------------ | ---------------- | --------------------------- |
[Single origin distance](#single-origin-distance)        | 100                  | Synchronous  | JSON             | Yes |
[Distance matrix](#distance-matrix)   | Up to 10,000       | Synchronous  | JSON             | Yes |
[Distance jobs](#distance-jobs-async)    | Up to 50,000  | Asynchronous | JSON    | Yes |

# Geocoding

Geocoding (also known as forward geocoding) allows you to convert one or more addresses into geographic coordinates (i.e. latitude and longitude). Geocoding will also parse the address and append additional information (e.g. if you specify a ZIP code, Geocodio will return the city and state corresponding to the zip code as well)

Geocodio supports geocoding of addresses, cities and ZIP codes in various formats.

> **Note:** Make sure to check the [address formats](#address-formats) section for more information on the different address formats supported.

Whenever possible, batch requests via the batch or lists endpoints is encouraged since they are significantly faster due to reduced network overhead.

## Single address

Geocodio can geocode a single address by making a `GET` request to the *geocode* endpoint. You can [try this in your browser right now](https://api.geocod.io/v2/geocode?q=1109+N+Highland+St%2c+Arlington+VA&api_key=YOUR_API_KEY) after creating an API key or via our [demo tool](https://www.geocod.io/geocode-an-address).

> **Tip:** The `results` are always ordered with the most accurate locations first. It is therefore always safe to pick the first result in the list.

> To geocode a single address:

```shell
# Using q parameter
curl "https://api.geocod.io/v2/geocode?q=1109+N+Highland+St%2c+Arlington+VA&api_key=YOUR_API_KEY"

# Using individual address components
curl "https://api.geocod.io/v2/geocode?street=1109+N+Highland+St&city=Arlington&state_province=VA&api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

location = geocodio.geocode(['1109 N Highland St, Arlington VA'])
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

response = client.geocode("1109 N Highland St, Arlington VA")
# Access the first result
print(response.results[0].formatted_address)
print(response.results[0].location.lat)
print(response.results[0].location.lng)
```

```php
<?php
$response = $geocoder->geocode('1109 N Highland St, Arlington VA');
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocoder = new Geocodio('YOUR_API_KEY');

geocoder.geocode('1109 N Highland St, Arlington VA')
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example response:

```json
{
  "results": [
    {
      "address_components": {
        "number": "1109",
        "predirectional": "N",
        "street": "Highland",
        "suffix": "St",
        "formatted_street": "N Highland St",
        "city": "Arlington",
        "county": "Arlington County",
        "state_province": "VA",
        "postal_code": "22201",
        "country": "US"
      },
      "address_lines": [
        "1109 N Highland St",
        "",
        "Arlington, VA 22201"
      ],
      "formatted_address": "1109 N Highland St, Arlington, VA 22201",
      "location": {
        "lat": 38.886665,
        "lng": -77.094733
      },
      "accuracy": 1,
      "accuracy_type": "rooftop",
      "source": "Virginia GIS Clearinghouse",
      "stable_address_key": "gcod_usnbfvbm5l57cc8b8bnfnyrua9ym3"
    }
  ]
}
```

### HTTP Request

`GET https://api.geocod.io/v2/geocode`

### URL Parameters

Parameter | Description
--------- | -----------
`q`       | The query (i.e. address) to geocode
`api_key` | Your Geocodio API key
`country` | Optional parameter. The country to geocode the address in. The default is to infer from the query, with a fallback to USA.
`fields`  | Optional parameter to request [additional data appends](#data-appends-fields).
`limit`   | Optional parameter. The maximum number of results to return. The default is no limit. If set to 0, no limit will be applied.
`format`  | Optional parameter to change the JSON output format to a different pre-defined structure. Currently, "simple" is the only valid value. If not set, the default full JSON output structure is used.
`destinations[]` | Optional parameter. Array of destination locations for [distance calculation](#distance). Each destination can be a coordinate string (`"lat,lng"` or `"lat,lng,id"`) or a geocodable address. When provided, each result will include a `destinations` array with distance/duration to each destination.
`distance_mode` | Optional parameter. Distance calculation mode: `driving` (road network, includes duration) or `straightline` (great-circle distance, no duration). Default is `straightline`.
`distance_units` | Optional parameter. Unit of measurement: `miles` or `km`. Default is `miles`.
`distance_max_results` | Optional parameter. Maximum number of destinations to return per geocoded result.
`distance_max_distance` | Optional parameter. Filter out destinations beyond this distance (in specified units).
`distance_min_distance` | Optional parameter. Filter out destinations closer than this distance (in specified units).
`distance_max_duration` | Optional parameter. Filter out destinations with travel time exceeding this value in seconds (driving mode only).
`distance_min_duration` | Optional parameter. Filter out destinations with travel time below this value in seconds (driving mode only).
`distance_order_by` | Optional parameter. Sort destinations by `distance` or `duration`. Default is `distance`.
`distance_sort_order` | Optional parameter. Sort order: `asc` or `desc`. Default is `asc`.

***

**Alternative URL Parameters**

Instead of using the *q* parameter, you can use a combination of `addressee`, `street`, `street2`, `city`, `county`, `state_province`, `postal_code`, and/or `country`.

This is recommended if the address is already parsed into separate fields in your database.

Parameter     | Description
------------- | -----------
`addressee`   | Optional. E.g. Apple Inc. The recipient, business, or firm name. Used to return a more precise [USPS ZIP+4 code](#usps-zip-4) for businesses. See [The `addressee` parameter](#the-addressee-parameter)
`street`      | E.g. 1600 Pennsylvania Ave NW
`street2`     | E.g. Apt 204
`city`        | E.g. Washington
`county`      | E.g. Arlington
`state_province` | E.g. DC
`postal_code` | E.g. 20500
`country`     | E.g. Canada, Mexico, GB. Defaults to USA. See [Supported Countries](#supported-countries) for the accepted values

### International addresses

Geocoding works the same way for every country Geocodio supports — only the address format changes. See [Supported Countries](#supported-countries) for the current coverage and [Address Format Differences](#address-format-differences) for the per-country conventions.

The country is inferred from the query when the address format makes it recognizable, and falls back to the United States when it does not. Set the [`country` parameter](#specifying-country) whenever you already know which country an address belongs to — it is the only way to guarantee that a query is interpreted the way you intend.

> To geocode an address outside the United States:

```shell
# Canada — the trailing country name is enough to infer Canada
curl "https://api.geocod.io/v2/geocode?q=525+University+Ave%2c+Toronto%2c+ON%2c+Canada&api_key=YOUR_API_KEY"

# Mexico — country set explicitly
curl "https://api.geocod.io/v2/geocode?q=Avenida+Paseo+De+La+Reforma+489%2c+06500+Ciudad+De+M%C3%A9xico%2c+CMX&country=Mexico&api_key=YOUR_API_KEY"

# United Kingdom — country set explicitly
curl "https://api.geocod.io/v2/geocode?q=10+Downing+Street%2c+London+SW1A+2AA&country=GB&api_key=YOUR_API_KEY"

# Individual address components work the same way
curl "https://api.geocod.io/v2/geocode?street=7515+118+Ave+NW&city=Edmonton&state_province=AB&postal_code=T5B+0X2&country=Canada&api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

locations = geocodio.geocode([
  '525 University Ave, Toronto, ON, Canada',
  'Avenida Paseo De La Reforma 489, 06500 Ciudad De México, CMX',
  '10 Downing Street, London SW1A 2AA'
])
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

addresses = [
  "525 University Ave, Toronto, ON, Canada",
  "Avenida Paseo De La Reforma 489, 06500 Ciudad De México, CMX",
  "10 Downing Street, London SW1A 2AA"
]

response = client.geocode(addresses)
for result in response.results:
    if result.response.results:
        print(result.response.results[0].formatted_address)
```

```php
<?php
$addresses = [
  '525 University Ave, Toronto, ON, Canada',
  'Avenida Paseo De La Reforma 489, 06500 Ciudad De México, CMX',
  '10 Downing Street, London SW1A 2AA'
];
$response = $geocoder->geocode($addresses);
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocoder = new Geocodio('YOUR_API_KEY');

const addresses = [
  '525 University Ave, Toronto, ON, Canada',
  'Avenida Paseo De La Reforma 489, 06500 Ciudad De México, CMX',
  '10 Downing Street, London SW1A 2AA'
];

geocoder.geocode(addresses)
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);
```

#### Canadian results

> Example response for "525 University Ave, Toronto, ON, Canada":

```json
{
  "results": [
    {
      "stable_address_key": "gcod_canazxhbttsbey6hfa5rfsgt8cgq8",
      "address_components": {
        "number": "525",
        "street": "University",
        "suffix": "Ave",
        "formatted_street": "University Ave",
        "city": "Toronto",
        "state_province": "ON",
        "postal_code": "M5G",
        "country": "CA"
      },
      "address_lines": [
        "525 University Ave",
        "",
        "Toronto, ON M5G"
      ],
      "formatted_address": "525 University Ave, Toronto, ON M5G",
      "location": {
        "lat": 43.65625,
        "lng": -79.38822
      },
      "accuracy": 1,
      "accuracy_type": "rooftop",
      "match_type": "parcel_centroid",
      "source": "City of Toronto (Open Government Licence – Toronto Contains information licensed under the Open Government Licence – Toronto)"
    }
  ]
}
```

Canadian results return only the 3-character FSA in `postal_code`, since full postal codes cannot be redistributed under Canada Post licensing. A full postal code that you supply is echoed back when its FSA matches the geocoded result — see [Canadian full postal codes](#canadian-full-postal-codes).

#### Mexican results

> Example response for "Avenida Paseo De La Reforma 489, 06500 Ciudad De México, CMX":

```json
{
  "results": [
    {
      "stable_address_key": "gcod_mxngh2e9nnhlytg92d9lxl5krf6g5",
      "address_components": {
        "number": "489",
        "street": "Avenida Paseo De La Reforma",
        "formatted_street": "Avenida Paseo De La Reforma",
        "city": "Ciudad De México",
        "state_province": "CMX",
        "postal_code": "06500",
        "country": "MX"
      },
      "address_lines": [
        "Avenida Paseo De La Reforma 489",
        "",
        "06500 Ciudad De México, CMX"
      ],
      "formatted_address": "Avenida Paseo De La Reforma 489, 06500 Ciudad De México, CMX",
      "location": {
        "lat": 19.424056,
        "lng": -99.174903
      },
      "accuracy": 1,
      "accuracy_type": "rooftop",
      "match_type": null,
      "source": "Statewide (Source: INEGI, Directorio Estadístico Nacional de Unidades Económicas (DENUE))"
    }
  ]
}
```

Mexican addresses put the house number *after* the street name, and the postal code *before* the city, and that is how Geocodio returns them in `formatted_address` and `address_lines` as well.

#### United Kingdom results

> Example response for "10 Downing Street, London SW1A 2AA":

```json
{
  "results": [
    {
      "stable_address_key": "gcod_gbnf5jp6g3xbpmcg4djw4475wxx89",
      "address_components": {
        "number": "10",
        "street": "Downing",
        "suffix": "St",
        "formatted_street": "Downing St",
        "city": "London",
        "nation": "England",
        "postal_code": "SW1A 2AA",
        "country": "GB"
      },
      "address_lines": [
        "10 Downing St",
        "London",
        "SW1A 2AA"
      ],
      "formatted_address": "10 Downing St, London SW1A 2AA",
      "location": {
        "lat": 51.503541,
        "lng": -0.12767
      },
      "accuracy": 1,
      "accuracy_type": "rooftop",
      "match_type": "building_centroid",
      "source": "Contains OS data © Crown copyright. Contains PAF® data © Royal Mail Group Ltd."
    }
  ]
}
```

GB results carry the constituent country in `nation` rather than `state_province`, and the postcode is returned in full. See [United Kingdom political districts](#united-kingdom-political-districts) for the electoral field appends available for GB addresses.

> **Warning:** Street names are not unique across countries, so an unrecognized query really can land in the wrong one. `10 Downing Street, London SW1A 2AA` without a country matches a Downing St in Charleston, WV, because the query falls back to the United States. Send `country` whenever you know it.

### The `addressee` parameter

The `addressee` is the recipient line of an address: a person, business, or firm name such as `Apple Inc.` or `Sara Lee`. It is optional and most useful for US business addresses.

Geocodio uses the addressee to return a more precise [USPS ZIP+4 code](#usps-zip-4) for businesses that have registered a name with USPS. The addressee refines the result behind the scenes. It does not change the `address_components` and is not returned in the response.

When you geocode a single-line address with the `q` parameter, Geocodio can also detect an addressee on its own. If a query begins with a non-address prefix, Geocodio treats that prefix as the addressee. For example, given `Walmart Supercenter, 3201 SE Military Dr, San Antonio, TX`, Geocodio reads `Walmart Supercenter` as the addressee and geocodes `3201 SE Military Dr, San Antonio, TX`.

### The `format` parameter

```ruby
#  To receive a `simple` response, include the string `"simple"`
#  as the fourth argument after any fields or limit parameters
#  you have set.

  require 'geocodio/gem'

  geocodio = Geocodio::Gem.new('YOUR_API_KEY')

  response = geocodio.geocode(["1109 N Highland St, Arlington, VA"], [], nil, "simple")
```

> Example response when `format` is set to `simple`:

```json
{
  "address": "1109 N Highland St, Arlington, VA 22201",
  "lat": 38.886665,
  "lng": -77.094733,
  "accuracy": 1,
  "accuracy_type": "rooftop",
  "source": "Arlington"
}
```

> Example response when `format` is set to `simple` and no results are found:

```json
{
  "address": null,
  "lat": null,
  "lng": null,
  "accuracy": null,
  "accuracy_type": null,
  "source": null
}
```

In most cases, the standard output format would be used. In certain situations, it can however be beneficial to work with a JSON structure that is specifically designed for your use case.

**`simple` format**

When `format` is set to `simple`, a very simple JSON structure is outputted, with only basic information for the best matched results. This makes it much easier to work with the JSON document in situations where extra verbosity is not needed.

The `fields` parameter is still supported when the `simple` output format is selected, but the `limit` parameter has no effect.

### Secondary address line geocoding

> Geocoding two different units at the same street address:

```shell
# Unit A
curl "https://api.geocod.io/v2/geocode?q=734+Ave+C%2c+Unit+A%2c+El+Campo+TX&api_key=YOUR_API_KEY"

# Unit B
curl "https://api.geocod.io/v2/geocode?q=734+Ave+C%2c+Unit+B%2c+El+Campo+TX&api_key=YOUR_API_KEY"
```

> Example response for Unit A (note `match_type: "unit"` and unit-specific coordinates):

```json
{
  "results": [
    {
      "address_components": {
        "number": "734",
        "street": "C",
        "prefix": "Ave",
        "unit_type": "Unit",
        "unit_number": "A",
        "formatted_street": "Ave C",
        "city": "El Campo",
        "county": "Wharton County",
        "state_province": "TX",
        "postal_code": "77437",
        "country": "US"
      },
      "address_lines": [
        "734 Ave C",
        "Unit A",
        "El Campo, TX 77437"
      ],
      "formatted_address": "734 Ave C, Unit A, El Campo, TX 77437",
      "location": {
        "lat": 29.198601,
        "lng": -96.270966
      },
      "accuracy": 1,
      "accuracy_type": "rooftop",
      "match_type": "unit",
      "source": "Texas",
      "stable_address_key": "gcod_usnbfvbm5l57cc8b8bnfnyrua9ym3-a1b2c3"
    },
    {
      "address_components": {
        "number": "734",
        "street": "C",
        "prefix": "Ave",
        "formatted_street": "Ave C",
        "city": "El Campo",
        "county": "Wharton County",
        "state_province": "TX",
        "postal_code": "77437",
        "country": "US"
      },
      "address_lines": [
        "734 Ave C",
        "",
        "El Campo, TX 77437"
      ],
      "formatted_address": "734 Ave C, El Campo, TX 77437",
      "location": {
        "lat": 29.198432,
        "lng": -96.271015
      },
      "accuracy": 1,
      "accuracy_type": "rooftop",
      "match_type": "building_centroid",
      "source": "Texas",
      "stable_address_key": "gcod_usnbfvbm5l57cc8b8bnfnyrua9ym3"
    }
  ]
}
```

When a secondary address component is provided (apartment, suite, unit, etc.), Geocodio will attempt to return unit-specific coordinates. If unit-level data is available, the unit-specific result is returned first with `match_type` set to `"unit"`, followed by the building-level result.

Different units at the same street address may return different coordinates. For example, "734 Ave C, Unit A, El Campo TX" and "734 Ave C, Unit B, El Campo TX" can each resolve to their own precise location.

Unit-level geocoding is supported for both forward and reverse geocoding:

* **Forward geocoding:** When a secondary address component is provided, Geocodio looks up unit-specific coordinates and returns both the unit-level and building-level results
* **Reverse geocoding:** After finding a rooftop-level match, Geocodio searches for the nearest unit within proximity and enhances the result with unit-level data when available

> **Note:** Unit-level geocoding coverage depends on data availability for the specific address. When unit-level data is not available, the building-level result is returned as before. You can check the `match_type` field to determine whether a unit-level match was found.

### Geocoding with Unit Numbers

> To geocode an address with a Unit Number

```shell
  curl "https://api.geocod.io/v2/geocode?q=2800+Clarendon+Blvd+Suite+R500+Arlington+VA+22201&api_key=YOUR_API_KEY"
```

> Example response with Unit Number

```json
{
  "results": [
    {
      "address_components": {
        "number": "2800",
        "street": "Clarendon",
        "suffix": "Blvd",
        "unit_type": "Ste",
        "unit_number": "R500",
        "formatted_street": "Clarendon Blvd",
        "city": "Arlington",
        "county": "Arlington County",
        "state_province": "VA",
        "postal_code": "22201",
        "country": "US"
      },
      "address_lines": [
        "2800 Clarendon Blvd",
        "Ste R500",
        "Arlington, VA 22201"
      ],
      "formatted_address": "2800 Clarendon Blvd, Ste R500, Arlington, VA 22201",
      "location": {
        "lat": 38.887455,
        "lng": -77.092018
      },
      "accuracy": 1,
      "accuracy_type": "rooftop",
      "match_type": "unit",
      "source": "Arlington",
      "stable_address_key": "gcod_usnbfvbm5l57cc8b8bnfnyrua9ym3-d4e5f6"
    }
  ]
}
```

If you include an Apartment or Suite number along as a suffix to the street name, we will parse that number and return it as part of your response. It will be broken out into the `unit_type` and `unit_number` keys within `address_components`.

**For US addresses:** The `unit_type` value will be standardized based on USPS records, if the unit number is deemed mailable and valid.

E.g. if the unit number is inputted as `#R500`, the outputted value will be `Ste R500`.

In order to verify that the unit number is valid per USPS, you can request the [`zip4`](#usps-zip-4) field append and check the `exact_match` value. If it is set to `true`, it means that the unit number is recognized by USPS.

### Geocoding with distance calculation

> Geocode an address and calculate distances to multiple destinations:

```shell
curl "https://api.geocod.io/v2/geocode?q=1109+N+Highland+St%2c+Arlington+VA&destinations[]=38.8977,-77.0365,WhiteHouse&destinations[]=38.8895,-77.0353,WashingtonMonument&distance_mode=driving&api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

destinations = [
  '38.8977,-77.0365,WhiteHouse',
  '38.8895,-77.0353,WashingtonMonument'
]

response = geocodio.geocode(
  ['1109 N Highland St, Arlington VA'],
  [],
  nil,
  nil,
  destinations: destinations,
  distance_mode: :driving,
  distance_units: :miles
)
```

```python
from geocodio import Geocodio, DISTANCE_MODE_DRIVING, DISTANCE_UNITS_MILES

client = Geocodio("YOUR_API_KEY")

destinations = [
    "38.8977,-77.0365,WhiteHouse",
    "38.8895,-77.0353,WashingtonMonument"
]

response = client.geocode(
    "1109 N Highland St, Arlington VA",
    destinations=destinations,
    distance_mode=DISTANCE_MODE_DRIVING,
    distance_units=DISTANCE_UNITS_MILES
)

# Access distances from the first result
for destination in response.results[0].destinations:
    print(f"{destination.id}: {destination.distance_miles} miles")
```

```php
<?php
use Geocodio\Enums\DistanceMode;
use Geocodio\Enums\DistanceUnits;

$destinations = [
    '38.8977,-77.0365,WhiteHouse',
    '38.8895,-77.0353,WashingtonMonument'
];

$response = $geocoder->geocode(
    '1109 N Highland St, Arlington VA',
    destinations: $destinations,
    distanceMode: DistanceMode::Driving,
    distanceUnits: DistanceUnits::Miles
);
```

```javascript
const Geocodio = require('geocodio-library-node');
const { DistanceMode, DistanceUnits } = Geocodio;

const geocoder = new Geocodio('YOUR_API_KEY');

const destinations = [
  '38.8977,-77.0365,WhiteHouse',
  '38.8895,-77.0353,WashingtonMonument'
];

geocoder.geocode('1109 N Highland St, Arlington VA', [], null, {
    destinations: destinations,
    mode: DistanceMode.Driving,
    units: DistanceUnits.Miles
  })
  .then(response => {
    console.log(response.results[0].destinations);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example response with distances:

```json
{
  "results": [
    {
      "address_components": {
        "number": "1109",
        "predirectional": "N",
        "street": "Highland",
        "suffix": "St",
        "formatted_street": "N Highland St",
        "city": "Arlington",
        "county": "Arlington County",
        "state_province": "VA",
        "postal_code": "22201",
        "country": "US"
      },
      "formatted_address": "1109 N Highland St, Arlington, VA 22201",
      "location": {
        "lat": 38.886665,
        "lng": -77.094733
      },
      "accuracy": 1,
      "accuracy_type": "rooftop",
      "source": "Virginia GIS Clearinghouse",
      "destinations": [
        {
          "query": "38.8977,-77.0365,WhiteHouse",
          "id": "WhiteHouse",
          "location": [38.8977, -77.0365],
          "distance_miles": 3.8,
          "distance_km": 6.1,
          "duration_seconds": 720
        },
        {
          "query": "38.8895,-77.0353,WashingtonMonument",
          "id": "WashingtonMonument",
          "location": [38.8895, -77.0353],
          "distance_miles": 4.2,
          "distance_km": 6.8,
          "duration_seconds": 780
        }
      ]
    }
  ]
}
```

When `destinations[]` is provided, each geocoded result will include a `destinations` array containing the distance and duration (if using `driving` mode) to each destination location. This is useful for finding the nearest locations to a geocoded address.

See the [Distance](#distance) section for more details on distance calculation options and dedicated distance endpoints. To use Geocodio's Distance endpoints, you'll need to enable access on an API key level [via the dashboard](https://dash.geocod.io/apikey).

## Batch geocoding

> To perform batch geocoding:

```shell
curl -X POST \
  -H "Content-Type: application/json" \
  -d '["1109 N Highland St, Arlington VA", "525 University Ave, Toronto, ON, Canada", "Avenida Paseo De La Reforma 489, 06500 Ciudad De México, CMX", "4410 S Highway 17 92, Casselberry FL", "15000 NE 24th Street, Redmond WA", "17015 Walnut Grove Drive, Morgan Hill CA"]' \
  https://api.geocod.io/v2/geocode?api_key=YOUR_API_KEY
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

locations = geocodio.geocode(['1109 N Highland St, Arlington VA', '525 University Ave, Toronto, ON, Canada', 'Avenida Paseo De La Reforma 489, 06500 Ciudad De México, CMX', '4410 S Highway 17 92, Casselberry FL', '15000 NE 24th Street, Redmond WA', '17015 Walnut Grove Drive, Morgan Hill CA'])

```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

addresses = [
  '1109 N Highland St, Arlington VA',
  '525 University Ave, Toronto, ON, Canada',
  'Avenida Paseo De La Reforma 489, 06500 Ciudad De México, CMX',
  '4410 S Highway 17 92, Casselberry FL',
  '15000 NE 24th Street, Redmond WA',
  '17015 Walnut Grove Drive, Morgan Hill CA'
]

response = client.geocode(addresses)
# Results are returned in the same order as the input
for result in response.results:
    if result.response.results:
        print(result.response.results[0].formatted_address)
```

```php
<?php
$addresses = [
  '1109 N Highland St, Arlington VA',
  '525 University Ave, Toronto, ON, Canada',
  'Avenida Paseo De La Reforma 489, 06500 Ciudad De México, CMX',
  '4410 S Highway 17 92, Casselberry FL',
  '15000 NE 24th Street, Redmond WA',
  '17015 Walnut Grove Drive, Morgan Hill CA'
];
$response = $geocoder->geocode($addresses);
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocoder = new Geocodio('YOUR_API_KEY');

const addresses = [
  '1109 N Highland St, Arlington VA',
  '525 University Ave, Toronto, ON, Canada',
  'Avenida Paseo De La Reforma 489, 06500 Ciudad De México, CMX',
  '4410 S Highway 17 92, Casselberry FL',
  '15000 NE 24th Street, Redmond WA',
  '17015 Walnut Grove Drive, Morgan Hill CA'
];

geocoder.geocode(addresses)
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example response:

```json
{
  "results": [
    {
      "query": "1109 N Highland St, Arlington VA",
      "response": {
        "results": [
          {
            "address_components": {
              "number": "1109",
              "predirectional": "N",
              "street": "Highland",
              "suffix": "St",
              "formatted_street": "N Highland St",
              "city": "Arlington",
              "county": "Arlington County",
              "state_province": "VA",
              "postal_code": "22201",
              "country": "US"
            },
            "address_lines": [
              "1109 N Highland St",
              "",
              "Arlington, VA 22201"
            ],
            "formatted_address": "1109 N Highland St, Arlington, VA 22201",
            "location": {
              "lat": 38.886672,
              "lng": -77.094735
            },
            "accuracy": 1,
            "accuracy_type": "rooftop",
            "source": "Arlington"
          },
          {
            "address_components": {
              "number": "1109",
              "predirectional": "N",
              "street": "Highland",
              "suffix": "St",
              "formatted_street": "N Highland St",
              "city": "Arlington",
              "county": "Arlington County",
              "state_province": "VA",
              "postal_code": "22201",
              "country": "US"
            },
            "address_lines": [
              "1109 N Highland St",
              "",
              "Arlington, VA 22201"
            ],
            "formatted_address": "1109 N Highland St, Arlington, VA 22201",
            "location": {
              "lat": 38.886665,
              "lng": -77.094733
            },
            "accuracy": 1,
            "accuracy_type": "rooftop",
            "source": "Virginia Geographic Information Network (VGIN)"
          }
        ]
      }
    },
    {
      "query": "525 University Ave, Toronto, ON, Canada",
      "response": {
        "results": [
          {
            "address_components": {
              "number": "525",
              "street": "University",
              "suffix": "Ave",
              "formatted_street": "University Ave",
              "city": "Toronto",
              "state_province": "ON",
              "country": "CA"
            },
            "address_lines": [
              "525 University Ave",
              "",
              "Toronto, ON M5G"
            ],
            "formatted_address": "525 University Ave, Toronto, ON",
            "location": {
              "lat": 43.656258,
              "lng": -79.388223
            },
            "accuracy": 1,
            "accuracy_type": "rooftop",
            "source": "City of Toronto Open Data"
          }
        ]
      }
    },
    ...
  ]
}
```

If you have multiple addresses that you need to geocode, we recommend using Geocodio's batch geocoding endpoints. This will save you time as it removes the overhead of having to perform multiple `HTTP` requests.

Batch geocoding requests can be performed by making a `POST` request to the *geocode* endpoint, supplying a `JSON` array, or a `JSON` object in the body with any key of your choosing.

> **Warning:** You can process up to 10,000 lookups at a time with the batch endpoint. Field appends count as lookups, so geocoding 5,000 addresses with the `census` field append would be a total of 10,000 lookups. Geocoding 10,000 lookups takes about 600 seconds, so please make sure to adjust your timeout value accordingly. For large lists, consider using the lists API.

### Understanding Lookup Counts

Each address counts as one lookup, and each field append counts as an additional lookup per address.

**Lookup Calculation Formula:**
```
Total Lookups = Number of Addresses × (1 + Number of Fields)
```

**Examples within the 10,000 limit:**

* ✅ 10,000 addresses, no fields = 10,000 lookups
* ✅ 5,000 addresses, 1 field = 10,000 lookups (5,000 × 2)
* ✅ 2,500 addresses, 3 fields = 10,000 lookups (2,500 × 4)
* ✅ 2,000 addresses, 4 fields = 10,000 lookups (2,000 × 5)

**Examples exceeding the limit:**

* ❌ 10,000 addresses, 1 field = 20,000 lookups (exceeds limit)
* ❌ 6,000 addresses, 2 fields = 18,000 lookups (exceeds limit)

> **Warning:** Plan your batch requests carefully when using field appends. If you need to process more than 10,000 lookups, split your request into multiple batches or use the [lists API](#geocoding-lists) instead.

### HTTP Request

`POST https://api.geocod.io/v2/geocode`

### URL Parameters

Parameter | Description
--------- | -----------
`api_key` | Your Geocodio API key
`fields`  | Optional parameter to request [additional field appends](#data-appends-fields).
`limit`   | Optional parameter. The maximum number of results to return. The default is no limit. If set to 0, no limit will be applied.
`destinations[]` | Optional parameter. Array of destination locations for [distance calculation](#distance). When provided, each result will include a `destinations` array with distance/duration to each destination.
`distance_mode` | Optional parameter. Distance calculation mode: `driving` or `straightline`. Default is `straightline`.
`distance_units` | Optional parameter. Unit of measurement: `miles` or `km`. Default is `miles`.
`distance_max_results` | Optional parameter. Maximum number of destinations to return per geocoded result.
`distance_max_distance` | Optional parameter. Maximum distance filter (in specified units).
`distance_min_distance` | Optional parameter. Minimum distance filter (in specified units).
`distance_max_duration` | Optional parameter. Maximum duration filter in seconds (driving mode only).
`distance_min_duration` | Optional parameter. Minimum duration filter in seconds (driving mode only).
`distance_order_by` | Optional parameter. Sort destinations by `distance` or `duration`. Default is `distance`.
`distance_sort_order` | Optional parameter. Sort order: `asc` or `desc`. Default is `asc`.

### JSON array/object
When making a batch geocoding request, you can `POST` queries as either a JSON array or a JSON object. If a JSON object is posted, you can specify a custom key for each element of your choice. This can be useful to match queries up with your existing data after the request is complete.

If using a JSON array, results are **guaranteed** to be returned in the same order as they are requested.

You can also use the alternative parameters with batch geocoding; just pass an associative array instead of a string for each address. This is also how you set a `country` for an individual entry, which is required for any address whose country cannot be inferred from the query on its own — see [JSON object with parameters](#json-object-with-parameters).

Here's a couple of examples of what the `POST` body can look like:

### JSON array

```json
[
  "1109 N Highland St, Arlington VA",
  "525 University Ave, Toronto, ON, Canada",
  "Avenida Paseo De La Reforma 489, 06500 Ciudad De México, CMX",
  "4410 S Highway 17 92, Casselberry FL",
  "15000 NE 24th Street, Redmond WA",
  "17015 Walnut Grove Drive, Morgan Hill CA"
]
```

> Example response when POST'ing JSON object:

```json
{
  "results": {
    "FID1": {
      "query": "1109 N Highland St, Arlington VA",
      "response": {
        "results": [
          {
            "address_components": {
              "number": "1109",
              "predirectional": "N",
              "street": "Highland",
              "suffix": "St",
              "formatted_street": "N Highland St",
              "city": "Arlington",
              "county": "Arlington County",
              "state_province": "VA",
              "postal_code": "22201",
              "country": "US"
            },
            "address_lines": [
              "1109 N Highland St",
              "",
              "Arlington, VA 22201"
            ],
            "formatted_address": "1109 N Highland St, Arlington, VA 22201",
            "location": {
              "lat": 38.886672,
              "lng": -77.094735
            },
            "accuracy": 1,
            "accuracy_type": "rooftop",
            "source": "Arlington"
          }
        ]
      }
    },
    "FID2": {
     ...
    },
    "FID3": {
     ...
    },
    "FID4": {
     ...
    },
    "FID5": {
     ...
    },
    "FID6": {
     ...
    }
  }
}
```

### JSON object

```json
{
  "FID1": "1109 N Highland St, Arlington VA",
  "FID2": "525 University Ave, Toronto, ON, Canada",
  "FID3": "Avenida Paseo De La Reforma 489, 06500 Ciudad De México, CMX",
  "FID4": "4410 S Highway 17 92, Casselberry FL",
  "FID5": "15000 NE 24th Street, Redmond WA",
  "FID6": "17015 Walnut Grove Drive, Morgan Hill CA"
}
```

### JSON object with parameters

```json
{
  "1": {
    "street": "1109 N Highland St",
    "city": "Arlington",
    "state_province": "VA"
  },
  "2": {
    "city": "Toronto",
    "country": "CA"
  },
  "3": {
    "street": "Avenida Paseo De La Reforma 489",
    "city": "Ciudad De México",
    "state_province": "CMX",
    "postal_code": "06500",
    "country": "Mexico"
  },
  "4": {
    "street": "10 Downing Street",
    "city": "London",
    "postal_code": "SW1A 2AA",
    "country": "GB"
  }
}
```

### Accepted Address Components

When supplying an address as individual components (instead of a single string) you can use a combination of `addressee`, `street`, `street2`, `city`, `county`, `state_province`, `postal_code`, and/or `country`.

This is recommended if the address is already stored as separate fields on your end.

Parameter     | Description
------------- | -----------
`addressee`   | Optional. E.g. Apple Inc. The recipient, business, or firm name. Used to return a more precise [USPS ZIP+4 code](#usps-zip-4) for businesses. See [The `addressee` parameter](#the-addressee-parameter)
`street`      | E.g. 1600 Pennsylvania Ave NW
`street2`     | E.g. Apt 204
`city`        | E.g. Washington
`county`      | E.g. Arlington
`state_province` | E.g. DC
`postal_code` | E.g. 20500
`country`     | E.g. Canada, Mexico, GB. Defaults to USA. See [Supported Countries](#supported-countries) for the accepted values

# Reverse Geocoding

Reverse geocoding is the process of converting latitude and longitude into a street address.

Geocodio will find matching street(s) and determine the correct house number based on the location. Note that Geocodio does not guarantee to return a valid house number; it is our closest approximation.

As with forward geocoding, you can either geocode a single set of coordinates at the time or collect multiple coordinates in batches. You can batch reverse geocode up to 10,000 coordinates at a time.

This endpoint can return up to 5 possible matches ranked and ordered by an [accuracy score](#accuracy-score).

> **Tip:** A geographic coordinate consists of latitude followed by longitude separated by a comma, for example `38.9002898,-76.9990361`

## Reverse geocoding single coordinate

> To reverse geocode a single coordinate:

```shell
# A coordinate in Washington, DC
curl "https://api.geocod.io/v2/reverse?q=38.9002898,-76.9990361&api_key=YOUR_API_KEY"

# A coordinate in Toronto, ON
curl "https://api.geocod.io/v2/reverse?q=43.65625,-79.38822&api_key=YOUR_API_KEY"

# A coordinate in Ciudad De México, CMX
curl "https://api.geocod.io/v2/reverse?q=19.424056,-99.174903&api_key=YOUR_API_KEY"

# A coordinate in London, England
curl "https://api.geocod.io/v2/reverse?q=51.503541,-0.12767&api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

addresses = geocodio.reverse(['38.9002898,-76.9990361'])
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

response = client.reverse("38.9002898,-76.9990361")
# Or using a tuple
# response = client.reverse((38.9002898, -76.9990361))

# Access the first result
print(response.results[0].formatted_address)
```

```php
<?php
$response = $geocoder->reverse('38.9002898,-76.9990361');
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocoder = new Geocodio('YOUR_API_KEY');

geocoder.reverse('38.9002898,-76.9990361')
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example response:

```json
{
  "results": [
    {
      "address_components": {
        "number": "508",
        "street": "H",
        "suffix": "St",
        "postdirectional": "NE",
        "formatted_street": "H St NE",
        "city": "Washington",
        "county": "District of Columbia",
        "state_province": "DC",
        "postal_code": "20002",
        "country": "US"
      },
      "address_lines": [
        "508 H St NE",
        "",
        "Washington, DC 20002"
      ],
      "formatted_address": "508 H St NE, Washington, DC 20002",
      "location": {
        "lat": 38.900432,
        "lng": -76.999031
      },
      "accuracy": 1,
      "accuracy_type": "rooftop",
      "source": "City of Washington"
    },
    {
      "address_components": {
        "number": "510",
        "street": "H",
        "suffix": "St",
        "postdirectional": "NE",
        "formatted_street": "H St NE",
        "city": "Washington",
        "county": "District of Columbia",
        "state_province": "DC",
        "postal_code": "20002",
        "country": "US"
      },
      "address_lines": [
        "510 H St NE",
        "",
        "Washington, DC 20002"
      ],
      "formatted_address": "510 H St NE, Washington, DC 20002",
      "location": {
        "lat": 38.900429,
        "lng": -76.998965
      },
      "accuracy": 0.9,
      "accuracy_type": "rooftop",
      "source": "City of Washington"
    },
    ...
  ]
}
```

A single coordinate can be reverse geocoded by making a simple `GET` request to the *reverse* endpoint, you can [try this in your browser right now](https://api.geocod.io/v2/reverse?q=38.9002898,-76.9990361&api_key=YOUR_API_KEY).

### HTTP Request

`GET https://api.geocod.io/v2/reverse`

### URL Parameters

Parameter | Description
--------- | -----------
`q`       | The query (i.e. latitude/longitude pair) to geocode. The coordinate pair should be comma-separated
`api_key` | Your Geocodio API key
`fields`  | Optional parameter to request [additional field appends](#data-appends-fields).
`limit`   | Optional parameter. The maximum number of results to return. The default is no limit. If set to 0, no limit will be applied.
`format`  | Optional parameter to change the JSON output format to a different pre-defined structure. Currently, "simple" is the only valid value. If not set, the default full JSON output structure is used.
`destinations[]` | Optional parameter. Array of destination locations for [distance calculation](#distance). When provided, each result will include a `destinations` array with distance/duration to each destination.
`distance_mode` | Optional parameter. Distance calculation mode: `driving` or `straightline`. Default is `straightline`.
`distance_units` | Optional parameter. Unit of measurement: `miles` or `km`. Default is `miles`.
`distance_max_results` | Optional parameter. Maximum number of destinations to return per result.
`distance_max_distance` | Optional parameter. Maximum distance filter (in specified units).
`distance_min_distance` | Optional parameter. Minimum distance filter (in specified units).
`distance_max_duration` | Optional parameter. Maximum duration filter in seconds (driving mode only).
`distance_min_duration` | Optional parameter. Minimum duration filter in seconds (driving mode only).
`distance_order_by` | Optional parameter. Sort destinations by `distance` or `duration`. Default is `distance`.
`distance_sort_order` | Optional parameter. Sort order: `asc` or `desc`. Default is `asc`.
`skipGeocoding` | Optional parameter. When set to `true` (or empty value), skips the reverse geocoding step and applies [field appends](#data-appends-fields) directly to the supplied coordinates. The `fields` parameter is required when using `skipGeocoding`. See [Skip Geocoding (extracting field data from coordinates)](#skip-geocoding-extracting-field-data-from-coordinates) for more details.

### The `format` parameter

```ruby
#  To receive a `simple` response, include the string `"simple"`
#  as the fourth argument after any fields or limit parameters
#  you have set.

  require 'geocodio/gem'

  geocodio = Geocodio::Gem.new('YOUR_API_KEY')

  response = geocodio.reverse(["38.9002898,-76.9990361"], [], nil, "simple")
```

> Example response, when `format` is set to `simple`:

```json
{
  "address": "508 H St NE, Washington, DC 20002",
  "lat": 38.900432,
  "lng": -76.999031,
  "accuracy": 1,
  "accuracy_type": "rooftop",
  "source": "Statewide"
}
```

> Example response, when `format` is set to `simple` and no results are found:

```json
{
  "address": null,
  "lat": null,
  "lng": null,
  "accuracy": null,
  "accuracy_type": null,
  "source": null
}
```

In most cases, the standard output format would be used. In certain situations, it can however be beneficial to work with a JSON structure that is specifically designed for your use case.

**`simple` format**

When `format` is set to `simple`, a very simple JSON structure is outputted, with only basic information for the best matched results. This makes it much easier to work with the JSON document in situations where extra verbosity is not needed.

The `fields` parameter is still supported when the `simple` output format is selected, but the `limit` parameter has no effect.

## Batch reverse geocoding

> To perform batch reverse geocoding:

```shell
curl -X POST \
  -H "Content-Type: application/json" \
  -d '["35.9746000,-77.9658000","32.8793700,-96.6303900","33.8337100,-117.8362320","43.65625,-79.38822","19.424056,-99.174903","51.503541,-0.12767","35.4171240,-80.6784760"]' \
  https://api.geocod.io/v2/reverse?api_key=YOUR_API_KEY
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

address_sets = geocodio.reverse(['35.9746000,-77.9658000', '32.8793700,-96.6303900', '33.8337100,-117.8362320', '43.65625,-79.38822', '19.424056,-99.174903', '51.503541,-0.12767', '35.4171240,-80.6784760'])
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

coordinates = [
  "35.9746000,-77.9658000",
  "32.8793700,-96.6303900",
  "33.8337100,-117.8362320",
  "43.65625,-79.38822",
  "19.424056,-99.174903",
  "51.503541,-0.12767",
  "35.4171240,-80.6784760"
]
# Or using tuples
# coordinates = [
#   (35.9746000, -77.9658000),
#   (32.8793700, -96.6303900),
#   (33.8337100, -117.8362320),
#   (43.65625, -79.38822),
#   (19.424056, -99.174903),
#   (51.503541, -0.12767),
#   (35.4171240, -80.6784760),
# ]

response = client.reverse(coordinates)
# Results are returned in the same order as the input
for result in response.results:
    if result.response.results:
        print(result.response.results[0].formatted_address)
```

```php
<?php
$coordinates = [
  '35.9746000,-77.9658000',
  '32.8793700,-96.6303900',
  '33.8337100,-117.8362320',
  '43.65625,-79.38822',
  '19.424056,-99.174903',
  '51.503541,-0.12767',
  '35.4171240,-80.6784760'
];
$results = $geocoder->reverse($coordinates);
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocoder = new Geocodio('YOUR_API_KEY');

const coordinates = [
  '35.9746000,-77.9658000',
  '32.8793700,-96.6303900',
  '33.8337100,-117.8362320',
  '43.65625,-79.38822',
  '19.424056,-99.174903',
  '51.503541,-0.12767',
  '35.4171240,-80.6784760'
];

geocoder.reverse(coordinates)
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example response (shortened for brevity):

```json
{
  "results": [
    {
      "query": "35.9746000,-77.9658000",
      "response": {
        "results": [
          {
            "address_components": {
              "number": "101",
              "predirectional": "W",
              "street": "Washington",
              "suffix": "St",
              "formatted_street": "W Washington St",
              "city": "Nashville",
              "county": "Nash County",
              "state_province": "NC",
              "postal_code": "27856",
              "country": "US"
            },
            "address_lines": [
              "101 W Washington St",
              "",
              "Nashville, NC 27856"
            ],
            "formatted_address": "101 W Washington St, Nashville, NC 27856",
            "location": {
              "lat": 35.974357,
              "lng": -77.966064
            },
            "accuracy": 1,
            "accuracy_type": "rooftop",
            "source": "NC Geographic Information Coordinating Council"
          }
        ]
      }
    },
    {
      "query": "32.8793700,-96.6303900",
      "response": {
        "results": [
          {
            "address_components": {
              "number": "3034",
              "predirectional": "S",
              "street": "1st",
              "suffix": "St",
              "formatted_street": "S 1st St",
              "city": "Garland",
              "county": "Dallas County",
              "state_province": "TX",
              "postal_code": "75041",
              "country": "US"
            },
            "address_lines": [
              "3034 S 1st St",
              "",
              "Garland, TX 75041"
            ],
            "formatted_address": "3034 S 1st St, Garland, TX 75041",
            "location": {
              "lat": 32.879386,
              "lng": -96.630471
            },
            "accuracy": 1,
            "accuracy_type": "rooftop",
            "source": "City of Garland"
          },
          ...
        ]
      }
    },
    ...
  ]
}
```

If you have several coordinates that you need to reverse geocode, batch reverse geocoding is a much faster option since it removes the overhead of having to perform multiple `HTTP` requests.

Batch reverse geocoding requests are performed by making a `POST` request to the *reverse* endpoint, supplying a `JSON` array in the body.

> **Warning:** You can batch reverse geocode up to 10,000 coordinates at a time. Field appends count as lookups as well, make sure to keep the overall number of lookups at 10,000 or below.

### HTTP Request

`POST https://api.geocod.io/v2/reverse`

### URL Parameters

Parameter | Description
--------- | -----------
`api_key` | Your Geocodio API key
`fields`  | Optional parameter to request [additional field appends](#data-appends-fields).
`limit`   | Optional parameter. The maximum number of results to return. The default is no limit. If set to 0, no limit will be applied.
`destinations[]` | Optional parameter. Array of destination locations for [distance calculation](#distance). When provided, each result will include a `destinations` array with distance/duration to each destination.
`distance_mode` | Optional parameter. Distance calculation mode: `driving` or `straightline`. Default is `straightline`.
`distance_units` | Optional parameter. Unit of measurement: `miles` or `km`. Default is `miles`.
`distance_max_results` | Optional parameter. Maximum number of destinations to return per result.
`distance_max_distance` | Optional parameter. Maximum distance filter (in specified units).
`distance_min_distance` | Optional parameter. Minimum distance filter (in specified units).
`distance_max_duration` | Optional parameter. Maximum duration filter in seconds (driving mode only).
`distance_min_duration` | Optional parameter. Minimum duration filter in seconds (driving mode only).
`distance_order_by` | Optional parameter. Sort destinations by `distance` or `duration`. Default is `distance`.
`distance_sort_order` | Optional parameter. Sort order: `asc` or `desc`. Default is `asc`.
`skipGeocoding` | Optional parameter. When set to `true` (or empty value), skips the reverse geocoding step and applies [field appends](#data-appends-fields) directly to the supplied coordinates. The `fields` parameter is required when using `skipGeocoding`. See [Skip Geocoding (extracting field data from coordinates)](#skip-geocoding-extracting-field-data-from-coordinates) for more details.

# Geocoding lists

Geocodio's lists API lets you geocode CSV, TSV, Excel, and other forms of spreadsheets with addresses or coordinates. Similar to the [spreadsheet geocoding tool](https://www.geocod.io/upload/), the spreadsheet will be processed as a job on Geocodio's infrastructure and can be downloaded later. While a spreadsheet is being, processed it is possible to query the status and progress.

> **Warning:** Data for spreadsheets processed through the lists API is automatically deleted 72 hours after processing completes. In addition to a 1GB file size limit, we recommend a maximum of 10M lookups per list batch. Larger batches should be split up into multiple list jobs.

## Create a new list

> Create a new list from a file called "[sample_list.csv](https://www.geocod.io/sample_list.csv)"

```shell
curl "https://api.geocod.io/v2/lists?api_key=YOUR_API_KEY" \
  -F "file"="@sample_list.csv" \
  -F "direction"="forward" \
  -F "format"="{{A}} {{B}} {{C}} {{D}}" \
  -F "callback"="https://example.com/my-callback"
```

```ruby
  require 'geocodio/gem'

  geocodio = Geocodio::Gem.new('YOUR_API_KEY')

  response = geocodio.createList(File.read("sample_list_test.csv"), "sample_list_test.csv", "forward", "{{A}} {{B}} {{C}} {{D}}")
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

# Create a list from a CSV file
with open('sample_list.csv', 'rb') as file:
    response = client.create_list(
        file=file,
        filename='sample_list.csv',
        direction='forward',
        format='{{A}} {{B}} {{C}} {{D}}',
        callback='https://example.com/my-callback'  # Optional
    )
    list_id = response.id
```

```php
<?php

$response = $geocoder->uploadList(
    file: 'sample_list_test.csv',
    direction: GeocodeDirection::Forward,
    format: '{{B}} {{C}} {{D}} {{E}}',
    callbackWebhook: 'https://example.com/callbacks/list-upload',
);
```

```javascript
  const Geocodio = require('geocodio-library-node');
  const geocoder = new Geocodio('YOUR_API_KEY');

  geocoder.list.create(
  `${__dirname}/stubs/sample_list.csv`,
  "forward",
  "{{A}} {{B}} {{C}} {{D}}",
  "https://example.com/my-callback"
  )
```

> Create a new list from inline data

```shell
curl "https://api.geocod.io/v2/lists?api_key=YOUR_API_KEY" \
  -F "file"=$'Zip\n20003\n20001' \
  -F "filename"="file.csv" \
  -F "direction"="forward" \
  -F "format"="{{A}}" \
  -F "callback"="https://example.com/my-callback"
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

# Upload a list from inline data
csv_data = """Zip
20003
20001"""

response = client.create_list(
    file=csv_data.encode('utf-8'),
    filename='file.csv',
    direction='forward',
    format='{{A}}',
    callback='https://example.com/my-callback'  # Optional
)
list_id = response.id
```

```php
<?php

// Upload a list from inline data
$csvData = <<<'CSV'
name,street,city,state,zip
"Peregrine Espresso","660 Pennsylvania Ave SE",Washington,DC,20003
"Lot 38 Espresso Bar","1001 2nd St SE",Washington,DC,20003
CSV;

$geocodio->uploadInlineList(
    $csvData,
    'coffee-shops.csv',
    GeocodeDirection::Forward,
    '{{B}} {{C}} {{D}} {{E}}'
);
```

> Example response:

```json
{
    "id": 48,
    "file":
    {
        "headers":
        [
            "address",
            "city",
            "state",
            "zip"
        ],
        "estimated_rows_count": 24,
        "filename": "sample_list.csv"
    }
}
```

Creates a new spreadsheet list job and starts processing the list in the background. The response returns a list id that can be used to retrieve the job progress as well as download the processed list when it has completed.

### HTTP Request

`POST https://api.geocod.io/v2/lists`

### URL Parameters

Parameter | Description
--------- | -----------
`api_key` | Your Geocodio API key
`fields`  | Optional parameter to request [additional field appends](#data-appends-fields)

### Data Parameters

Parameter   | Description
----------- | -----------
`file`      | The file to geocoded, can be uploaded as a form-data file or sent inline
`filename`  | Only required if file contents are sent inline, file extension is used to determine file format so it can be processed correctly. Valid file formats include csv, tsv, xls, xlsx. A zip file can also be uploaded, it needs to contain exactly one file of the supported extensions
`direction` | Can either be `forward` for address to coordinate geocoding or `reverse` for coordinate to address geocoding
`format`    | A template for how addresses or coordinates should be read from the spreadsheet, see more below
`callback`  | Optional. A valid URL that a webhook should be sent to upon completion of the spreadsheet geocoding job

### `format` syntax

The `format` parameter uses a simple templating syntax that is used to construct a full address or coordinate for geocoding. A column can be referenced by its letter, encapsulated in double curly brackets, e.g. `{{A}}`.

**Examples:***

* The full address can be found in column `A`: `{{A}}`
* The street addresses are in column `A` and the zip codes are in column `D`: `{{A}} {{D}}`
* Street addresses are column `A`. They are all located in Washington D.C: `{{A}} Washington DC`
* The spreadsheet has a list of Canadian addresses with street addreses in column `A`, city name in column `B` and province name in column `C`: `{{A}} {{B}} {{C}} Canada`
* The spreadsheet has a list of Mexican addresses with street addresses in column `A`, city name in column `B` and state in column `C`: `{{A}} {{B}} {{C}} Mexico`
* The spreadsheet has a list of UK addresses with street addresses in column `A`, city name in column `B` and postcode in column `C`: `{{A}} {{B}} {{C}} GB`
* For reverse geocoding, latitude is in column `A` and longitude in column `B`: `{{A}},{{B}}`

### Callback

> Example webhook `POST` data

```json
{
    "id": 49,
    "fields": ["cd"],
    "file": {
        "geocoded_rows_count": 39809,
        "filename": "sample_list.csv"
    },
    "download_url": "https://api.geocod.io/v2/lists/49/download"
}
```

The callback url is an optional method to receive a notification when a spreadsheet geocoding job has completed.

The webhook is sent as a `POST` request, it needs to be publicly accessible and the URL is served over HTTPS, the SSL certificate has to be valid and active.
A total of 3 attempts are made to delivery the webhook.

## See list status

> Show status for list id 42

```shell
curl "https://api.geocod.io/v2/lists/42?api_key=YOUR_API_KEY"
```

```ruby
  require 'geocodio/gem'
  geocodio = Geocodio::Gem.new('YOUR_API_KEY')

  response = geocodio.getList(42)
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

# Get status of a list
response = client.get_list(42)
print(response.status.state)  # 'UPLOADED', 'ENQUEUED', 'PROCESSING', 'COMPLETED', or 'FAILED'
print(response.status.progress)  # Progress percentage
```

```php
<?php

$response = $geocoder->listStatus(42);
```

```javascript
  const Geocodio = require('geocodio-library-node');
  const geocoder = new Geocodio('YOUR_API_KEY');

  geocoder.list.status(42)
  .then(response => { ... })
  .catch(err => { ... });
```

> Example response (list that just started processing)

```json
{
    "id": 42,
    "fields": [],
    "file": {
        "estimated_rows_count": 39809,
        "filename": "bigger_list.csv"
    },
    "status": {
        "state": "PROCESSING",
        "progress": 1,
        "message": "Processing",
        "time_left_description": "Estimating time to complete",
        "time_left_seconds": null
    },
    "download_url": null,
    "expires_at": "2021-09-23T18:23:29.000000Z"
}

```

> Example response (list that is currently processing)

```json
{
    "id": 42,
    "fields": [],
    "file": {
        "estimated_rows_count": 39809,
        "filename": "bigger_list.csv"
    },
    "status": {
        "state": "PROCESSING",
        "progress": 12.82,
        "message": "Geocoding",
        "time_left_description": "17 min. left",
        "time_left_seconds": 1072
    },
    "download_url": null,
    "expires_at": "2021-09-23T18:23:29.000000Z"
}

```

> Example response (list that has been fully processed):

```json
{
    "id": 42,
    "fields": [],
    "file": {
        "estimated_rows_count": 39809,
        "filename": "bigger_list.csv"
    },
    "status": {
        "state": "COMPLETED",
        "progress": 100,
        "message": "Completed",
        "time_left_description": null,
        "time_left_seconds": null
    },
    "download_url": "https://api.geocod.io/v2/lists/42/download",
    "expires_at": "2021-09-23T18:23:29.000000Z"
}
```

View the metadata and status for a single uploaded list.

### HTTP Request

`GET https://api.geocod.io/v2/lists/LIST_ID`

### URL Parameters

Parameter | Description
--------- | -----------
`api_key` | Your Geocodio API key
`page`    | The page number to show

### List status values

Status | Description
------ | -----------
`UPLOADED` | File has been received and stored, not yet queued for processing
`ENQUEUED` | List is waiting for a processing slot to free up
`PROCESSING` | List is currently being processed
`COMPLETED` | List is complete, results available for download
`FAILED` | List processing failed

## Concurrent list processing

Geocodio limits how many of an account's lists are processed at the same time. Pay-as-you-go and Flex plans process 1 list at a time. Plans with a dedicated instance (Unlimited, Enterprise Unlimited) process up to 3 lists concurrently per instance — accounts with multiple instances in their spreadsheet pool get 3 per instance. This limit is shared across the whole billing account: lists started from the Geocodio dashboard use the same processing slots as lists created through the API.

> **Note:** Submitting a list while others are already processing is never rejected — `POST /lists` always accepts the upload. The new list is simply held in the `ENQUEUED` state (see [List status values](#list-status-values)) until a processing slot frees up, then it moves to `PROCESSING` automatically. This is expected behavior, not an error, and doesn't require any retry logic on your end. There is currently no field in the API that reports your account's concurrency limit or a list's position in the queue.

## Show all lists

> Show all lists

```shell
curl "https://api.geocod.io/v2/lists?api_key=YOUR_API_KEY"
```

```ruby
  require 'geocodio/gem'
  geocodio = Geocodio::Gem.new('YOUR_API_KEY')

  response = geocodio.getAllLists
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

# Get all lists
response = client.get_all_lists()
for list_item in response.data:
    print(f"List {list_item.id}: {list_item.file.filename} - {list_item.status.state}")
```

```php
<?php

$response = $geocoder->lists();
```

```javascript
  const Geocodio = require('geocodio-library-node');
  const geocoder = new Geocodio('YOUR_API_KEY');

  geocoder.list.all()
  .then(response => { ... })
  .catch(err => { ... });
```
> Example response:

```json
{
    "current_page": 1,
    "data":
    [
        {
            "id": 48,
            "fields":
            [],
            "file":
            {
                "estimated_rows_count": 24,
                "filename": "sample_list.csv"
            },
            "status":
            {
                "state": "COMPLETED",
                "progress": 100,
                "message": "Completed",
                "time_left_description": null,
                "time_left_seconds": null
            },
            "download_url": "https://api.geocod.io/v2/lists/48/download",
            "expires_at": "2021-09-23T12:09:09.000000Z"
        },
        ...
    ],
    "first_page_url": "https://api.geocod.io/v2/lists?page=1",
    "from": 1,
    "next_page_url": "https://api.geocod.io/v2/lists?page=2",
    "path": "https://api.geocod.io/v2/lists",
    "per_page": 15,
    "prev_page_url": null,
    "to": 15
}
```

Show all lists that have been created. The endpoint is paginated, showing 15 lists at a time, ordered by recency.

### HTTP Request

`GET https://api.geocod.io/v2/lists`

### URL Parameters

Parameter | Description
--------- | -----------
`api_key` | Your Geocodio API key

## Download a list

```shell
curl -L "https://api.geocod.io/v2/lists/LIST_ID/download?api_key=YOUR_API_KEY"
```

```ruby
  require 'geocodio/gem'
  geocodio = Geocodio::Gem.new('YOUR_API_KEY')

  response = geocodio.downloadList(42)
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

# Download a completed list
csv_content = client.download_list(42)
# Save to file
with open('geocoded_results.csv', 'w') as f:
    f.write(csv_content)
```

```php
<?php

$response = $geocoder->downloadList(42, 'path/to/file.csv');
```

```javascript
  const Geocodio = require('geocodio-library-node');
  const geocoder = new Geocodio('YOUR_API_KEY');

  geocoder.list.download(42, "geocoded_file.csv")
   .then(response => { ...})
   .catch(err => { ... });
```

> Example response:

```csv
address,city,state,zip,Latitude,Longitude,"Accuracy Score","Accuracy Type",Number,Street,"Unit Type","Unit Number",City,State,County,Zip,Country,Source
"660 Pennsylvania Ave SE",Washington,DC,20003,38.885172,-76.996565,1,rooftop,660,"Pennsylvania Ave SE",,,Washington,DC,"District of Columbia",20003,US,Statewide
"1718 14th St NW",Washington,DC,20009,38.913274,-77.032266,1,rooftop,1718,"14th St NW",,,Washington,DC,"District of Columbia",20009,US,Statewide
"1309 5th St NE",,,20002,38.908724,-76.997653,0.9,rooftop,1309,"5th St NE",,,Washington,DC,"District of Columbia",20002,US,Statewide
"2150 P St NW",,,20037,38.90948,-77.048527,1,rooftop,2150,"P St NW",,,Washington,DC,"District of Columbia",20037,US,Statewide
"201 F Street NE",,,20002,38.897139,-77.003286,0.9,rooftop,201,"F St NE",,,Washington,DC,"District of Columbia",20002,US,Statewide
"1001 2nd St SE",,,20003,38.877737,-77.003695,1,rooftop,1001,"2nd St SE",,,Washington,DC,"District of Columbia",20003,US,Statewide
"1645 Wisconsin Avenue NW",Washington,DC,20007,38.911626,-77.065281,1,rooftop,1645,"Wisconsin Ave NW",,,Washington,DC,"District of Columbia",20007,US,Statewide
"820 East Baltimore Street",Baltimore,MD,21202,39.290427,-76.60485,1,rooftop,820,"E Baltimore St",,,Baltimore,MD,"Baltimore City",21202,US,"City of Baltimore"
"800 F St NW",Washington,DC,20001,38.896987,-77.023286,1,rooftop,800,"F St NW",,,Washington,DC,"District of Columbia",20004,US,Statewide
"700 Constitution Avenue NW",Washington,DC,20565,38.892228,-77.0219,0.9,range_interpolation,700,"Constitution Ave NW",,,Washington,DC,"District of Columbia",20002,US,"TIGER/Line® dataset from the US Census Bureau"
"1123 Pennsylvania Ave SE",Washington,DC,20003,38.882097,-76.990714,1,rooftop,1123,"Pennsylvania Ave SE",,,Washington,DC,"District of Columbia",20003,US,Statewide
"621 Pennsylvania Ave SE",Washington,DC,20003,38.884906,-76.997682,1,rooftop,621,"Pennsylvania Ave SE",,,Washington,DC,"District of Columbia",20003,US,Statewide
"1702 G Street NW",Washington,DC,20006,38.89816,-77.039982,1,rooftop,1702,"G St NW",,,Washington,DC,"District of Columbia",20006,US,Statewide
"701 8th St SE",Washington,DC,20003,38.881115,-76.995245,1,rooftop,701,"8th St SE",,,Washington,DC,"District of Columbia",20003,US,Statewide
"12187 Darnestown Rd",Gaithersburg,MD,20878,39.118169,-77.251699,1,rooftop,12187,"Darnestown Rd",,,Gaithersburg,MD,"Montgomery County",20878,US,Montgomery
"4961 Elm Street",Bethesda,MD,,38.982196,-77.098161,1,rooftop,4961,"Elm St",,,Bethesda,MD,"Montgomery County",20814,US,Montgomery
"3064 Mount Pleasant St NW",Washington,DC,,38.92846,-77.037509,1,rooftop,3064,"Mt Pleasant St NW",,,Washington,DC,"District of Columbia",20009,US,Statewide
"1052 Thomas Jefferson Street NW",Washington,DC,,38.903887,-77.060437,1,rooftop,1052,"Thomas Jefferson St NW",,,Washington,DC,"District of Columbia",20007,US,Statewide
"475 H St NW",Washington,DC,,38.900078,-77.018645,1,rooftop,475,"H St NW",,,Washington,DC,"District of Columbia",20001,US,Statewide
"1301 U St NW",Washington,DC,,38.917294,-77.03052,1,rooftop,1301,"U St NW",,,Washington,DC,"District of Columbia",20009,US,Statewide
"1726 20th Street, NW",Washington,DC,,38.913694,-77.045095,1,rooftop,1726,"20th St NW",,,Washington,DC,"District of Columbia",20009,US,Statewide
"1916 I Street, NW",Washington,DC,,38.90115,-77.044172,1,rooftop,1916,"I St NW",,,Washington,DC,"District of Columbia",20006,US,Statewide
"107 Church St NE",Vienna,VA,,38.902565,-77.265693,1,rooftop,107,"Church St NE",,,Vienna,VA,"Fairfax County",22180,US,Fairfax
"4817 Bethesda Ave",Bethesda,MD,20814,38.981067,-77.096506,1,rooftop,4817,"Bethesda Ave",,,Bethesda,MD,"Montgomery County",20814,US,Montgomery
```

> Example response (trying to download a list that is still processing):

```json
{
    "message": "List is still processing",
    "success": false
}

```

Download a fully geocoded list, the returned format will always be a UTF-8 encoded, comma-separated csv file.

The response may be a `Redirect` HTTP header, so it is important to configure your HTTP client to follow redirects.

See our [spreadsheet output guide](/guides/data-matching-overview/) for a reference of the outputted columns.

### HTTP Request

`GET https://api.geocod.io/v2/lists/LIST_ID/download`

### URL Parameters

Parameter | Description
--------- | -----------
`api_key` | Your Geocodio API key

## Delete a list

```shell
curl -X DELETE "https://api.geocod.io/v2/lists/LIST_ID?api_key=YOUR_API_KEY"
```

```ruby
  require 'geocodio/gem'
  geocodio = Geocodio::Gem.new('YOUR_API_KEY')

  response = geocodio.deleteList(42)
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

# Delete a list
response = client.delete_list(42)
print(response.success)  # True if successful
```

```php
<?php

$response = $geocoder->deleteList(42);
```

```javascript
  const Geocodio = require('geocodio-library-node');
  const geocoder = new Geocodio('YOUR_API_KEY');

  geocoder.list.delete(42)
  .then(response => { ... })
  .catch(err => { ... });
```

> Example response:

```json
{
  "success": true
}
```

Delete a previously uploaded list and its underlying spreadsheet data permanently. This can also be used to cancel and delete a spreadsheet that is currently processing.

Geocodio Unlimited customers can cancel a spreadsheet at any time. Pay as You Go customers can only cancel a spreadsheet if it was just recently started.

The spreadsheet data will always be deleted automatically after 72 hours if it is not deleted manually first.

### HTTP Request

`DELETE https://api.geocod.io/v2/lists/LIST_ID`

### URL Parameters

Parameter | Description
--------- | -----------
`api_key` | Your Geocodio API key

# Data Appends (fields)

> To get `cd` and `stateleg` field appends for an address or a coordinate:

```shell
curl "https://api.geocod.io/v2/geocode?q=1109+N+Highland+St%2C+Arlington+VA&fields=cd,stateleg&api_key=YOUR_API_KEY"
curl "https://api.geocod.io/v2/reverse?q=38.886672,-77.094735&fields=cd,stateleg&api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

location = geocodio.geocode(['1109 N Highland St, Arlington VA'], ['cd', 'stateleg'])
location = geocodio.reverse(['38.886672,-77.094735'], ['cd', 'stateleg'])
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

response = client.geocode("1109 N Highland St, Arlington VA", fields=["cd", "stateleg"])
response = client.reverse("38.886672,-77.094735", fields=["cd", "stateleg"])
```

```php
<?php
$response = $geocoder->geocode('1109 N Highland St, Arlington VA', ['cd', 'stateleg']);
$response = $geocoder->reverse('38.886672,-77.094735', ['cd', 'stateleg']);
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocodio = new Geocodio('YOUR_API_KEY');

geocoder.geocode('1109 N Highland St, Arlington VA', ['cd', 'stateleg'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);

geocoder.reverse('38.886672,-77.094735', ['cd', 'stateleg'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example for "1109 N Highland St, Arlington VA":

```json
...
  "fields": {
    "congressional_districts": [
      {
        "name": "Congressional District 8",
        "district_number": 8,
        "ocd_id": "ocd-division/country:us/state:va/cd:8",
        "congress_number": "119th",
        "congress_years": "2025-2027",
        "proportion": 1,
        "current_legislators": [
          {
            "type": "representative",
            "seniority": null,
            "bio": {
              "last_name": "Beyer",
              "first_name": "Donald",
              "birthday": "1950-06-20",
              "gender": "M",
              "party": "Democrat",
              "photo_url": "https://www.congress.gov/img/member/b001292_200.jpg",
              "photo_attribution": "Image courtesy of the Member"
            },
            "contact": {
              "url": "https://beyer.house.gov",
              "address": "1226 Longworth House Office Building Washington DC 20515-4608",
              "phone": "202-225-4376",
              "contact_form": null
            },
            "social": {
              "rss_url": null,
              "twitter": "RepDonBeyer",
              "facebook": "RepDonBeyer",
              "youtube": null,
              "youtube_id": "UCPJGVbOVcAVGiBwq8qr_T9w"
            },
            "references": {
              "bioguide_id": "B001292",
              "thomas_id": "02272",
              "opensecrets_id": "N00036018",
              "lis_id": null,
              "cspan_id": "21141",
              "govtrack_id": "412657",
              "votesmart_id": "1707",
              "ballotpedia_id": "Don Beyer",
              "washington_post_id": null,
              "icpsr_id": "21554",
              "wikipedia_id": "Don Beyer"
            },
            "source": "Legislator data collected by the @unitedstates project (https://github.com/unitedstates/)"
          },
          {
            "type": "senator",
            "seniority": "senior",
            "bio": {
              "last_name": "Warner",
              "first_name": "Mark",
              "birthday": "1954-12-15",
              "gender": "M",
              "party": "Democrat",
              "photo_url": "https://www.congress.gov/img/member/w000805_200.jpg",
              "photo_attribution": "Courtesy U.S. Senate Historical Office (http://www.senate.gov/artandhistory/history/common/generic/Photo_Collection_of_the_Senate_Historical_Office.htm)"
            },
            "contact": {
              "url": "https://www.warner.senate.gov",
              "address": "703 Hart Senate Office Building Washington DC 20510",
              "phone": "202-224-2023",
              "contact_form": "https://www.warner.senate.gov/public/index.cfm?p=Contact"
            },
            "social": {
              "rss_url": "http://www.warner.senate.gov/public/?a=rss.feed",
              "twitter": "MarkWarner",
              "facebook": "MarkRWarner",
              "youtube": "SenatorMarkWarner",
              "youtube_id": "UCwyivNlEGf4sGd1oDLfY5jw"
            },
            "references": {
              "bioguide_id": "W000805",
              "thomas_id": "01897",
              "opensecrets_id": "N00002097",
              "lis_id": "S327",
              "cspan_id": "7630",
              "govtrack_id": "412321",
              "votesmart_id": "535",
              "ballotpedia_id": "Mark Warner",
              "washington_post_id": null,
              "icpsr_id": "40909",
              "wikipedia_id": "Mark Warner"
            },
            "source": "Legislator data collected by the @unitedstates project (https://github.com/unitedstates/)"
          },
          {
            "type": "senator",
            "seniority": "junior",
            "bio": {
              "last_name": "Kaine",
              "first_name": "Timothy",
              "birthday": "1958-02-26",
              "gender": "M",
              "party": "Democrat",
              "photo_url": "https://www.congress.gov/img/member/k000384_200.jpg",
              "photo_attribution": "Courtesy U.S. Senate Historical Office (http://www.senate.gov/artandhistory/history/common/generic/Photo_Collection_of_the_Senate_Historical_Office.htm)"
            },
            "contact": {
              "url": "https://www.kaine.senate.gov",
              "address": "231 Russell Senate Office Building Washington DC 20510",
              "phone": "202-224-4024",
              "contact_form": "https://www.kaine.senate.gov/contact"
            },
            "social": {
              "rss_url": "http://www.kaine.senate.gov/rss/feeds/?type=all",
              "twitter": null,
              "facebook": "SenatorKaine",
              "youtube": "SenatorTimKaine",
              "youtube_id": "UC27LgTZlUnBQoNEQFZdn9LA"
            },
            "references": {
              "bioguide_id": "K000384",
              "thomas_id": "02176",
              "opensecrets_id": "N00033177",
              "lis_id": "S362",
              "cspan_id": "49219",
              "govtrack_id": "412582",
              "votesmart_id": "50772",
              "ballotpedia_id": "Tim Kaine",
              "washington_post_id": null,
              "icpsr_id": "41305",
              "wikipedia_id": "Tim Kaine"
            },
            "source": "Legislator data collected by the @unitedstates project (https://github.com/unitedstates/)"
          }
        ]
      }
    ],
    "state_legislative_districts": {
      "house": [
        {
          "name": "2nd District",
          "district_number": "2",
          "ocd_id": "ocd-division/country:us/state:va/sldl:2",
          "is_upcoming_state_legislative_district": false,
          "proportion": 1,
          "current_legislators": [
            {
              "type": "representative",
              "bio": {
                "last_name": "McClure",
                "first_name": "Adele",
                "birthday": null,
                "gender": "F",
                "party": "Democrat",
                "photo_url": "https://memdata.virginiageneralassembly.gov/images/display_image/H0375"
              },
              "contact": {
                "url": "https://house.vga.virginia.gov/members/H0375",
                "address": "Room 1102, General Assembly Building 201 N. 9th St., Richmond, VA 23219",
                "phone": "804-698-1002",
                "email": "delamcclure@house.virginia.gov",
                "contact_form": null
              },
              "social": {
                "rss_url": null,
                "twitter": null,
                "facebook": null,
                "youtube": null,
                "youtube_id": null
              },
              "references": {
                "votesmart_id": "212037",
                "ballotpedia_id": "Adele_McClure",
                "wikipedia_id": "Adele_McClure",
                "openstates_id": "ocd-person/d0de7acb-ce8d-4bb2-b6e5-99cefe5e76a6"
              },
              "source": "Legislator data collected by Open States (https://github.com/openstates/)"
            }
          ]
        }
      ],
      "senate": [
        {
          "name": "District 40",
          "district_number": "40",
          "ocd_id": "ocd-division/country:us/state:va/sldu:40",
          "is_upcoming_state_legislative_district": false,
          "proportion": 1,
          "current_legislators": [
            {
              "type": "senator",
              "bio": {
                "last_name": "Favola",
                "first_name": "Barbara",
                "birthday": "1955-06-21",
                "gender": "F",
                "party": "Democrat",
                "photo_url": "https://apps.senate.virginia.gov/Senator/images/member_photos/Favola40"
              },
              "contact": {
                "url": "https://apps.senate.virginia.gov/Senator/memberpage.php?id=S86",
                "address": "Room 509, General Assembly Building P.O. Box 396, Richmond, VA 23218",
                "phone": "804-698-7540",
                "email": "senatorfavola@senate.virginia.gov",
                "contact_form": null
              },
              "social": {
                "rss_url": null,
                "twitter": "BarbaraFavola",
                "facebook": "BarbaraFavola",
                "youtube": null,
                "youtube_id": null
              },
              "references": {
                "votesmart_id": "94043",
                "ballotpedia_id": "Barbara_Favola",
                "wikipedia_id": "Barbara_Favola",
                "openstates_id": "ocd-person/72ecc30c-7175-4aef-9762-fda3ba5b451e"
              },
              "source": "Legislator data collected by Open States (https://github.com/openstates/)"
            }
          ]
        }
      ]
    }
  }
...
```

> **Warning:** **Note:** Fields count as an additional lookup each. Please consult our [pricing calculator](/pricing/).

Geocodio allows you to request additional data with forward and reverse geocoding requests. We call this additional data *fields*.

To request additional data, just add a `fields` parameter to your query string and set the value according to the table below. You can request multiple data fields at the same time by separating them with a comma. If the `fields` parameter has been specified, a new `fields` key is exposed with each geocoding result containing all necessary data for each field.

Go ahead, [try this in your browser right now](https://api.geocod.io/v2/geocode?q=1109+N+Highland+St%2c+Arlington+VA&fields=cd&api_key=YOUR_API_KEY).

Some fields are specific to the US and cannot be queried for other countries.

| Parameter name                                                                                                                                                                                                                                       | Description                                                | Coverage                    |
|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------------------------------|:----------------------------|
| [cd, cd113, cd114, cd115, cd116, cd117, cd118, cd119, cd120](#congressional-districts)                                                                                                                                                               | Congressional District & Legislator information            | US-only                     |
| [stateleg, stateleg-next](#state-legislative-districts)                                                                                                                                                                                              | State Legislative District (House & Senate) & Legislator information                | US-only                     |
| [school](#school-districts)                                                                                                                                                                                                                          | School District (elementary/secondary or unified)          | US-only                     |
| [census, census2000, census2010, census2011, census2012, census2013, census2014, census2015, census2016, census2017, census2018, census2019, census2020, census2021, census2022, census2023, census2024, census2025](#census-blocktract-fips-codes-msacsa-codes) | Census Block/Tract, FIPS codes & MSA/CSA codes             | US-only                     |
| [acs-demographics](#census-demographics)                                                                                                                                                                                                             | Demographics (Census)                                      | US-only                     |
| [acs-economics](#census-income)                                                                                                                                                                                                                      | Economics: Income Data (Census)                            | US-only                     |
| [acs-families](#census-households)                                                                                                                                                                                                                   | Families (Census)                                          | US-only                     |
| [acs-housing](#census-housing)                                                                                                                                                                                                                       | Housing (Census)                                           | US-only                     |
| [acs-social](#social-education-veteran-status-census)                                                                                                                                                                                                | Social: Education & Veteran Status (Census)                | US-only                     |
| [zip4](#usps-zip-4)                                                                                                                                                                                                                                  | USPS Zip+4 code and delivery information                   | US-only                     |
| [ffiec](#ffiec-fair-lending)                                                                                                                                                                                                                         | (Beta) FFIEC CRA/HMDA Data                                 | US-only                     |
| [riding](#riding-canadian-federal-electoral-district)                                                                                                                                                                                                | Riding: Canadian Federal Electoral District                | Canada-only                 |
| [provriding, provriding-next](#riding-canadian-provincial-electoral-district)                                                                                                                                                                        | Riding: Canadian Provincial/Territorial Electoral District | Canada-only                 |
| [statcan](#canadian-statistical-boundaries-from-statistics-canada)                                                                                                                                                                                   | Canadian statistical boundaries from Statistics Canada     | Canada-only                 |
| [uk-westminster, uk-devolved, uk-local (and their -next variants)](#united-kingdom-political-districts)                                                                                                                                               | UK political districts: Westminster, devolved & local      | UK-only                     |
| [timezone](#timezone)                                                                                                                                                                                                                                | Timezone                                                   | All countries |

> **Tip:** This feature is available for both single and batch geocoding requests as well as the lists API

## Congressional Districts
**Field name: `cd`, `cd113`, `cd114`, `cd115`, `cd116`, `cd117`, `cd118`, `cd119`, `cd120`**

> To get `cd` field appends for an address or a coordinate:

```shell
curl "https://api.geocod.io/v2/geocode?q=1109+N+Highland+St%2C+Arlington+VA&fields=cd&api_key=YOUR_API_KEY"
curl "https://api.geocod.io/v2/reverse?q=38.886672,-77.094735&fields=cd&api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

location = geocodio.geocode(['1109 N Highland St, Arlington VA'], ['cd'])
location = geocodio.reverse(['38.886672,-77.094735'], ['cd'])
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

response = client.geocode("1109 N Highland St, Arlington VA", fields=["cd"])
response = client.reverse("38.886672,-77.094735", fields=["cd"])
```

```php
<?php
$response = $geocoder->geocode('1109 N Highland St, Arlington VA', ['cd']);
$response = $geocoder->reverse('38.886672,-77.094735', ['cd']);
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocodio = new Geocodio('YOUR_API_KEY');

geocoder.geocode('1109 N Highland St, Arlington VA', ['cd'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);

geocoder.reverse('38.886672,-77.094735', ['cd'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example for "1109 N Highland St, Arlington VA":

```json
...
  "fields": {
    "congressional_districts": [
      {
        "name": "Congressional District 8",
        "district_number": 8,
        "ocd_id": "ocd-division/country:us/state:va/cd:8",
        "congress_number": "119th",
        "congress_years": "2025-2027",
        "proportion": 1,
        "current_legislators": [
          {
            "type": "representative",
            "seniority": null,
            "bio": {
              "last_name": "Beyer",
              "first_name": "Donald",
              "birthday": "1950-06-20",
              "gender": "M",
              "party": "Democrat",
              "photo_url": "https://www.congress.gov/img/member/b001292_200.jpg",
              "photo_attribution": "Image courtesy of the Member"
            },
            "contact": {
              "url": "https://beyer.house.gov",
              "address": "1226 Longworth House Office Building Washington DC 20515-4608",
              "phone": "202-225-4376",
              "contact_form": null
            },
            "social": {
              "rss_url": null,
              "twitter": "RepDonBeyer",
              "facebook": "RepDonBeyer",
              "youtube": null,
              "youtube_id": "UCPJGVbOVcAVGiBwq8qr_T9w"
            },
            "references": {
              "bioguide_id": "B001292",
              "thomas_id": "02272",
              "opensecrets_id": "N00036018",
              "lis_id": null,
              "cspan_id": "21141",
              "govtrack_id": "412657",
              "votesmart_id": "1707",
              "ballotpedia_id": "Don Beyer",
              "washington_post_id": null,
              "icpsr_id": "21554",
              "wikipedia_id": "Don Beyer"
            },
            "source": "Legislator data collected by the @unitedstates project (https://github.com/unitedstates/)"
          },
          {
            "type": "senator",
            "seniority": "senior",
            "bio": {
              "last_name": "Warner",
              "first_name": "Mark",
              "birthday": "1954-12-15",
              "gender": "M",
              "party": "Democrat",
              "photo_url": "https://www.congress.gov/img/member/w000805_200.jpg",
              "photo_attribution": "Courtesy U.S. Senate Historical Office (http://www.senate.gov/artandhistory/history/common/generic/Photo_Collection_of_the_Senate_Historical_Office.htm)"
            },
            "contact": {
              "url": "https://www.warner.senate.gov",
              "address": "703 Hart Senate Office Building Washington DC 20510",
              "phone": "202-224-2023",
              "contact_form": "https://www.warner.senate.gov/public/index.cfm?p=Contact"
            },
            "social": {
              "rss_url": "http://www.warner.senate.gov/public/?a=rss.feed",
              "twitter": "MarkWarner",
              "facebook": "MarkRWarner",
              "youtube": "SenatorMarkWarner",
              "youtube_id": "UCwyivNlEGf4sGd1oDLfY5jw"
            },
            "references": {
              "bioguide_id": "W000805",
              "thomas_id": "01897",
              "opensecrets_id": "N00002097",
              "lis_id": "S327",
              "cspan_id": "7630",
              "govtrack_id": "412321",
              "votesmart_id": "535",
              "ballotpedia_id": "Mark Warner",
              "washington_post_id": null,
              "icpsr_id": "40909",
              "wikipedia_id": "Mark Warner"
            },
            "source": "Legislator data collected by the @unitedstates project (https://github.com/unitedstates/)"
          },
          {
            "type": "senator",
            "seniority": "junior",
            "bio": {
              "last_name": "Kaine",
              "first_name": "Timothy",
              "birthday": "1958-02-26",
              "gender": "M",
              "party": "Democrat",
              "photo_url": "https://www.congress.gov/img/member/k000384_200.jpg",
              "photo_attribution": "Courtesy U.S. Senate Historical Office (http://www.senate.gov/artandhistory/history/common/generic/Photo_Collection_of_the_Senate_Historical_Office.htm)"
            },
            "contact": {
              "url": "https://www.kaine.senate.gov",
              "address": "231 Russell Senate Office Building Washington DC 20510",
              "phone": "202-224-4024",
              "contact_form": "https://www.kaine.senate.gov/contact"
            },
            "social": {
              "rss_url": "http://www.kaine.senate.gov/rss/feeds/?type=all",
              "twitter": null,
              "facebook": "SenatorKaine",
              "youtube": "SenatorTimKaine",
              "youtube_id": "UC27LgTZlUnBQoNEQFZdn9LA"
            },
            "references": {
              "bioguide_id": "K000384",
              "thomas_id": "02176",
              "opensecrets_id": "N00033177",
              "lis_id": "S362",
              "cspan_id": "49219",
              "govtrack_id": "412582",
              "votesmart_id": "50772",
              "ballotpedia_id": "Tim Kaine",
              "washington_post_id": null,
              "icpsr_id": "41305",
              "wikipedia_id": "Tim Kaine"
            },
            "source": "Legislator data collected by the @unitedstates project (https://github.com/unitedstates/)"
          }
        ]
      }
    ]
  }
...
```

Geocodio can return the Congressional district and Representative/Senator information for an address or coordinate pair via any one of the valid parameter names in the `fields` query parameter. `cd` will always return the Congressional district for the current Congress, while e.g. `cd113` will continue to show the Congressional district for the 113th Congress.

The field returns the full name of the Congressional district, the district number, the Congress number, and the year range. If the current Congress (i.e. `cd` or `cd119`) is specified, Geocodio will also return detailed information about the current legislators.

> **Tip:** The list of legislators is always ordered with the Representative first then Senators.

> **Note:** Per U.S. Census Bureau specifications, the following rules apply:
>
> States with a single Congressional district return a special "district_number" of 0 (i.e. Vermont).
>
> Districts with non-voting delegates return a special "district_number" of 98 (i.e. Washington DC).

### OCD Identifiers

[Open Civic Data Division Identifiers](https://github.com/opencivicdata/ocd-division-ids) (OCD-IDs) are returned for each district when using `cd119` or `cd120`.

This ID can be used as a unique identifier for each district. You can see the full list of districts returned by Geocodio and their corresponding OCD-IDs [here.](https://www.geocod.io/guides/ocd-ids/)

When requesting boundaries for other congressional periods, the `ocd_id` property is still present, but set to `null`.

### Look up Congressional districts with ZIP codes

Geocodio can return the most likely Congressional districts given a ZIP code. In cases where there may be multiple possible Congressional districts for a ZIP code, we will return multiple Congressional districts, and rank them each using a `proportion` key. This key is the share of the ZIP code's area that falls inside the district (i.e., a bigger number means it's more likely to be the correct district for residents in that ZIP code). The proportions returned for a ZIP code sum to approximately 1; districts covering less than 0.1% of the ZIP code are left out.

Districts are always sorted by the `proportion` value in descending order (largest first).

This weighted list is not limited to queries that consist of a bare ZIP code. Geocodio returns it whenever the result's `accuracy_type` is `place`, which includes a query naming only a city, or a city and state. In those cases the lookup is keyed on the ZIP code in the returned `address_components`, which is the ZIP code of the matched place rather than one supplied in the query. Reverse geocoding does not return the weighted list: a reverse result at `nearest_place` accuracy is looked up at its coordinate and returns a single district with a `proportion` of `1`.

Read `proportion` before using the first entry in the list. At `place` accuracy, every district returned is a possible answer for the address, and `proportion` tells you how much of the matched ZIP code falls inside each district. Where the first entry holds only a narrow majority of the ZIP code, the entries below it carry real weight.

> **Note:** Where possible, we recommend looking up Congressional districts with full addresses rather than ZIP codes. This will result in more accurate results, as ZIP codes are postal routes rather than geographic areas and may not be as accurate.

## State Legislative Districts
**Field name: `stateleg` or `stateleg-next`**

> To get `stateleg` field appends for an address or a coordinate:

```shell
curl "https://api.geocod.io/v2/geocode?q=1109+N+Highland+St%2C+Arlington+VA&fields=stateleg&api_key=YOUR_API_KEY"
curl "https://api.geocod.io/v2/reverse?q=38.886672,-77.094735&fields=stateleg&api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

location = geocodio.geocode(['1109 N Highland St, Arlington VA'], ['stateleg'])
location = geocodio.reverse(['38.886672,-77.094735'], ['stateleg'])
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

response = client.geocode("1109 N Highland St, Arlington VA", fields=["stateleg"])
response = client.reverse("38.886672,-77.094735", fields=["stateleg"])
```

```php
<?php
$response = $geocoder->geocode('1109 N Highland St, Arlington VA', ['stateleg']);
$response = $geocoder->reverse('38.886672,-77.094735', ['stateleg']);
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocodio = new Geocodio('YOUR_API_KEY');

geocoder.geocode('1109 N Highland St, Arlington VA', ['stateleg'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);

geocoder.reverse('38.886672,-77.094735', ['stateleg'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example for "1109 N Highland St, Arlington VA":

```json
...
  "fields": {
    "state_legislative_districts": {
      "house": [
        {
          "name": "2nd District",
          "district_number": "2",
          "ocd_id": "ocd-division/country:us/state:va/sldl:2",
          "is_upcoming_state_legislative_district": false,
          "proportion": 1,
          "current_legislators": [
            {
              "type": "representative",
              "bio": {
                "last_name": "McClure",
                "first_name": "Adele",
                "birthday": null,
                "gender": "F",
                "party": "Democrat",
                "photo_url": "https://memdata.virginiageneralassembly.gov/images/display_image/H0375"
              },
              "contact": {
                "url": "https://house.vga.virginia.gov/members/H0375",
                "address": "Room 1102, General Assembly Building 201 N. 9th St., Richmond, VA 23219",
                "phone": "804-698-1002",
                "email": "delamcclure@house.virginia.gov",
                "contact_form": null
              },
              "social": {
                "rss_url": null,
                "twitter": null,
                "facebook": null,
                "youtube": null,
                "youtube_id": null
              },
              "references": {
                "votesmart_id": "212037",
                "ballotpedia_id": "Adele_McClure",
                "wikipedia_id": "Adele_McClure",
                "openstates_id": "ocd-person/d0de7acb-ce8d-4bb2-b6e5-99cefe5e76a6"
              },
              "source": "Legislator data collected by Open States (https://github.com/openstates/)"
            }
          ]
        }
      ],
      "senate": [
        {
          "name": "District 40",
          "district_number": "40",
          "ocd_id": "ocd-division/country:us/state:va/sldu:40",
          "is_upcoming_state_legislative_district": false,
          "proportion": 1,
          "current_legislators": [
            {
              "type": "senator",
              "bio": {
                "last_name": "Favola",
                "first_name": "Barbara",
                "birthday": "1955-06-21",
                "gender": "F",
                "party": "Democrat",
                "photo_url": "https://apps.senate.virginia.gov/Senator/images/member_photos/Favola40"
              },
              "contact": {
                "url": "https://apps.senate.virginia.gov/Senator/memberpage.php?id=S86",
                "address": "Room 509, General Assembly Building P.O. Box 396, Richmond, VA 23218",
                "phone": "804-698-7540",
                "email": "senatorfavola@senate.virginia.gov",
                "contact_form": null
              },
              "social": {
                "rss_url": null,
                "twitter": "BarbaraFavola",
                "facebook": "BarbaraFavola",
                "youtube": null,
                "youtube_id": null
              },
              "references": {
                "votesmart_id": "94043",
                "ballotpedia_id": "Barbara_Favola",
                "wikipedia_id": "Barbara_Favola",
                "openstates_id": "ocd-person/72ecc30c-7175-4aef-9762-fda3ba5b451e"
              },
              "source": "Legislator data collected by Open States (https://github.com/openstates/)"
            }
          ]
        }
      ]
    }
  }
...
```

Geocodio can return the state legislative districts and legislator information for an address or coordinate pair via `stateleg` in the `fields` query parameter.

The `stateleg-next` append can be used to retrieve state legislative districts based on upcoming district changes due to redistricting.

The field will return both the *house* and *senate* state legislative districts (also known as *lower* and *upper*) with the full name and district number for each. For areas with a [unicameral legislature](http://en.wikipedia.org/wiki/Unicameralism), such as Washington DC and Nebraska, the `house` and `senate` keys return the same district.

Geocodio will also return current state legislator names, contact information, and more. For districts or states with at-large legislature (such as Washington DC and Puerto Rico), the at-large legislators are returned for all districts, but they are returned last. See more details on the legislator biographical and contact information Geocodio returns [here.](https://www.geocod.io/guides/state-legislative-districts/)

### Using `stateleg-next`

`stateleg-next` is a preview of upcoming redistricting changes for states that have off-year elections.

Where available, the state legislative district returned will be based on newly redistricted boundaries.

Every district boundary Geocodio holds carries an effective date, and a state chamber can have more than one set of boundaries on file at once. `stateleg` always returns the most recent set that is already in effect. `stateleg-next` returns the earliest set with an effective date in the future, if Geocodio holds one for that state and chamber. If no future-dated set exists, `stateleg-next` returns the current boundaries instead of returning an error.

Geocodio promotes each set automatically on its effective date. Once an upcoming set becomes the current one, `stateleg` returns it, and `stateleg-next` falls back to it until Geocodio loads a further set.

### Interpreting `is_upcoming_state_legislative_district`

`is_upcoming_state_legislative_district` is `true` when the boundary that produced the match has an effective date in the future.

The flag describes which boundary set the district came from. It does not indicate whether that particular district was redrawn. Boundary sets are selected per state and chamber, so when a state chamber has a future-dated set, every district in that chamber returns `true` from `stateleg-next`, including districts that the new map left untouched.

Michigan's Senate shows this in practice. Alongside the current boundaries, Geocodio holds a set effective 2027-01-01. All 38 districts belong to the 2027 set, even though the remedial plan changed only 14 of them, so every Michigan address returns `is_upcoming_state_legislative_district: true` from `stateleg-next` whether or not its own district moved.

To determine whether a specific address changes districts, request `stateleg` and `stateleg-next` for that address and compare the district numbers. The flag on its own will not tell you.

Because the flag is `false` both when a state has no upcoming boundaries and when a state's new map has not been loaded yet, it cannot be used to survey which states hold upcoming data. Use the table below for that.

### Upcoming state legislative boundaries

Geocodio currently holds future-dated state legislative boundaries for the following state chambers. For every other state and chamber, `stateleg-next` returns today's boundaries and `is_upcoming_state_legislative_district` is `false`.

| State | Chamber | Boundaries effective | Source |
|---|---|---|---|
| Michigan | Senate | 2027-01-01 | Michigan Independent Citizens Redistricting Commission |

**Michigan Senate.** The commission adopted this remedial plan in 2024, and a three-judge panel approved it in *Agee v. Benson* on 2024-07-26. 14 of the 38 districts changed, all in Metro Detroit. The plan is first used in the November 2026 election and takes effect when those senators are seated.

Rows leave this table once their boundaries are promoted. On the effective date the set becomes what `stateleg` returns, so it is no longer upcoming and `is_upcoming_state_legislative_district` returns to `false` for those districts.

For the effective dates of *current* boundaries in every state, along with the litigation Geocodio is tracking that may change them, see the [Redistricting Tracker](https://www.geocod.io/redistricting/).

> To get `stateleg-next` field appends for an address or a coordinate:

```shell
curl "https://api.geocod.io/v2/geocode?q=1109+N+Highland+St%2C+Arlington+VA&fields=stateleg-next&api_key=YOUR_API_KEY"
curl "https://api.geocod.io/v2/reverse?q=38.886672,-77.094735&fields=stateleg-next&api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

location = geocodio.geocode(['1109 N Highland St, Arlington VA'], ['stateleg-next'])
location = geocodio.reverse(['38.886672,-77.094735'], ['stateleg-next'])
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

response = client.geocode("1109 N Highland St, Arlington VA", fields=["stateleg-next"])
response = client.reverse("38.886672,-77.094735", fields=["stateleg-next"])
```

```php
<?php
$response = $geocoder->geocode('1109 N Highland St, Arlington VA', ['stateleg-next']);
$response = $geocoder->reverse('38.886672,-77.094735', ['stateleg-next']);
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocodio = new Geocodio('YOUR_API_KEY');

geocoder.geocode('1109 N Highland St, Arlington VA', ['stateleg-next'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);

geocoder.reverse('38.886672,-77.094735', ['stateleg-next'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example for "1109 N Highland St, Arlington VA":

```json
...
  "fields": {
    "state_legislative_districts": {
      "house": [
        {
          "name": "2nd District",
          "district_number": "2",
          "ocd_id": "ocd-division/country:us/state:va/sldl:2",
          "is_upcoming_state_legislative_district": false,
          "proportion": 1,
          "current_legislators": [
            {
              "type": "representative",
              "bio": {
                "last_name": "McClure",
                "first_name": "Adele",
                "birthday": null,
                "gender": "F",
                "party": "Democrat",
                "photo_url": "https://memdata.virginiageneralassembly.gov/images/display_image/H0375"
              },
              "contact": {
                "url": "https://house.vga.virginia.gov/members/H0375",
                "address": "Room 1102, General Assembly Building 201 N. 9th St., Richmond, VA 23219",
                "phone": "804-698-1002",
                "email": "delamcclure@house.virginia.gov",
                "contact_form": null
              },
              "social": {
                "rss_url": null,
                "twitter": null,
                "facebook": null,
                "youtube": null,
                "youtube_id": null
              },
              "references": {
                "votesmart_id": "212037",
                "ballotpedia_id": "Adele_McClure",
                "wikipedia_id": "Adele_McClure",
                "openstates_id": "ocd-person/d0de7acb-ce8d-4bb2-b6e5-99cefe5e76a6"
              },
              "source": "Legislator data collected by Open States (https://github.com/openstates/)"
            }
          ]
        }
      ],
      "senate": [
        {
          "name": "District 40",
          "district_number": "40",
          "ocd_id": "ocd-division/country:us/state:va/sldu:40",
          "is_upcoming_state_legislative_district": false,
          "proportion": 1,
          "current_legislators": [
            {
              "type": "senator",
              "bio": {
                "last_name": "Favola",
                "first_name": "Barbara",
                "birthday": "1955-06-21",
                "gender": "F",
                "party": "Democrat",
                "photo_url": "https://apps.senate.virginia.gov/Senator/images/member_photos/Favola40"
              },
              "contact": {
                "url": "https://apps.senate.virginia.gov/Senator/memberpage.php?id=S86",
                "address": "Room 509, General Assembly Building P.O. Box 396, Richmond, VA 23218",
                "phone": "804-698-7540",
                "email": "senatorfavola@senate.virginia.gov",
                "contact_form": null
              },
              "social": {
                "rss_url": null,
                "twitter": "BarbaraFavola",
                "facebook": "BarbaraFavola",
                "youtube": null,
                "youtube_id": null
              },
              "references": {
                "votesmart_id": "94043",
                "ballotpedia_id": "Barbara_Favola",
                "wikipedia_id": "Barbara_Favola",
                "openstates_id": "ocd-person/72ecc30c-7175-4aef-9762-fda3ba5b451e"
              },
              "source": "Legislator data collected by Open States (https://github.com/openstates/)"
            }
          ]
        }
      ]
    }
  }
...
```

### OCD Identifiers

[Open Civic Data Division Identifiers](https://github.com/opencivicdata/ocd-division-ids) (OCD-IDs) are returned for all legislative districts.

This ID can be used as a unique identifier for each district. You can see the full list of districts returned by Geocodio and their corresponding OCD-IDs [here.](https://www.geocod.io/guides/ocd-ids/)

> Example lookup using the `22206` zip code instead of a full address

```json
...
"fields": {
  "state_legislative_districts": {
    "house": [
      {
        "name": "State House District 49",
        "district_number": "49",
        "ocd_id": "ocd-division/country:us/state:va/sldl:49",
        "is_upcoming_state_legislative_district": false,
        "proportion": 0.532
      },
      {
        "name": "State House District 45",
        "district_number": "45",
        "ocd_id": "ocd-division/country:us/state:va/sldl:45",
        "is_upcoming_state_legislative_district": false,
        "proportion": 0.453
      },
      {
        "name": "State House District 46",
        "district_number": "46",
        "ocd_id": "ocd-division/country:us/state:va/sldl:46",
        "is_upcoming_state_legislative_district": false,
        "proportion": 0.015
      }
    ],
    "senate": [
      {
        "name": "State Senate District 30",
        "district_number": "30",
        "ocd_id": "ocd-division/country:us/state:va/sldu:30",
        "is_upcoming_state_legislative_district": false,
        "proportion": 1
      }
    ]
  }
}
...
```

### Look up state legislative districts with ZIP codes

Geocodio can return the most likely state legislative districts given a ZIP code. In cases where there may be multiple possible state legislative districts for a ZIP code, we will return multiple state legislative districts, and rank them each using a `proportion` key. This key is the share of the ZIP code's area that falls inside the district (i.e., a bigger number means it's more likely to be the correct district for residents in that ZIP code). Across a chamber, the proportions returned for a ZIP code sum to approximately 1; districts covering less than 0.1% of the ZIP code are left out.

Districts are always sorted by the `proportion` in descending order (largest first).

This weighted list is not limited to queries that consist of a bare ZIP code. Geocodio returns it whenever the result's `accuracy_type` is `place`, which includes a query naming only a city, or a city and state. In those cases the lookup is keyed on the ZIP code in the returned `address_components`, which is the ZIP code of the matched place rather than one supplied in the query. Reverse geocoding does not return the weighted list: a reverse result at `nearest_place` accuracy is looked up at its coordinate and returns a single district with a `proportion` of `1`.

Read `proportion` before using the first entry in the list. At `place` accuracy, every district returned is a possible answer for the address, and `proportion` tells you how much of the matched ZIP code falls inside each district. In the `22206` example above, House District 49 leads at `0.532`, so roughly half of that ZIP code sits outside it and the entries below carry real weight.

> **Note:** Where possible, we recommend looking up state legislative districts with full addresses rather than ZIP codes. This will result in more accurate results, as ZIP codes are postal routes rather than geographic areas and may not be as accurate.

## School Districts
**Field name: `school`**

> To get `school` field appends for an address or a coordinate:

```shell
curl "https://api.geocod.io/v2/geocode?q=1109+N+Highland+St%2C+Arlington+VA&fields=school&api_key=YOUR_API_KEY"
curl "https://api.geocod.io/v2/reverse?q=38.886672,-77.094735&fields=school&api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

location = geocodio.geocode(['1109 N Highland St, Arlington VA'], ['school'])
location = geocodio.reverse(['38.886672,-77.094735'], ['school'])
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

response = client.geocode("1109 N Highland St, Arlington VA", fields=["school"])
response = client.reverse("38.886672,-77.094735", fields=["school"])
```

```php
<?php
$response = $geocoder->geocode('1109 N Highland St, Arlington VA', ['school']);
$response = $geocoder->reverse('38.886672,-77.094735', ['school']);
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocodio = new Geocodio('YOUR_API_KEY');

geocoder.geocode('1109 N Highland St, Arlington VA', ['school'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);

geocoder.reverse('38.886672,-77.094735', ['school'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Unified school district example

```json
...
"fields": {
  "school_districts": {
    "unified": {
      "name": "Desert Sands Unified School District",
      "lea_code": "11110",
      "grade_low": "KG",
      "grade_high": "12"
    }
  },
}
...
```

> Elementary/Secondary school districts example

```json
...
"fields": {
  "school_districts": {
      "elementary": {
        "name": "Topsfield School District",
        "lea_code": "11670",
        "grade_low": "PK",
        "grade_high": "06"
      },
      "secondary": {
        "name": "Masconomet School District",
        "lea_code": "07410",
        "grade_low": "07",
        "grade_high": "12"
      }
    }
  }
}
...
```
Geocodio can return the school district for an address or coordinate using `school` in the `fields` query parameter.

The field will return either a *unified* school district or separate *elementary* and *secondary* fields depending on the area. Each school district is returned with its full name, the LEA (Local Education Agency) code, and the grades supported. Kindergarden is abbreviated as *KG* and pre-kindergarten is abbreviated as *PK*.

## Census Block/Tract, FIPS codes & MSA/CSA codes
**Field name: `census`, `census2000`, `census2010`, `census2011`, `census2012`, `census2013`, `census2014`, `census2015`, `census2016`, `census2017`, `census2018`, `census2019`, `census2020`, `census2021`, `census2022`, `census2023`, `census2024`, `census2025`**

> To get `census2010` and `census` field appends for an address or a coordinate:

```shell
curl "https://api.geocod.io/v2/geocode?q=1109+N+Highland+St%2C+Arlington+VA&fields=census2010,census&api_key=YOUR_API_KEY"
curl "https://api.geocod.io/v2/reverse?q=38.886672,-77.094735&fields=census2010,census&api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

location = geocodio.geocode(['1109 N Highland St, Arlington VA'], ['census2010', 'census'])
location = geocodio.reverse(['38.886672,-77.094735'], ['census2010', 'census'])
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

response = client.geocode("1109 N Highland St, Arlington VA", fields=["census2010", "census"])
response = client.reverse("38.886672,-77.094735", fields=["census2010", "census"])
```

```php
<?php
$response = $geocoder->geocode('1109 N Highland St, Arlington VA', ['census2010', 'census']);
$response = $geocoder->reverse('38.886672,-77.094735', ['census2010', 'census']);
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocodio = new Geocodio('YOUR_API_KEY');

geocoder.geocode('1109 N Highland St, Arlington VA', ['census2010', 'census'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);

geocoder.reverse('38.886672,-77.094735', ['census2010', 'census'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example for "1109 N Highland St, Arlington VA":

```json
...
  "fields": {
    "census": {
      "2010": {
        "census_year": 2010,
        "state_fips": "51",
        "county_fips": "51013",
        "tract_code": "101801",
        "block_code": "1004",
        "block_group": "1",
        "full_fips": "510131018011004",
        "place": {
          "name": "Arlington",
          "fips": "5103000"
        },
        "metro_micro_statistical_area": {
          "name": "Washington-Arlington-Alexandria, DC-VA-MD-WV",
          "area_code": "47900",
          "type": "metropolitan"
        },
        "combined_statistical_area": {
          "name": "Washington-Baltimore-Northern Virginia, DC-MD-VA-WV",
          "area_code": "51548"
        },
        "metropolitan_division": {
          "name": "Washington-Arlington-Alexandria, DC-VA-MD-WV",
          "area_code": "47894"
        },
        "county_subdivision": {
          "name": "Arlington",
          "fips": "90072",
          "fips_class": {
            "class_code": "Z7",
            "description": "A county subdivision that is coextensive with a county or equivalent feature or all or part of an incorporated place that the Census Bureau recognizes separately"
          }
        },
        "source": "US Census Bureau"
      },
      "2025": {
        "census_year": 2025,
        "state_fips": "51",
        "county_fips": "51013",
        "tract_code": "101801",
        "block_code": "2004",
        "block_group": "2",
        "full_fips": "510131018012004",
        "place": {
          "name": "Arlington",
          "fips": "5103000"
        },
        "metro_micro_statistical_area": {
          "name": "Washington-Arlington-Alexandria, DC-VA-MD-WV",
          "area_code": "47900",
          "type": "metropolitan"
        },
        "combined_statistical_area": {
          "name": "Washington-Baltimore-Arlington, DC-MD-VA-WV-PA",
          "area_code": "548"
        },
        "metropolitan_division": {
          "name": "Arlington-Alexandria-Reston, VA-WV",
          "area_code": "11694"
        },
        "county_subdivision": {
          "name": "Arlington",
          "fips": "90072",
          "fips_class": {
            "class_code": "Z7",
            "description": "A county subdivision that is coextensive with a county or equivalent feature or all or part of an incorporated place that the Census Bureau recognizes separately"
          }
        },
        "source": "US Census Bureau"
      }
    }
  }
...
```

Geocodio can append various US Census-designated geographies to an address or coordinate pair, including Census Tract, Census Block, FIPS codes, MSAs/CSAs, and more. Geographies are available back to 2010 as well as 2000.

> **Note:** Looking for Canadian Census data? See the [`statcan`](#canadian-statistical-boundaries-from-statistics-canada) field append.

Geocodio can provide vintage Census geographies for every year back to the 2010 Census. You can do this by specifying the year together with the field name, such as `census2015` for 2015 data. It is also possible to request multiple years at the same time, such as `census2010,census` (as shown in the example response).

Geographies for the 2000 Census are available as well using the `census2000` field append. Note that only County, Place, Tract and Block FIPS codes are returned for year 2000.

> **Warning:** If no year is specified, the API will default to the most recent Census. Currently, 2025 data is returned when appending the census field.

Field        | Description
------------ | -----------------------------------------------------------
census_year  | The full year that the Census data belongs to (The U.S. Census Bureau might make slight boundary changes from year to year)
state_fips   | The two-digit state FIPS code. A full list is available on [Wikipedia](https://en.wikipedia.org/wiki/Federal_Information_Processing_Standard_state_code)
county_fips  | The five-digit county FIPS code. The two first digits represents the state. A full list of US counties is available on [Wikipedia](https://en.wikipedia.org/wiki/List_of_United_States_counties_and_county_equivalents)
tract_code   | The 6-digit census tract code. This is a subdivision of a county, used for statistical purposes.
block_code   | The full 4-digit block code that the location belongs to. This is the smallest geographical unit that the U.S. Census Bureau provides statistical data for.
block_group  | The single-digit group number for the block
full_fips  | The full 15-digit fips code, consisting of the county fips, tract code and block code

The U.S. Census Bureau also provides a more [detailed guide](https://www.census.gov/geo/reference/gtc/gtc_ct.html) for the above terms.

Using Census tracts and blocks, you can match addresses and latitude/longitude pairs with statistical data from the U.S. Census Bureau. For example, appending Census tracts and blocks enables you to utilize the [American Community Survey (ACS) data](https://www.census.gov/programs-surveys/acs/data.html).

### Place

This field is returned for locations that are within a Census-designated place. If the location is not in a Census-designated place, the API will return `null` instead of the individual fields.

You can read more about [Census-designated places on Wikipedia](https://en.wikipedia.org/wiki/Census-designated_place).

Field        | Description
------------ | -----------------------------------------------------------
name         | The official Census-designated name for the place
fips         | The 7-digit place FIPS code. A place is defined as a city or other census designated area. A full list of ANSI codes is available from the [U.S. Census Bureau](https://www.census.gov/geo/reference/codes/place.html)

### Metropolitan/Micropolitan Statistical Area (MSA)

This field is returned for locations that are within an MSA area. If no MSA area is associated with the location, the API will return `null` instead of the individual fields.

You can read more about [Metropolitan](https://en.wikipedia.org/wiki/Metropolitan_statistical_area) and [Micropolitan](https://en.wikipedia.org/wiki/Micropolitan_statistical_area) areas on Wikipedia.

Field        | Description
------------ | -----------------------------------------------------------
name         | The official Census-designated name for the area
area_code    | Unique code for the area, also known as the CBSA code
type         | Can either be "metropolitan" or "micropolitan"

### Combined Statistical Area (CSA)

This field is returned for locations that are within an CSA area. If no CSA area is associated with the location, the API will return `null` instead of the individual fields.

You can read more about [Combined Statisical Areas on Wikipedia](https://en.wikipedia.org/wiki/Combined_statistical_area).

Field        | Description
------------ | -----------------------------------------------------------
name         | The official Census-designated name for the area
area_code    | Unique census-defined code for the area

### Metropolitan Divisions (METDIV)

This field is returned for locations that are within a Metropolitan Division. If no area is associated with the location, the API will return `null` instead of the individual fields.

Metropolitan Divisions was introduced by the U.S. Census Bureau in 2003 to further split larger MSA's (Metropolitan Statistical Areas) into smaller groups.

You can read more about [Metropolitan divisions on Wikipedia](https://simple.wikipedia.org/wiki/United_States_metropolitan_area).

Field        | Description
------------ | -----------------------------------------------------------
name         | The official Census-designated name for the area
area_code    | Unique census-defined code for the area

### County Subdivisions

Depending on the state, this is either a [MCD (Minor Civil Division)](https://en.wikipedia.org/wiki/Minor_civil_division) or [CCD (Census County Division)](https://en.wikipedia.org/wiki/Census_county_division).

Field        | Description
------------ | -----------------------------------------------------------
name         | The name of the county subdivision. Depending on the state, this could be a city/town/township name or a district number
fips         | Unique census-defined code for the area
fips_class   | The `class_code` and `description` for the given [class code](https://www.census.gov/library/reference/code-lists/class-codes.html)

## Census ACS (American Community Survey)

Geocodio helps you retrieve statistics from the American Community Survey for any US address or coordinate pair.

We've organized the ACS results into 5 helpful categories: [Demographics](/#census-demographics), [Economics (Income Data)](/#census-income), [Families](/#census-households), [Housing](#census-housing) and [Social (Education & Veteran Status)](#social-education-veteran-status-census).

### Pricing

When planning your project, each category counts as an additional lookup for billing purposes. As a bonus, the basic `census` field comes included with any `acs-` field lookups *at no additional cost*.

### Geographies

> To get `acs-demographics-county` field appends for an address or a coordinate:

```shell
curl "https://api.geocod.io/v2/geocode?q=1109+N+Highland+St%2C+Arlington+VA&fields=acs-demographics-county&api_key=YOUR_API_KEY"
curl "https://api.geocod.io/v2/reverse?q=38.886672,-77.094735&fields=acs-demographics-county&api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

location = geocodio.geocode(['1109 N Highland St, Arlington VA'], ['acs-demographics-county'])
location = geocodio.reverse(['38.886672,-77.094735'], ['acs-demographics-county'])
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

response = client.geocode("1109 N Highland St, Arlington VA", fields=["acs-demographics-county"])
response = client.reverse("38.886672,-77.094735", fields=["acs-demographics-county"])
```

```php
<?php
$response = $geocoder->geocode('1109 N Highland St, Arlington VA', ['acs-demographics-county']);
$response = $geocoder->reverse('38.886672,-77.094735', ['acs-demographics-county']);
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocodio = new Geocodio('YOUR_API_KEY');

geocoder.geocode('1109 N Highland St, Arlington VA', ['acs-demographics-county'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);

geocoder.reverse('38.886672,-77.094735', ['acs-demographics-county'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example for "1109 N Highland St, Arlington VA":

```json
...
  "fields": {
    "census": {
      "2024": {
        "census_year": 2024,
        "state_fips": "51",
        "county_fips": "51013",
        "tract_code": "101801",
        "block_code": "2004",
        "block_group": "2",
        "full_fips": "510131018012004",
        "place": {
          "name": "Arlington",
          "fips": "5103000"
        },
        "metro_micro_statistical_area": {
          "name": "Washington-Arlington-Alexandria, DC-VA-MD-WV",
          "area_code": "47900",
          "type": "metropolitan"
        },
        "combined_statistical_area": {
          "name": "Washington-Baltimore-Arlington, DC-MD-VA-WV-PA",
          "area_code": "548"
        },
        "metropolitan_division": {
          "name": "Arlington-Alexandria-Reston, VA-WV",
          "area_code": "11694"
        },
        "county_subdivision": {
          "name": "Arlington",
          "fips": "90072",
          "fips_class": {
            "class_code": "Z7",
            "description": "A county subdivision that is coextensive with a county or equivalent feature or all or part of an incorporated place that the Census Bureau recognizes separately"
          }
        },
        "source": "US Census Bureau"
      }
    },
    "acs": {
      "meta": {
        "source": "American Community Survey from the US Census Bureau",
        "survey_years": "2020-2024",
        "survey_duration_years": "5"
      },
      "demographics": {
        "Median age": {
          "meta": {
            "table_id": "B01002",
            "universe": "Total population"
          },
          "Total": {
            "value": 35.5,
            "margin_of_error": 0.2
          },
          "Male": {
            "value": 35.3,
            "margin_of_error": 0.1
          },
          "Female": {
            "value": 35.8,
            "margin_of_error": 0.2
          }
        },
        "Population by age range": {
          "meta": {
            "table_id": "B01001",
            "universe": "Total population"
          },
          "Total": {
            "value": 236254,
            "margin_of_error": 0
          },
          "Male": {
            "value": 118902,
            "margin_of_error": 46,
            "percentage": 0.503
          },
          "Male: Under 5 years": {
            "value": 6000,
            "margin_of_error": 11,
            "percentage": 0.05
          },
          "Male: 5 to 9 years": {
            "value": 6145,
            "margin_of_error": 416,
            "percentage": 0.052
          },
          "Male: 10 to 14 years": {
            "value": 6242,
            "margin_of_error": 426,
            "percentage": 0.052
          },
          "Male: 15 to 17 years": {
            "value": 3545,
            "margin_of_error": 3,
            "percentage": 0.03
          },
          "Male: 18 and 19 years": {
            "value": 1788,
            "margin_of_error": 92,
            "percentage": 0.015
          },
          "Male: 20 years": {
            "value": 769,
            "margin_of_error": 201,
            "percentage": 0.006
          },
          "Male: 21 years": {
            "value": 664,
            "margin_of_error": 175,
            "percentage": 0.006
          },
          "Male: 22 to 24 years": {
            "value": 6577,
            "margin_of_error": 268,
            "percentage": 0.055
          },
          "Male: 25 to 29 years": {
            "value": 15043,
            "margin_of_error": 20,
            "percentage": 0.127
          },
          "Male: 30 to 34 years": {
            "value": 12116,
            "margin_of_error": 59,
            "percentage": 0.102
          },
          "Male: 35 to 39 years": {
            "value": 9639,
            "margin_of_error": 593,
            "percentage": 0.081
          },
          "Male: 40 to 44 years": {
            "value": 9604,
            "margin_of_error": 585,
            "percentage": 0.081
          },
          "Male: 45 to 49 years": {
            "value": 7952,
            "margin_of_error": 63,
            "percentage": 0.067
          },
          "Male: 50 to 54 years": {
            "value": 7526,
            "margin_of_error": 48,
            "percentage": 0.063
          },
          "Male: 55 to 59 years": {
            "value": 6488,
            "margin_of_error": 467,
            "percentage": 0.055
          },
          "Male: 60 and 61 years": {
            "value": 2460,
            "margin_of_error": 324,
            "percentage": 0.021
          },
          "Male: 62 to 64 years": {
            "value": 3353,
            "margin_of_error": 428,
            "percentage": 0.028
          },
          "Male: 65 and 66 years": {
            "value": 2133,
            "margin_of_error": 319,
            "percentage": 0.018
          },
          "Male: 67 to 69 years": {
            "value": 2535,
            "margin_of_error": 295,
            "percentage": 0.021
          },
          "Male: 70 to 74 years": {
            "value": 3376,
            "margin_of_error": 246,
            "percentage": 0.028
          },
          "Male: 75 to 79 years": {
            "value": 2474,
            "margin_of_error": 295,
            "percentage": 0.021
          },
          "Male: 80 to 84 years": {
            "value": 1225,
            "margin_of_error": 170,
            "percentage": 0.01
          },
          "Male: 85 years and over": {
            "value": 1248,
            "margin_of_error": 274,
            "percentage": 0.01
          },
          "Female": {
            "value": 117352,
            "margin_of_error": 46,
            "percentage": 0.497
          },
          "Female: Under 5 years": {
            "value": 5805,
            "margin_of_error": 11,
            "percentage": 0.049
          },
          "Female: 5 to 9 years": {
            "value": 5731,
            "margin_of_error": 430,
            "percentage": 0.049
          },
          "Female: 10 to 14 years": {
            "value": 5796,
            "margin_of_error": 429,
            "percentage": 0.049
          },
          "Female: 15 to 17 years": {
            "value": 3337,
            "margin_of_error": 22,
            "percentage": 0.028
          },
          "Female: 18 and 19 years": {
            "value": 1602,
            "margin_of_error": 118,
            "percentage": 0.014
          },
          "Female: 20 years": {
            "value": 547,
            "margin_of_error": 216,
            "percentage": 0.005
          },
          "Female: 21 years": {
            "value": 600,
            "margin_of_error": 201,
            "percentage": 0.005
          },
          "Female: 22 to 24 years": {
            "value": 7166,
            "margin_of_error": 313,
            "percentage": 0.061
          },
          "Female: 25 to 29 years": {
            "value": 14709,
            "margin_of_error": 34,
            "percentage": 0.125
          },
          "Female: 30 to 34 years": {
            "value": 11615,
            "margin_of_error": 58,
            "percentage": 0.099
          },
          "Female: 35 to 39 years": {
            "value": 10181,
            "margin_of_error": 623,
            "percentage": 0.087
          },
          "Female: 40 to 44 years": {
            "value": 8735,
            "margin_of_error": 630,
            "percentage": 0.074
          },
          "Female: 45 to 49 years": {
            "value": 7874,
            "margin_of_error": 50,
            "percentage": 0.067
          },
          "Female: 50 to 54 years": {
            "value": 7108,
            "margin_of_error": 4,
            "percentage": 0.061
          },
          "Female: 55 to 59 years": {
            "value": 6130,
            "margin_of_error": 421,
            "percentage": 0.052
          },
          "Female: 60 and 61 years": {
            "value": 2264,
            "margin_of_error": 417,
            "percentage": 0.019
          },
          "Female: 62 to 64 years": {
            "value": 3020,
            "margin_of_error": 385,
            "percentage": 0.026
          },
          "Female: 65 and 66 years": {
            "value": 1984,
            "margin_of_error": 281,
            "percentage": 0.017
          },
          "Female: 67 to 69 years": {
            "value": 2700,
            "margin_of_error": 258,
            "percentage": 0.023
          },
          "Female: 70 to 74 years": {
            "value": 3944,
            "margin_of_error": 298,
            "percentage": 0.034
          },
          "Female: 75 to 79 years": {
            "value": 3186,
            "margin_of_error": 304,
            "percentage": 0.027
          },
          "Female: 80 to 84 years": {
            "value": 1430,
            "margin_of_error": 240,
            "percentage": 0.012
          },
          "Female: 85 years and over": {
            "value": 1888,
            "margin_of_error": 279,
            "percentage": 0.016
          }
        },
        "Sex": {
          "meta": {
            "table_id": "B01001",
            "universe": "Total population"
          },
          "Total": {
            "value": 236254,
            "margin_of_error": 0
          },
          "Male": {
            "value": 118902,
            "margin_of_error": 46,
            "percentage": 0.503
          },
          "Female": {
            "value": 117352,
            "margin_of_error": 46,
            "percentage": 0.497
          }
        },
        "Race and ethnicity": {
          "meta": {
            "table_id": "B03002",
            "universe": "Total population"
          },
          "Total": {
            "value": 236254,
            "margin_of_error": 0
          },
          "Not Hispanic or Latino": {
            "value": 198682,
            "margin_of_error": 0,
            "percentage": 0.841
          },
          "Not Hispanic or Latino: White alone": {
            "value": 136939,
            "margin_of_error": 814,
            "percentage": 0.689
          },
          "Not Hispanic or Latino: Black or African American alone": {
            "value": 21913,
            "margin_of_error": 493,
            "percentage": 0.11
          },
          "Not Hispanic or Latino: American Indian and Alaska Native alone": {
            "value": 268,
            "margin_of_error": 101,
            "percentage": 0.001
          },
          "Not Hispanic or Latino: Asian alone": {
            "value": 24753,
            "margin_of_error": 719,
            "percentage": 0.125
          },
          "Not Hispanic or Latino: Native Hawaiian and Other Pacific Islander alone": {
            "value": 82,
            "margin_of_error": 68,
            "percentage": 0
          },
          "Not Hispanic or Latino: Some other race alone": {
            "value": 1646,
            "margin_of_error": 441,
            "percentage": 0.008
          },
          "Not Hispanic or Latino: Two or more races": {
            "value": 13081,
            "margin_of_error": 1095,
            "percentage": 0.066
          },
          "Not Hispanic or Latino: Two or more races: Two races including Some other race": {
            "value": 3208,
            "margin_of_error": 709,
            "percentage": 0.245
          },
          "Not Hispanic or Latino: Two or more races: Two races excluding Some other race, and three or more races": {
            "value": 9873,
            "margin_of_error": 922,
            "percentage": 0.755
          },
          "Hispanic or Latino": {
            "value": 37572,
            "margin_of_error": 0,
            "percentage": 0.159
          },
          "Hispanic or Latino: White alone": {
            "value": 5701,
            "margin_of_error": 728,
            "percentage": 0.152
          },
          "Hispanic or Latino: Black or African American alone": {
            "value": 414,
            "margin_of_error": 155,
            "percentage": 0.011
          },
          "Hispanic or Latino: American Indian and Alaska Native alone": {
            "value": 1208,
            "margin_of_error": 590,
            "percentage": 0.032
          },
          "Hispanic or Latino: Asian alone": {
            "value": 170,
            "margin_of_error": 97,
            "percentage": 0.005
          },
          "Hispanic or Latino: Native Hawaiian and Other Pacific Islander alone": {
            "value": 27,
            "margin_of_error": 39,
            "percentage": 0.001
          },
          "Hispanic or Latino: Some other race alone": {
            "value": 11602,
            "margin_of_error": 1276,
            "percentage": 0.309
          },
          "Hispanic or Latino: Two or more races": {
            "value": 18450,
            "margin_of_error": 1405,
            "percentage": 0.491
          },
          "Hispanic or Latino: Two or more races: Two races including Some other race": {
            "value": 16516,
            "margin_of_error": 1357,
            "percentage": 0.895
          },
          "Hispanic or Latino: Two or more races: Two races excluding Some other race, and three or more races": {
            "value": 1934,
            "margin_of_error": 448,
            "percentage": 0.105
          }
        },
        "meta": {
          "geography": "county"
        }
      }
    }
  }
...
```

> To get `acs-demographics-tract` field appends for an address or a coordinate:

```shell
curl "https://api.geocod.io/v2/geocode?q=1109+N+Highland+St%2C+Arlington+VA&fields=acs-demographics-tract&api_key=YOUR_API_KEY"
curl "https://api.geocod.io/v2/reverse?q=38.886672,-77.094735&fields=acs-demographics-tract&api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

location = geocodio.geocode(['1109 N Highland St, Arlington VA'], ['acs-demographics-tract'])
location = geocodio.reverse(['38.886672,-77.094735'], ['acs-demographics-tract'])
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

response = client.geocode("1109 N Highland St, Arlington VA", fields=["acs-demographics-tract"])
response = client.reverse("38.886672,-77.094735", fields=["acs-demographics-tract"])
```

```php
<?php
$response = $geocoder->geocode('1109 N Highland St, Arlington VA', ['acs-demographics-tract']);
$response = $geocoder->reverse('38.886672,-77.094735', ['acs-demographics-tract']);
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocodio = new Geocodio('YOUR_API_KEY');

geocoder.geocode('1109 N Highland St, Arlington VA', ['acs-demographics-tract'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);

geocoder.reverse('38.886672,-77.094735', ['acs-demographics-tract'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example for "1109 N Highland St, Arlington VA":

```json
...
  "fields": {
    "census": {
      "2024": {
        "census_year": 2024,
        "state_fips": "51",
        "county_fips": "51013",
        "tract_code": "101801",
        "block_code": "2004",
        "block_group": "2",
        "full_fips": "510131018012004",
        "place": {
          "name": "Arlington",
          "fips": "5103000"
        },
        "metro_micro_statistical_area": {
          "name": "Washington-Arlington-Alexandria, DC-VA-MD-WV",
          "area_code": "47900",
          "type": "metropolitan"
        },
        "combined_statistical_area": {
          "name": "Washington-Baltimore-Arlington, DC-MD-VA-WV-PA",
          "area_code": "548"
        },
        "metropolitan_division": {
          "name": "Arlington-Alexandria-Reston, VA-WV",
          "area_code": "11694"
        },
        "county_subdivision": {
          "name": "Arlington",
          "fips": "90072",
          "fips_class": {
            "class_code": "Z7",
            "description": "A county subdivision that is coextensive with a county or equivalent feature or all or part of an incorporated place that the Census Bureau recognizes separately"
          }
        },
        "source": "US Census Bureau"
      }
    },
    "acs": {
      "meta": {
        "source": "American Community Survey from the US Census Bureau",
        "survey_years": "2020-2024",
        "survey_duration_years": "5"
      },
      "demographics": {
        "Median age": {
          "meta": {
            "table_id": "B01002",
            "universe": "Total population"
          },
          "Total": {
            "value": 33.3,
            "margin_of_error": 1.2
          },
          "Male": {
            "value": 33.9,
            "margin_of_error": 2.7
          },
          "Female": {
            "value": 33.2,
            "margin_of_error": 1.2
          }
        },
        "Population by age range": {
          "meta": {
            "table_id": "B01001",
            "universe": "Total population"
          },
          "Total": {
            "value": 2937,
            "margin_of_error": 336
          },
          "Male": {
            "value": 1598,
            "margin_of_error": 220,
            "percentage": 0.544
          },
          "Male: Under 5 years": {
            "value": 71,
            "margin_of_error": 41,
            "percentage": 0.044
          },
          "Male: 5 to 9 years": {
            "value": 3,
            "margin_of_error": 6,
            "percentage": 0.002
          },
          "Male: 10 to 14 years": {
            "value": 10,
            "margin_of_error": 14,
            "percentage": 0.006
          },
          "Male: 15 to 17 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Male: 18 and 19 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Male: 20 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Male: 21 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Male: 22 to 24 years": {
            "value": 207,
            "margin_of_error": 115,
            "percentage": 0.13
          },
          "Male: 25 to 29 years": {
            "value": 408,
            "margin_of_error": 125,
            "percentage": 0.255
          },
          "Male: 30 to 34 years": {
            "value": 162,
            "margin_of_error": 68,
            "percentage": 0.101
          },
          "Male: 35 to 39 years": {
            "value": 191,
            "margin_of_error": 65,
            "percentage": 0.12
          },
          "Male: 40 to 44 years": {
            "value": 66,
            "margin_of_error": 37,
            "percentage": 0.041
          },
          "Male: 45 to 49 years": {
            "value": 124,
            "margin_of_error": 96,
            "percentage": 0.078
          },
          "Male: 50 to 54 years": {
            "value": 163,
            "margin_of_error": 92,
            "percentage": 0.102
          },
          "Male: 55 to 59 years": {
            "value": 71,
            "margin_of_error": 70,
            "percentage": 0.044
          },
          "Male: 60 and 61 years": {
            "value": 21,
            "margin_of_error": 26,
            "percentage": 0.013
          },
          "Male: 62 to 64 years": {
            "value": 8,
            "margin_of_error": 13,
            "percentage": 0.005
          },
          "Male: 65 and 66 years": {
            "value": 28,
            "margin_of_error": 25,
            "percentage": 0.018
          },
          "Male: 67 to 69 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Male: 70 to 74 years": {
            "value": 46,
            "margin_of_error": 32,
            "percentage": 0.029
          },
          "Male: 75 to 79 years": {
            "value": 19,
            "margin_of_error": 21,
            "percentage": 0.012
          },
          "Male: 80 to 84 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Male: 85 years and over": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female": {
            "value": 1339,
            "margin_of_error": 195,
            "percentage": 0.456
          },
          "Female: Under 5 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: 5 to 9 years": {
            "value": 69,
            "margin_of_error": 56,
            "percentage": 0.052
          },
          "Female: 10 to 14 years": {
            "value": 63,
            "margin_of_error": 60,
            "percentage": 0.047
          },
          "Female: 15 to 17 years": {
            "value": 17,
            "margin_of_error": 28,
            "percentage": 0.013
          },
          "Female: 18 and 19 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: 20 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: 21 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: 22 to 24 years": {
            "value": 119,
            "margin_of_error": 107,
            "percentage": 0.089
          },
          "Female: 25 to 29 years": {
            "value": 240,
            "margin_of_error": 80,
            "percentage": 0.179
          },
          "Female: 30 to 34 years": {
            "value": 291,
            "margin_of_error": 100,
            "percentage": 0.217
          },
          "Female: 35 to 39 years": {
            "value": 144,
            "margin_of_error": 66,
            "percentage": 0.108
          },
          "Female: 40 to 44 years": {
            "value": 19,
            "margin_of_error": 22,
            "percentage": 0.014
          },
          "Female: 45 to 49 years": {
            "value": 207,
            "margin_of_error": 75,
            "percentage": 0.155
          },
          "Female: 50 to 54 years": {
            "value": 78,
            "margin_of_error": 55,
            "percentage": 0.058
          },
          "Female: 55 to 59 years": {
            "value": 13,
            "margin_of_error": 21,
            "percentage": 0.01
          },
          "Female: 60 and 61 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: 62 to 64 years": {
            "value": 8,
            "margin_of_error": 13,
            "percentage": 0.006
          },
          "Female: 65 and 66 years": {
            "value": 15,
            "margin_of_error": 20,
            "percentage": 0.011
          },
          "Female: 67 to 69 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: 70 to 74 years": {
            "value": 40,
            "margin_of_error": 31,
            "percentage": 0.03
          },
          "Female: 75 to 79 years": {
            "value": 16,
            "margin_of_error": 18,
            "percentage": 0.012
          },
          "Female: 80 to 84 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: 85 years and over": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          }
        },
        "Sex": {
          "meta": {
            "table_id": "B01001",
            "universe": "Total population"
          },
          "Total": {
            "value": 2937,
            "margin_of_error": 336
          },
          "Male": {
            "value": 1598,
            "margin_of_error": 220,
            "percentage": 0.544
          },
          "Female": {
            "value": 1339,
            "margin_of_error": 195,
            "percentage": 0.456
          }
        },
        "Race and ethnicity": {
          "meta": {
            "table_id": "B03002",
            "universe": "Total population"
          },
          "Total": {
            "value": 2937,
            "margin_of_error": 336
          },
          "Not Hispanic or Latino": {
            "value": 2804,
            "margin_of_error": 343,
            "percentage": 0.955
          },
          "Not Hispanic or Latino: White alone": {
            "value": 2093,
            "margin_of_error": 274,
            "percentage": 0.746
          },
          "Not Hispanic or Latino: Black or African American alone": {
            "value": 104,
            "margin_of_error": 85,
            "percentage": 0.037
          },
          "Not Hispanic or Latino: American Indian and Alaska Native alone": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Not Hispanic or Latino: Asian alone": {
            "value": 369,
            "margin_of_error": 152,
            "percentage": 0.132
          },
          "Not Hispanic or Latino: Native Hawaiian and Other Pacific Islander alone": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Not Hispanic or Latino: Some other race alone": {
            "value": 31,
            "margin_of_error": 30,
            "percentage": 0.011
          },
          "Not Hispanic or Latino: Two or more races": {
            "value": 207,
            "margin_of_error": 74,
            "percentage": 0.074
          },
          "Not Hispanic or Latino: Two or more races: Two races including Some other race": {
            "value": 5,
            "margin_of_error": 9,
            "percentage": 0.024
          },
          "Not Hispanic or Latino: Two or more races: Two races excluding Some other race, and three or more races": {
            "value": 202,
            "margin_of_error": 75,
            "percentage": 0.976
          },
          "Hispanic or Latino": {
            "value": 133,
            "margin_of_error": 60,
            "percentage": 0.045
          },
          "Hispanic or Latino: White alone": {
            "value": 21,
            "margin_of_error": 23,
            "percentage": 0.158
          },
          "Hispanic or Latino: Black or African American alone": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Hispanic or Latino: American Indian and Alaska Native alone": {
            "value": 6,
            "margin_of_error": 11,
            "percentage": 0.045
          },
          "Hispanic or Latino: Asian alone": {
            "value": 22,
            "margin_of_error": 30,
            "percentage": 0.165
          },
          "Hispanic or Latino: Native Hawaiian and Other Pacific Islander alone": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Hispanic or Latino: Some other race alone": {
            "value": 36,
            "margin_of_error": 27,
            "percentage": 0.271
          },
          "Hispanic or Latino: Two or more races": {
            "value": 48,
            "margin_of_error": 45,
            "percentage": 0.361
          },
          "Hispanic or Latino: Two or more races: Two races including Some other race": {
            "value": 48,
            "margin_of_error": 45,
            "percentage": 1
          },
          "Hispanic or Latino: Two or more races: Two races excluding Some other race, and three or more races": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          }
        },
        "meta": {
          "geography": "tract"
        }
      }
    }
  }
...
```

Geocodio can return ACS data at several geographic levels:

| Name                                       | API Name             |
|--------------------------------------------|----------------------|
| Census Block Group                         | `block_group`        |
| Census Tract                               | `tract`              |
| ZIP Code Tabulation Area (ZCTA)            | `zcta`               |
| Census Place                               | `place`              |
| County Subdivision                         | `county_subdivision` |
| County                                     | `county`             |
| Census Metropolitan Statistical Area (MSA) | `msa`                |
| State                                      | `state`              |
| Census Division                            | `division`           |
| Census Region                              | `region`             |
| Nation                                     | `nation`             |

To request ACS data for a specific geography, simply append the ACS field name with the **API Name** for the geography. For example, to get ACS demographic data for an address at the County level, you would request `acs-demographics-county`.

If you request an ACS field without specifying a geography, Geocodio will select the most appropriate geography based on your geocoding result:

| Census Geography   | [Accuracy Type](#accuracy-score)                                                                                      |
|--------------------|-----------------------------------------------------------------------------------------------------------------------|
| Census Block Group | `rooftop`, `range_interpolation`, `nearest_street`, `point`, `nearest_rooftop_match`, `street_center`, `intersection` |
| Census Place       | `nearest_place`, `place`                                                                                              |
| County             | `county`                                                                                                              |
| State              | `state`                                                                                                               |

`zcta`, `division`, `region` and `nation` are only returned when you request them explicitly. They are never selected automatically, which is why the table above lists fewer geographies than the one before it.

> Example for "1109 N Highland St, Arlington VA" with `fields=acs-demographics-zcta`:

```json
...
"acs": {
  "demographics": {
    "Sex": {
      "meta": { "table_id": "B01001", "universe": "Total population" },
      "Total":  { "value": 37473, "margin_of_error": 1585 },
      "Male":   { "value": 18754, "margin_of_error": 1000, "percentage": 0.5 },
      "Female": { "value": 18719, "margin_of_error": 934, "percentage": 0.5 }
    },
    ...
    "meta": { "geography": "zcta" }
  },
  "meta": {
    "source": "American Community Survey from the US Census Bureau",
    "survey_years": "2020-2024",
    "survey_duration_years": "5"
  }
}
...
```

> The same address with `fields=acs-demographics-nation`:

```json
...
"Sex": {
  "meta": { "table_id": "B01001", "universe": "Total population" },
  "Total":  { "value": 334922499, "margin_of_error": 0 },
  "Male":   { "value": 165808018, "margin_of_error": 7054, "percentage": 0.495 },
  "Female": { "value": 169114481, "margin_of_error": 7067, "percentage": 0.505 }
},
...
"meta": { "geography": "nation" }
...
```

The response shape is identical at every geography. Only `meta.geography` changes, carrying the **API Name** of the level the values were pulled from.

The geographies nest, so the same address returns progressively larger populations as you move up the list. Using `Sex.Total.value` from `acs-demographics` for `1109 N Highland St, Arlington VA` (which sits in Census region 3, South, and division 5, South Atlantic):

| Geography  | Total population |
|------------|------------------|
| `zcta`     | 37,473           |
| `division` | 67,775,152       |
| `region`   | 129,288,316      |
| `nation`   | 334,922,499      |

For `nation`, `region` and `division`, `margin_of_error` is `0` on the grand total, because the Census Bureau publishes those as controlled totals rather than sampled estimates. Subgroup rows still carry real margins of error.

### ZIP Code Tabulation Areas vs. ZIP codes

> A ZIP code with no matching ZCTA, e.g. `q=20077&fields=acs-demographics-zcta`:

```json
...
"fields": {
  "census": { ... }
},
"_warnings": [
  "acs field was skipped since no data was found for the requested category and geography"
]
...
```

A ZIP Code Tabulation Area is the Census Bureau's *approximation* of a USPS ZIP code, built by assigning each Census block the ZIP code used by most addresses inside it. It is not the USPS ZIP code itself, and the two sets do not line up one-to-one:

* There are 33,791 ZCTAs versus 41,540 distinct USPS ZIP codes.
* 7,758 USPS ZIP codes (18.7%) have no ZCTA sharing their code. These are overwhelmingly PO-box-only and single-point ZIP codes, which contain no residential population for the Census Bureau to tabulate.

> **Warning:** When an address has no corresponding ZCTA, the `acs` field is **absent from the response entirely** — not present with a `null` value — and a message is added to `_warnings`. Make sure your code handles the missing key rather than assuming `acs` is always there.

For those records, request `county` or `tract` instead. Both are defined everywhere an address geocodes, so they make a good fallback when `zcta` comes back empty.

### National, region and division benchmarks

`nation` exists so that you can compute demographic indices without maintaining national figures yourself. An index compares a local percentage against the national one, where 100 is parity:

`index = (local percentage / national percentage) x 100`

For example, the Hispanic or Latino share for `1109 N Highland St, Arlington VA`:

* `acs-demographics-zcta` returns `0.110`
* `acs-demographics-nation` returns `0.193`
* `index = 0.110 / 0.193 x 100` = **57**

An index of 57 means the neighborhood's Hispanic or Latino share is about 43% below the national share. Previously this required looking up the national figures on [data.census.gov](https://data.census.gov) by hand and hard-coding them as constants.

`region` and `division` provide intermediate benchmarks for anyone who wants a comparison broader than a county but narrower than the whole country.

> **Note:** Percentages are relative to the parent row, not the grand total. An indented key such as `Hispanic or Latino: White alone` is a share of `Hispanic or Latino`, so multiply down the chain to get a percent-of-total.

### Metadata

> ACS overall metadata:

```json
...
"fields": {
  "acs": {
    "meta": {
      "source": "American Community Survey from the US Census Bureau",
      "survey_years": "2020-2024",
      "survey_duration_years": "5"
    },
    ...
  }
}
```

> Individual ACS table result metadata:

```json
...
"Median age": {
  "meta": {
    "table_id": "B01002",
    "universe": "Total population"
   },
   ...
}

> Individual ACS field metadata:

```json
"fields": {
  "acs": {
    "housing": {
      ...
      "meta": {
        "geography": "block_group"
      }
    },
    ...
  }
}
```

A `meta` field with high level data information is returned for all `acs` results in general as well as individual ACS appends and individual ACS values.

This contains information about the exact ACS results Geocodio is returning, including the Census years covered and the corresponding geography level. Geocodio always uses 5-year estimates, and always uses the most recent data that is available.

For each individual result, Geocodio returns the [official ACS table id](https://www.census.gov/programs-surveys/acs/library/handbooks/summary-file.html) as well as the "universe" that the values covers.

The universe can be values such as `Households`, `Population 15 Years and Older`, `Total population`, etc.

## Census: Demographics
**Field name: `acs-demographics`**

> To get `acs-demographics` field appends for an address or a coordinate:

```shell
curl "https://api.geocod.io/v2/geocode?q=1109+N+Highland+St%2C+Arlington+VA&fields=acs-demographics&api_key=YOUR_API_KEY"
curl "https://api.geocod.io/v2/reverse?q=38.886672,-77.094735&fields=acs-demographics&api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

location = geocodio.geocode(['1109 N Highland St, Arlington VA'], ['acs-demographics'])
location = geocodio.reverse(['38.886672,-77.094735'], ['acs-demographics'])
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

response = client.geocode("1109 N Highland St, Arlington VA", fields=["acs-demographics"])
response = client.reverse("38.886672,-77.094735", fields=["acs-demographics"])
```

```php
<?php
$response = $geocoder->geocode('1109 N Highland St, Arlington VA', ['acs-demographics']);
$response = $geocoder->reverse('38.886672,-77.094735', ['acs-demographics']);
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocodio = new Geocodio('YOUR_API_KEY');

geocoder.geocode('1109 N Highland St, Arlington VA', ['acs-demographics'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);

geocoder.reverse('38.886672,-77.094735', ['acs-demographics'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example for "1109 N Highland St, Arlington VA":

```json
...
  "fields": {
    "census": {
      "2024": {
        "census_year": 2024,
        "state_fips": "51",
        "county_fips": "51013",
        "tract_code": "101801",
        "block_code": "2004",
        "block_group": "2",
        "full_fips": "510131018012004",
        "place": {
          "name": "Arlington",
          "fips": "5103000"
        },
        "metro_micro_statistical_area": {
          "name": "Washington-Arlington-Alexandria, DC-VA-MD-WV",
          "area_code": "47900",
          "type": "metropolitan"
        },
        "combined_statistical_area": {
          "name": "Washington-Baltimore-Arlington, DC-MD-VA-WV-PA",
          "area_code": "548"
        },
        "metropolitan_division": {
          "name": "Arlington-Alexandria-Reston, VA-WV",
          "area_code": "11694"
        },
        "county_subdivision": {
          "name": "Arlington",
          "fips": "90072",
          "fips_class": {
            "class_code": "Z7",
            "description": "A county subdivision that is coextensive with a county or equivalent feature or all or part of an incorporated place that the Census Bureau recognizes separately"
          }
        },
        "source": "US Census Bureau"
      }
    },
    "acs": {
      "meta": {
        "source": "American Community Survey from the US Census Bureau",
        "survey_years": "2020-2024",
        "survey_duration_years": "5"
      },
      "demographics": {
        "Median age": {
          "meta": {
            "table_id": "B01002",
            "universe": "Total population"
          },
          "Total": {
            "value": 34,
            "margin_of_error": 2.6
          },
          "Male": {
            "value": 36.2,
            "margin_of_error": 4.3
          },
          "Female": {
            "value": 33.3,
            "margin_of_error": 1.3
          }
        },
        "Population by age range": {
          "meta": {
            "table_id": "B01001",
            "universe": "Total population"
          },
          "Total": {
            "value": 1554,
            "margin_of_error": 291
          },
          "Male": {
            "value": 775,
            "margin_of_error": 170,
            "percentage": 0.499
          },
          "Male: Under 5 years": {
            "value": 35,
            "margin_of_error": 31,
            "percentage": 0.045
          },
          "Male: 5 to 9 years": {
            "value": 3,
            "margin_of_error": 6,
            "percentage": 0.004
          },
          "Male: 10 to 14 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Male: 15 to 17 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Male: 18 and 19 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Male: 20 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Male: 21 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Male: 22 to 24 years": {
            "value": 62,
            "margin_of_error": 72,
            "percentage": 0.08
          },
          "Male: 25 to 29 years": {
            "value": 168,
            "margin_of_error": 86,
            "percentage": 0.217
          },
          "Male: 30 to 34 years": {
            "value": 106,
            "margin_of_error": 61,
            "percentage": 0.137
          },
          "Male: 35 to 39 years": {
            "value": 127,
            "margin_of_error": 59,
            "percentage": 0.164
          },
          "Male: 40 to 44 years": {
            "value": 23,
            "margin_of_error": 22,
            "percentage": 0.03
          },
          "Male: 45 to 49 years": {
            "value": 87,
            "margin_of_error": 83,
            "percentage": 0.112
          },
          "Male: 50 to 54 years": {
            "value": 94,
            "margin_of_error": 73,
            "percentage": 0.121
          },
          "Male: 55 to 59 years": {
            "value": 14,
            "margin_of_error": 23,
            "percentage": 0.018
          },
          "Male: 60 and 61 years": {
            "value": 13,
            "margin_of_error": 23,
            "percentage": 0.017
          },
          "Male: 62 to 64 years": {
            "value": 8,
            "margin_of_error": 13,
            "percentage": 0.01
          },
          "Male: 65 and 66 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Male: 67 to 69 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Male: 70 to 74 years": {
            "value": 16,
            "margin_of_error": 22,
            "percentage": 0.021
          },
          "Male: 75 to 79 years": {
            "value": 19,
            "margin_of_error": 21,
            "percentage": 0.025
          },
          "Male: 80 to 84 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Male: 85 years and over": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female": {
            "value": 779,
            "margin_of_error": 161,
            "percentage": 0.501
          },
          "Female: Under 5 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: 5 to 9 years": {
            "value": 7,
            "margin_of_error": 12,
            "percentage": 0.009
          },
          "Female: 10 to 14 years": {
            "value": 47,
            "margin_of_error": 59,
            "percentage": 0.06
          },
          "Female: 15 to 17 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: 18 and 19 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: 20 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: 21 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: 22 to 24 years": {
            "value": 85,
            "margin_of_error": 100,
            "percentage": 0.109
          },
          "Female: 25 to 29 years": {
            "value": 120,
            "margin_of_error": 49,
            "percentage": 0.154
          },
          "Female: 30 to 34 years": {
            "value": 205,
            "margin_of_error": 82,
            "percentage": 0.263
          },
          "Female: 35 to 39 years": {
            "value": 72,
            "margin_of_error": 54,
            "percentage": 0.092
          },
          "Female: 40 to 44 years": {
            "value": 19,
            "margin_of_error": 22,
            "percentage": 0.024
          },
          "Female: 45 to 49 years": {
            "value": 107,
            "margin_of_error": 70,
            "percentage": 0.137
          },
          "Female: 50 to 54 years": {
            "value": 47,
            "margin_of_error": 52,
            "percentage": 0.06
          },
          "Female: 55 to 59 years": {
            "value": 13,
            "margin_of_error": 21,
            "percentage": 0.017
          },
          "Female: 60 and 61 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: 62 to 64 years": {
            "value": 8,
            "margin_of_error": 13,
            "percentage": 0.01
          },
          "Female: 65 and 66 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: 67 to 69 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: 70 to 74 years": {
            "value": 33,
            "margin_of_error": 29,
            "percentage": 0.042
          },
          "Female: 75 to 79 years": {
            "value": 16,
            "margin_of_error": 18,
            "percentage": 0.021
          },
          "Female: 80 to 84 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: 85 years and over": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          }
        },
        "Sex": {
          "meta": {
            "table_id": "B01001",
            "universe": "Total population"
          },
          "Total": {
            "value": 1554,
            "margin_of_error": 291
          },
          "Male": {
            "value": 775,
            "margin_of_error": 170,
            "percentage": 0.499
          },
          "Female": {
            "value": 779,
            "margin_of_error": 161,
            "percentage": 0.501
          }
        },
        "Race and ethnicity": {
          "meta": {
            "table_id": "B03002",
            "universe": "Total population"
          },
          "Total": {
            "value": 1554,
            "margin_of_error": 291
          },
          "Not Hispanic or Latino": {
            "value": 1478,
            "margin_of_error": 295,
            "percentage": 0.951
          },
          "Not Hispanic or Latino: White alone": {
            "value": 1116,
            "margin_of_error": 225,
            "percentage": 0.755
          },
          "Not Hispanic or Latino: Black or African American alone": {
            "value": 44,
            "margin_of_error": 54,
            "percentage": 0.03
          },
          "Not Hispanic or Latino: American Indian and Alaska Native alone": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Not Hispanic or Latino: Asian alone": {
            "value": 130,
            "margin_of_error": 95,
            "percentage": 0.088
          },
          "Not Hispanic or Latino: Native Hawaiian and Other Pacific Islander alone": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Not Hispanic or Latino: Some other race alone": {
            "value": 22,
            "margin_of_error": 26,
            "percentage": 0.015
          },
          "Not Hispanic or Latino: Two or more races": {
            "value": 166,
            "margin_of_error": 74,
            "percentage": 0.112
          },
          "Not Hispanic or Latino: Two or more races: Two races including Some other race": {
            "value": 5,
            "margin_of_error": 9,
            "percentage": 0.03
          },
          "Not Hispanic or Latino: Two or more races: Two races excluding Some other race, and three or more races": {
            "value": 161,
            "margin_of_error": 74,
            "percentage": 0.97
          },
          "Hispanic or Latino": {
            "value": 76,
            "margin_of_error": 45,
            "percentage": 0.049
          },
          "Hispanic or Latino: White alone": {
            "value": 21,
            "margin_of_error": 23,
            "percentage": 0.276
          },
          "Hispanic or Latino: Black or African American alone": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Hispanic or Latino: American Indian and Alaska Native alone": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Hispanic or Latino: Asian alone": {
            "value": 22,
            "margin_of_error": 30,
            "percentage": 0.289
          },
          "Hispanic or Latino: Native Hawaiian and Other Pacific Islander alone": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Hispanic or Latino: Some other race alone": {
            "value": 9,
            "margin_of_error": 13,
            "percentage": 0.118
          },
          "Hispanic or Latino: Two or more races": {
            "value": 24,
            "margin_of_error": 23,
            "percentage": 0.316
          },
          "Hispanic or Latino: Two or more races: Two races including Some other race": {
            "value": 24,
            "margin_of_error": 23,
            "percentage": 1
          },
          "Hispanic or Latino: Two or more races: Two races excluding Some other race, and three or more races": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          }
        },
        "meta": {
          "geography": "block_group"
        }
      }
    }
  }
...
```

Geocodio provides the data exactly as it is packaged by the Census Bureau in the breakouts it gives. The only change we have made is to add a "percentage" calculation to aid ease of use.

The data returned includes the following data points. For each data point, the data returned includes the value, margin of error, and percentage.

* Total (Table #B01002)
  * total, male, female
* Population by age range (Table #B01001)
  * Broken out by male and female
  * under 5 years, 5-9 years, 10-14 years, 15-17 years, 18-19 years, 20 years, 21 years, 22-24 years, 25-29 years, 30-34 years, 35-39 years, 40-44 years, 45-49 years, 50-54 years, 55-59 years, 60-64 years, 65-69 years, 70-74 years, 75-79 years, 80-84 years, 85 years and over
* Sex (Table $B01001)
  * total, male, female
* Race and ethnicity (Table #B03002)
  * Broken out by not-Hispanic or Latino and Hispanic or Latino
  * Not Hispanic or Latino, white alone, black or African American alone, American Indian and Alaska Native alone, Asian alone, Native Hawaiian and Other Pacific Islander alone; some other race alone; two or more races; two or more races: two races including some other race; two or more races: two races excluding some other race, and three or more races

> **Note:** We recognize that age, sex, gender, race and ethnicity are sensitive subjects. Accordingly, we return the categories exactly as the Census Bureau provides. We recognize that the categories listed may not be all-inclusive or use preferred terminology.

## Census: Income
**Field name: `acs-economics`**

> To get `acs-economics` field appends for an address or a coordinate:

```shell
curl "https://api.geocod.io/v2/geocode?q=1109+N+Highland+St%2C+Arlington+VA&fields=acs-economics&api_key=YOUR_API_KEY"
curl "https://api.geocod.io/v2/reverse?q=38.886672,-77.094735&fields=acs-economics&api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

location = geocodio.geocode(['1109 N Highland St, Arlington VA'], ['acs-economics'])
location = geocodio.reverse(['38.886672,-77.094735'], ['acs-economics'])
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

response = client.geocode("1109 N Highland St, Arlington VA", fields=["acs-economics"])
response = client.reverse("38.886672,-77.094735", fields=["acs-economics"])
```

```php
<?php
$response = $geocoder->geocode('1109 N Highland St, Arlington VA', ['acs-economics']);
$response = $geocoder->reverse('38.886672,-77.094735', ['acs-economics']);
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocodio = new Geocodio('YOUR_API_KEY');

geocoder.geocode('1109 N Highland St, Arlington VA', ['acs-economics'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);

geocoder.reverse('38.886672,-77.094735', ['acs-economics'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example for "1109 N Highland St, Arlington VA":

```json
...
  "fields": {
    "census": {
      "2024": {
        "census_year": 2024,
        "state_fips": "51",
        "county_fips": "51013",
        "tract_code": "101801",
        "block_code": "2004",
        "block_group": "2",
        "full_fips": "510131018012004",
        "place": {
          "name": "Arlington",
          "fips": "5103000"
        },
        "metro_micro_statistical_area": {
          "name": "Washington-Arlington-Alexandria, DC-VA-MD-WV",
          "area_code": "47900",
          "type": "metropolitan"
        },
        "combined_statistical_area": {
          "name": "Washington-Baltimore-Arlington, DC-MD-VA-WV-PA",
          "area_code": "548"
        },
        "metropolitan_division": {
          "name": "Arlington-Alexandria-Reston, VA-WV",
          "area_code": "11694"
        },
        "county_subdivision": {
          "name": "Arlington",
          "fips": "90072",
          "fips_class": {
            "class_code": "Z7",
            "description": "A county subdivision that is coextensive with a county or equivalent feature or all or part of an incorporated place that the Census Bureau recognizes separately"
          }
        },
        "source": "US Census Bureau"
      }
    },
    "acs": {
      "meta": {
        "source": "American Community Survey from the US Census Bureau",
        "survey_years": "2020-2024",
        "survey_duration_years": "5"
      },
      "economics": {
        "Number of households": {
          "meta": {
            "table_id": "B19001",
            "universe": "Households"
          },
          "Total": {
            "value": 887,
            "margin_of_error": 124
          }
        },
        "Median household income": {
          "meta": {
            "table_id": "B19013",
            "universe": "Households"
          },
          "Total": {
            "value": 202344,
            "margin_of_error": 29891
          }
        },
        "Household income": {
          "meta": {
            "table_id": "B19001",
            "universe": "Households"
          },
          "Less than $10,000": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "$10,000 to $14,999": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "$15,000 to $19,999": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "$20,000 to $24,999": {
            "value": 7,
            "margin_of_error": 11,
            "percentage": 0.008
          },
          "$25,000 to $29,999": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "$30,000 to $34,999": {
            "value": 31,
            "margin_of_error": 51,
            "percentage": 0.035
          },
          "$35,000 to $39,999": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "$40,000 to $44,999": {
            "value": 8,
            "margin_of_error": 13,
            "percentage": 0.009
          },
          "$45,000 to $49,999": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "$50,000 to $59,999": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "$60,000 to $74,999": {
            "value": 12,
            "margin_of_error": 16,
            "percentage": 0.014
          },
          "$75,000 to $99,999": {
            "value": 59,
            "margin_of_error": 57,
            "percentage": 0.067
          },
          "$100,000 to $124,999": {
            "value": 117,
            "margin_of_error": 63,
            "percentage": 0.132
          },
          "$125,000 to $149,999": {
            "value": 56,
            "margin_of_error": 55,
            "percentage": 0.063
          },
          "$150,000 to $199,999": {
            "value": 146,
            "margin_of_error": 83,
            "percentage": 0.165
          },
          "$200,000 or more": {
            "value": 451,
            "margin_of_error": 98,
            "percentage": 0.508
          }
        },
        "Per capita income": {
          "meta": {
            "table_id": "B19301",
            "universe": "Total population"
          },
          "Total": {
            "value": 153059,
            "margin_of_error": 34075
          }
        },
        "meta": {
          "geography": "block_group"
        }
      }
    }
  }
...
```

We provide the data exactly as it is packaged by the Census Bureau in the breakouts it gives. The only change we have made is to add a "percentage" calculation to aid ease of use.

The data returned includes the following data points. For each data point, the data returned includes the value, margin of error, and percentage.

* Median household income (Table #B19013)
* Household income (Table #B19001)
  * less than $10,000; $10,000-$14,999; $15,000-$19,999; $20,000-$24,999; $25,000-$29,999; $30,000-$34,999; $40,000-$44,999; $45,000-$49,999; $50,000-$59,000; $60,000-$74,999; $75,000-$99,999; $100,000-$124,999; $125,000-$149,000; $150,000-$199,999; $200,000 or more
* Per capita income (Table #B19301)

## Census: Households
**Field name: `acs-families`**

> To get `acs-families` field appends for an address or a coordinate:

```shell
curl "https://api.geocod.io/v2/geocode?q=1109+N+Highland+St%2C+Arlington+VA&fields=acs-families&api_key=YOUR_API_KEY"
curl "https://api.geocod.io/v2/reverse?q=38.886672,-77.094735&fields=acs-families&api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

location = geocodio.geocode(['1109 N Highland St, Arlington VA'], ['acs-families'])
location = geocodio.reverse(['38.886672,-77.094735'], ['acs-families'])
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

response = client.geocode("1109 N Highland St, Arlington VA", fields=["acs-families"])
response = client.reverse("38.886672,-77.094735", fields=["acs-families"])
```

```php
<?php
$response = $geocoder->geocode('1109 N Highland St, Arlington VA', ['acs-families']);
$response = $geocoder->reverse('38.886672,-77.094735', ['acs-families']);
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocodio = new Geocodio('YOUR_API_KEY');

geocoder.geocode('1109 N Highland St, Arlington VA', ['acs-families'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);

geocoder.reverse('38.886672,-77.094735', ['acs-families'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example for "1109 N Highland St, Arlington VA":

```json
...
  "fields": {
    "census": {
      "2024": {
        "census_year": 2024,
        "state_fips": "51",
        "county_fips": "51013",
        "tract_code": "101801",
        "block_code": "2004",
        "block_group": "2",
        "full_fips": "510131018012004",
        "place": {
          "name": "Arlington",
          "fips": "5103000"
        },
        "metro_micro_statistical_area": {
          "name": "Washington-Arlington-Alexandria, DC-VA-MD-WV",
          "area_code": "47900",
          "type": "metropolitan"
        },
        "combined_statistical_area": {
          "name": "Washington-Baltimore-Arlington, DC-MD-VA-WV-PA",
          "area_code": "548"
        },
        "metropolitan_division": {
          "name": "Arlington-Alexandria-Reston, VA-WV",
          "area_code": "11694"
        },
        "county_subdivision": {
          "name": "Arlington",
          "fips": "90072",
          "fips_class": {
            "class_code": "Z7",
            "description": "A county subdivision that is coextensive with a county or equivalent feature or all or part of an incorporated place that the Census Bureau recognizes separately"
          }
        },
        "source": "US Census Bureau"
      }
    },
    "acs": {
      "meta": {
        "source": "American Community Survey from the US Census Bureau",
        "survey_years": "2020-2024",
        "survey_duration_years": "5"
      },
      "families": {
        "Household type by household": {
          "meta": {
            "table_id": "B11001",
            "universe": "Households"
          },
          "Total": {
            "value": 887,
            "margin_of_error": 124
          },
          "Family households": {
            "value": 345,
            "margin_of_error": 100,
            "percentage": 0.389
          },
          "Family households: Married-couple family": {
            "value": 338,
            "margin_of_error": 101,
            "percentage": 0.98
          },
          "Family households: Other family": {
            "value": 7,
            "margin_of_error": 13,
            "percentage": 0.02
          },
          "Family households: Other family: Male householder, no spouse present": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Family households: Other family: Female householder, no spouse present": {
            "value": 7,
            "margin_of_error": 13,
            "percentage": 1
          },
          "Nonfamily households": {
            "value": 542,
            "margin_of_error": 127,
            "percentage": 0.611
          },
          "Nonfamily households: Householder living alone": {
            "value": 349,
            "margin_of_error": 84,
            "percentage": 0.644
          },
          "Nonfamily households: Householder not living alone": {
            "value": 193,
            "margin_of_error": 96,
            "percentage": 0.356
          }
        },
        "Household type by population": {
          "meta": {
            "table_id": "B11002",
            "universe": "Population in Households"
          },
          "Total": {
            "value": 1554,
            "margin_of_error": 291
          },
          "In family households": {
            "value": 762,
            "margin_of_error": 220,
            "percentage": 0.49
          },
          "In family households: In married-couple family": {
            "value": 746,
            "margin_of_error": 221,
            "percentage": 0.979
          },
          "In family households: In married-couple family: Relatives": {
            "value": 746,
            "margin_of_error": 221,
            "percentage": 1
          },
          "In family households: In married-couple family: Nonrelatives": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "In family households: In male householder, no spouse present, family": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "In family households: In male householder, no spouse present, family: Relatives": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "In family households: In male householder, no spouse present, family: Nonrelatives": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "In family households: In female householder, no spouse present, family": {
            "value": 16,
            "margin_of_error": 27,
            "percentage": 0.021
          },
          "In family households: In female householder, no spouse present, family: Relatives": {
            "value": 16,
            "margin_of_error": 27,
            "percentage": 1
          },
          "In family households: In female householder, no spouse present, family: Nonrelatives": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "In nonfamily households": {
            "value": 792,
            "margin_of_error": 270,
            "percentage": 0.51
          }
        },
        "Marital status": {
          "meta": {
            "table_id": "B12001",
            "universe": "Population 15 Years And Older"
          },
          "Male": {
            "value": 737,
            "margin_of_error": 165,
            "percentage": 0.504
          },
          "Male: Never married": {
            "value": 354,
            "margin_of_error": 160,
            "percentage": 0.48
          },
          "Male: Now married": {
            "value": 375,
            "margin_of_error": 108,
            "percentage": 0.509
          },
          "Male: Now married: Married, spouse present": {
            "value": 340,
            "margin_of_error": 101,
            "percentage": 0.907
          },
          "Male: Now married: Married, spouse absent": {
            "value": 35,
            "margin_of_error": 44,
            "percentage": 0.093
          },
          "Male: Now married: Married, spouse absent: Separated": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Male: Now married: Married, spouse absent: Other": {
            "value": 35,
            "margin_of_error": 44,
            "percentage": 1
          },
          "Male: Widowed": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Male: Divorced": {
            "value": 8,
            "margin_of_error": 9,
            "percentage": 0.011
          },
          "Female": {
            "value": 725,
            "margin_of_error": 143,
            "percentage": 0.496
          },
          "Female: Never married": {
            "value": 359,
            "margin_of_error": 134,
            "percentage": 0.495
          },
          "Female: Now married": {
            "value": 317,
            "margin_of_error": 89,
            "percentage": 0.437
          },
          "Female: Now married: Married, spouse present": {
            "value": 314,
            "margin_of_error": 89,
            "percentage": 0.991
          },
          "Female: Now married: Married, spouse absent": {
            "value": 3,
            "margin_of_error": 5,
            "percentage": 0.009
          },
          "Female: Now married: Married, spouse absent: Separated": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: Now married: Married, spouse absent: Other": {
            "value": 3,
            "margin_of_error": 5,
            "percentage": 1
          },
          "Female: Widowed": {
            "value": 8,
            "margin_of_error": 13,
            "percentage": 0.011
          },
          "Female: Divorced": {
            "value": 41,
            "margin_of_error": 31,
            "percentage": 0.057
          }
        },
        "Family Type by Presence and Age of Own Children Under 18 Years": {
          "meta": {
            "table_id": "B11003",
            "universe": "Families"
          },
          "Total": {
            "value": 345,
            "margin_of_error": 100
          },
          "Married-couple family": {
            "value": 338,
            "margin_of_error": 101,
            "percentage": 0.98
          },
          "Married-couple family: With own children of the householder under 18 years": {
            "value": 90,
            "margin_of_error": 60,
            "percentage": 0.266
          },
          "Married-couple family: With own children of the householder under 18 years: Under 6 years only": {
            "value": 45,
            "margin_of_error": 31,
            "percentage": 0.5
          },
          "Married-couple family: With own children of the householder under 18 years: Under 6 years and 6 to 17 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Married-couple family: With own children of the householder under 18 years: 6 to 17 years only": {
            "value": 45,
            "margin_of_error": 54,
            "percentage": 0.5
          },
          "Married-couple family: No own children of the householder under 18 years": {
            "value": 248,
            "margin_of_error": 93,
            "percentage": 0.734
          },
          "Other family": {
            "value": 7,
            "margin_of_error": 13,
            "percentage": 0.02
          },
          "Other family: Male householder, no spouse present": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Other family: Male householder, no spouse present: With own children of the householder under 18 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Other family: Male householder, no spouse present: With own children of the householder under 18 years: Under 6 years only": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Other family: Male householder, no spouse present: With own children of the householder under 18 years: Under 6 years and 6 to 17 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Other family: Male householder, no spouse present: With own children of the householder under 18 years: 6 to 17 years only": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Other family: Male householder, no spouse present: No own children of the householder under 18 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Other family: Female householder, no spouse present": {
            "value": 7,
            "margin_of_error": 13,
            "percentage": 1
          },
          "Other family: Female householder, no spouse present: With own children of the householder under 18 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Other family: Female householder, no spouse present: With own children of the householder under 18 years: Under 6 years only": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Other family: Female householder, no spouse present: With own children of the householder under 18 years: Under 6 years and 6 to 17 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Other family: Female householder, no spouse present: With own children of the householder under 18 years: 6 to 17 years only": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Other family: Female householder, no spouse present: No own children of the householder under 18 years": {
            "value": 7,
            "margin_of_error": 13,
            "percentage": 1
          }
        },
        "Average Household Size of Occupied Housing Units by Tenure": {
          "meta": {
            "table_id": "B25010",
            "universe": "Occupied housing units"
          },
          "Total": {
            "value": 1.75,
            "margin_of_error": 0.17
          },
          "Owner occupied": {
            "value": 1.81,
            "margin_of_error": 0.24
          },
          "Renter occupied": {
            "value": 1.73,
            "margin_of_error": 0.22
          }
        },
        "Own Children Under 18 Years by Family Type and Age": {
          "meta": {
            "table_id": "B09002",
            "universe": "Own children under 18 years"
          },
          "Total": {
            "value": 92,
            "margin_of_error": 64
          },
          "In married-couple families": {
            "value": 92,
            "margin_of_error": 64,
            "percentage": 1
          },
          "In married-couple families: Under 3 years": {
            "value": 35,
            "margin_of_error": 31,
            "percentage": 0.38
          },
          "In married-couple families: 3 and 4 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "In married-couple families: 5 years": {
            "value": 10,
            "margin_of_error": 14,
            "percentage": 0.109
          },
          "In married-couple families: 6 to 11 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "In married-couple families: 12 to 17 years": {
            "value": 47,
            "margin_of_error": 59,
            "percentage": 0.511
          },
          "In other families": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "In other families: Male householder, no spouse present": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "In other families: Male householder, no spouse present: Under 3 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "In other families: Male householder, no spouse present: 3 and 4 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "In other families: Male householder, no spouse present: 5 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "In other families: Male householder, no spouse present: 6 to 11 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "In other families: Male householder, no spouse present: 12 to 17 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "In other families: Female householder, no spouse present": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "In other families: Female householder, no spouse present: Under 3 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "In other families: Female householder, no spouse present: 3 and 4 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "In other families: Female householder, no spouse present: 5 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "In other families: Female householder, no spouse present: 6 to 11 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "In other families: Female householder, no spouse present: 12 to 17 years": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          }
        },
        "meta": {
          "geography": "block_group"
        }
      }
    }
  }
...
```

We provide the data exactly as it is packaged by the Census Bureau in the breakouts it gives. The only change we have made is to add a "percentage" calculation to aid ease of use.

The data returned includes the following data points. For each data point, the data returned includes the value, margin of error, and percentage.

* Family households (Table #B11001)
  * total; married-couple family; other family; other family: male householder, no wife present; other family: female householder, no husband present; non-family households; non-family households -- householder living alone; non-family households -- householder not living alone
* Household type by population (Table #B11002)
  * total; in family households; in married-couple family; in married-couple family: relatives; in married-couple family: non-relatives; in male householder, no spouse present, family; in male householder, no spouse present, family: relatives; in male householder, no spouse present, family: nonrelatives; in female householder, no spouse present, family; in female householder, no spouse present, family: relatives; in female householder, no spouse present, family: in nonfamily households
* Marital status (Table #B12001)
  * never married; now married; now married: married, spouse present; married, spouse absent; married, spouse absent: separated; married, spouse absent: other; married, spouse absent, widowed; married, spouse absent, divorced; male never married; female never married
* Family Type by Presence and Age of Own Children Under 18 Years (Table #B11003)
  * total; married-couple family; married-couple family: with own children of the householder under 18 years; married-couple family: with own children of the householder under 18 years: under 6 years only; married-couple family: with own children of the householder under 18 years: under 6 years and 6 to 17 years; married-couple family: with own children of the householder under 18 years: 6 to 17 years only; married-couple family: no own children of the householder under 18 years; other family; other family: male householder, no spouse present; other family: male householder, no spouse present: with own children of the householder under 18 years; other family: male householder, no spouse present: with own children of the householder under 18 years: under 6 years only; other family: male householder, no spouse present: with own children of the householder under 18 years: under 6 years and 6 to 17 years; other family: male householder, no spouse present: with own children of the householder under 18 years: 6 to 17 years only; other family: male householder, no spouse present: no own children of the householder under 18 years; other family: female householder, no spouse present; other family: female householder, no spouse present: with own children of the householder under 18 years; other family: female householder, no spouse present: with own children of the householder under 18 years: under 6 years only; other family: female householder, no spouse present: with own children of the householder under 18 years: under 6 years and 6 to 17 years; other family: female householder, no spouse present: with own children of the householder under 18 years: 6 to 17 years only; other family: female householder, no spouse present: no own children of the householder under 18 years
* Average Household Size of Occupied Housing Units by Tenure (Table #B25010)
  * total; owner occupied; renter occupied
* Own Children Under 18 Years by Family Type and Age (Table #B09002)
  * total; in married-couple families; in married-couple families: under 3 years; in married-couple families: 3 and 4 years; in married-couple families: 5 years; in married-couple families: 6 to 11 years; in married-couple families: 12 to 17 years; in other families; in other families: male householder, no spouse present; in other families: male householder, no spouse present: under 3 years; in other families: male householder, no spouse present: 3 and 4 years; in other families: male householder, no spouse present: 5 years; in other families: male householder, no spouse present: 6 to 11 years; in other families: male householder, no spouse present: 12 to 17 years; in other families: female householder, no spouse present; in other families: female householder, no spouse present: under 3 years; in other families: female householder, no spouse present: 3 and 4 years; in other families: female householder, no spouse present: 5 years; in other families: female householder, no spouse present: 6 to 11 years; in other families: female householder, no spouse present: 12 to 17 years

> **Note:** We recognize that household composition is a sensitive subject. Accordingly, we report the categories exactly as the Census Bureau provides. We recognize that the categories listed may not be all-inclusive or use preferred terminology.

## Census: Housing
**Field name: `acs-housing`**

> To get `acs-housing` field appends for an address or a coordinate:

```shell
curl "https://api.geocod.io/v2/geocode?q=1109+N+Highland+St%2C+Arlington+VA&fields=acs-housing&api_key=YOUR_API_KEY"
curl "https://api.geocod.io/v2/reverse?q=38.886672,-77.094735&fields=acs-housing&api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

location = geocodio.geocode(['1109 N Highland St, Arlington VA'], ['acs-housing'])
location = geocodio.reverse(['38.886672,-77.094735'], ['acs-housing'])
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

response = client.geocode("1109 N Highland St, Arlington VA", fields=["acs-housing"])
response = client.reverse("38.886672,-77.094735", fields=["acs-housing"])
```

```php
<?php
$response = $geocoder->geocode('1109 N Highland St, Arlington VA', ['acs-housing']);
$response = $geocoder->reverse('38.886672,-77.094735', ['acs-housing']);
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocodio = new Geocodio('YOUR_API_KEY');

geocoder.geocode('1109 N Highland St, Arlington VA', ['acs-housing'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);

geocoder.reverse('38.886672,-77.094735', ['acs-housing'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example for "1109 N Highland St, Arlington VA":

```json
...
  "fields": {
    "census": {
      "2024": {
        "census_year": 2024,
        "state_fips": "51",
        "county_fips": "51013",
        "tract_code": "101801",
        "block_code": "2004",
        "block_group": "2",
        "full_fips": "510131018012004",
        "place": {
          "name": "Arlington",
          "fips": "5103000"
        },
        "metro_micro_statistical_area": {
          "name": "Washington-Arlington-Alexandria, DC-VA-MD-WV",
          "area_code": "47900",
          "type": "metropolitan"
        },
        "combined_statistical_area": {
          "name": "Washington-Baltimore-Arlington, DC-MD-VA-WV-PA",
          "area_code": "548"
        },
        "metropolitan_division": {
          "name": "Arlington-Alexandria-Reston, VA-WV",
          "area_code": "11694"
        },
        "county_subdivision": {
          "name": "Arlington",
          "fips": "90072",
          "fips_class": {
            "class_code": "Z7",
            "description": "A county subdivision that is coextensive with a county or equivalent feature or all or part of an incorporated place that the Census Bureau recognizes separately"
          }
        },
        "source": "US Census Bureau"
      }
    },
    "acs": {
      "meta": {
        "source": "American Community Survey from the US Census Bureau",
        "survey_years": "2020-2024",
        "survey_duration_years": "5"
      },
      "housing": {
        "Number of housing units": {
          "meta": {
            "table_id": "B25002",
            "universe": "Housing Units"
          },
          "Total": {
            "value": 1000,
            "margin_of_error": 135
          }
        },
        "Occupancy status": {
          "meta": {
            "table_id": "B25002",
            "universe": "Housing Units"
          },
          "Occupied": {
            "value": 887,
            "margin_of_error": 124,
            "percentage": 0.887
          },
          "Vacant": {
            "value": 113,
            "margin_of_error": 74,
            "percentage": 0.113
          }
        },
        "Ownership of occupied units": {
          "meta": {
            "table_id": "B25003",
            "universe": "Occupied Housing Units"
          },
          "Owner occupied": {
            "value": 235,
            "margin_of_error": 79,
            "percentage": 0.265
          },
          "Renter occupied": {
            "value": 652,
            "margin_of_error": 117,
            "percentage": 0.735
          }
        },
        "Units in structure": {
          "meta": {
            "table_id": "B25024",
            "universe": "Housing Units"
          },
          "1, detached unit": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "1, attached unit": {
            "value": 142,
            "margin_of_error": 59,
            "percentage": 0.142
          },
          "2 units": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "3 or 4 units": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "5 to 9 units": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "10 to 19 unit": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "20 to 49 units": {
            "value": 10,
            "margin_of_error": 16,
            "percentage": 0.01
          },
          "50 or more units": {
            "value": 848,
            "margin_of_error": 139,
            "percentage": 0.848
          },
          "Mobile home units": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Boat, RV, van, etc. units": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          }
        },
        "Median value of owner-occupied housing units": {
          "meta": {
            "table_id": "B25077",
            "universe": "Owner-Occupied Housing Units"
          },
          "Total": {
            "value": 803600,
            "margin_of_error": 173895
          }
        },
        "Value of owner-occupied housing units": {
          "meta": {
            "table_id": "B25075",
            "universe": "Owner-Occupied Housing Units"
          },
          "Less than $10,000": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "$10,000 to $14,999": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "$15,000 to $19,999": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "$20,000 to $24,999": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "$25,000 to $29,999": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "$30,000 to $34,999": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "$35,000 to $39,999": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "$40,000 to $49,999": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "$50,000 to $59,999": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "$60,000 to $69,999": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "$70,000 to $79,999": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "$80,000 to $89,999": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "$90,000 to $99,999": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "$100,000 to $124,999": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "$125,000 to $149,999": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "$150,000 to $174,999": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "$175,000 to $199,999": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "$200,000 to $249,999": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "$250,000 to $299,999": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "$300,000 to $399,999": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "$400,000 to $499,999": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "$500,000 to $749,999": {
            "value": 107,
            "margin_of_error": 59,
            "percentage": 0.455
          },
          "$750,000 to $999,999": {
            "value": 49,
            "margin_of_error": 49,
            "percentage": 0.209
          },
          "$1,000,000 to $1,499,999": {
            "value": 76,
            "margin_of_error": 43,
            "percentage": 0.323
          },
          "$1,500,000 to $1,999,999": {
            "value": 3,
            "margin_of_error": 5,
            "percentage": 0.013
          },
          "$2,000,000 or more": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          }
        },
        "meta": {
          "geography": "block_group"
        }
      }
    }
  }
...
```

We provide the data exactly as it is packaged by the Census Bureau in the breakouts it gives. The only change we have made is to add a "percentage" calculation to aid ease of use.

For each data point, we return the value, margin of error, and percentage.

Data points returned are:

* Occupancy status (Table #B25002)
  * occupied
  * vacant
* Ownership of occupied units (Table #B25003)
  * owner-occupied
  * renter-occupied
* Units in structure (Table #B25024)
  * 1, detached unit; 1, attached unit; 2 units; 3 or 4 units; 5 to 9 units; 10 to 19 units; 20 to 49 units; 50 or more units; mobile home units; boat, RV, van, etc. units
* Median value of owner-occupied housing units (Table #B25077)
* Value of owner-occupied housing units (Table # B25075)
  * less than $10,000; $10,000-$14,999; $15,000-$19,999; $20,000-$29,000; $30,000-$34,999; $40,000-$49,999; $50,000-$59,000; $60,000-$69,999; $70,000-$79,000; $80,000-$89,999; $90,000-$99,999; $100,000-$124,999; $125,000-$149,000; $150,000-$174,999; $175,000-$199,999; $200,000-$249,000; $250,000-$299,000; $300,000-$399,999; $400,000-$499,000; $500,000-$749,000; $750,000-$999,999; $1,000,000-$1,499,999; $1,500,000-$1,999,999; $2,000,000 or more

## Social: Education & Veteran Status (Census)
**Field name: `acs-social`**

> To get `acs-social` field appends for an address or a coordinate:

```shell
curl "https://api.geocod.io/v2/geocode?q=1109+N+Highland+St%2C+Arlington+VA&fields=acs-social&api_key=YOUR_API_KEY"
curl "https://api.geocod.io/v2/reverse?q=38.886672,-77.094735&fields=acs-social&api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

location = geocodio.geocode(['1109 N Highland St, Arlington VA'], ['acs-social'])
location = geocodio.reverse(['38.886672,-77.094735'], ['acs-social'])
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

response = client.geocode("1109 N Highland St, Arlington VA", fields=["acs-social"])
response = client.reverse("38.886672,-77.094735", fields=["acs-social"])
```

```php
<?php
$response = $geocoder->geocode('1109 N Highland St, Arlington VA', ['acs-social']);
$response = $geocoder->reverse('38.886672,-77.094735', ['acs-social']);
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocodio = new Geocodio('YOUR_API_KEY');

geocoder.geocode('1109 N Highland St, Arlington VA', ['acs-social'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);

geocoder.reverse('38.886672,-77.094735', ['acs-social'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example for "1109 N Highland St, Arlington VA":

```json
...
  "fields": {
    "census": {
      "2024": {
        "census_year": 2024,
        "state_fips": "51",
        "county_fips": "51013",
        "tract_code": "101801",
        "block_code": "2004",
        "block_group": "2",
        "full_fips": "510131018012004",
        "place": {
          "name": "Arlington",
          "fips": "5103000"
        },
        "metro_micro_statistical_area": {
          "name": "Washington-Arlington-Alexandria, DC-VA-MD-WV",
          "area_code": "47900",
          "type": "metropolitan"
        },
        "combined_statistical_area": {
          "name": "Washington-Baltimore-Arlington, DC-MD-VA-WV-PA",
          "area_code": "548"
        },
        "metropolitan_division": {
          "name": "Arlington-Alexandria-Reston, VA-WV",
          "area_code": "11694"
        },
        "county_subdivision": {
          "name": "Arlington",
          "fips": "90072",
          "fips_class": {
            "class_code": "Z7",
            "description": "A county subdivision that is coextensive with a county or equivalent feature or all or part of an incorporated place that the Census Bureau recognizes separately"
          }
        },
        "source": "US Census Bureau"
      }
    },
    "acs": {
      "meta": {
        "source": "American Community Survey from the US Census Bureau",
        "survey_years": "2020-2024",
        "survey_duration_years": "5"
      },
      "social": {
        "Population by minimum level of education": {
          "meta": {
            "table_id": "B15002",
            "universe": "Population 25 Years And Over"
          },
          "Total": {
            "value": 1315,
            "margin_of_error": 178
          },
          "Male": {
            "value": 675,
            "margin_of_error": 125,
            "percentage": 0.513
          },
          "Male: No schooling completed": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Male: Nursery to 4th grade": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Male: 5th and 6th grade": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Male: 7th and 8th grade": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Male: 9th grade": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Male: 10th grade": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Male: 11th grade": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Male: 12th grade, no diploma": {
            "value": 6,
            "margin_of_error": 10,
            "percentage": 0.009
          },
          "Male: High school graduate (includes equivalency)": {
            "value": 8,
            "margin_of_error": 15,
            "percentage": 0.012
          },
          "Male: Some college, less than 1 year": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Male: Some college, 1 or more years, no degree": {
            "value": 24,
            "margin_of_error": 28,
            "percentage": 0.036
          },
          "Male: Associate's degree": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Male: Bachelor's degree": {
            "value": 277,
            "margin_of_error": 87,
            "percentage": 0.41
          },
          "Male: Master's degree": {
            "value": 254,
            "margin_of_error": 101,
            "percentage": 0.376
          },
          "Male: Professional school degree": {
            "value": 69,
            "margin_of_error": 55,
            "percentage": 0.102
          },
          "Male: Doctorate degree": {
            "value": 37,
            "margin_of_error": 46,
            "percentage": 0.055
          },
          "Female": {
            "value": 640,
            "margin_of_error": 102,
            "percentage": 0.487
          },
          "Female: No schooling completed": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: Nursery to 4th grade": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: 5th and 6th grade": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: 7th and 8th grade": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: 9th grade": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: 10th grade": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: 11th grade": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: 12th grade, no diploma": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: High school graduate (includes equivalency)": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: Some college, less than 1 year": {
            "value": 9,
            "margin_of_error": 14,
            "percentage": 0.014
          },
          "Female: Some college, 1 or more years, no degree": {
            "value": 17,
            "margin_of_error": 26,
            "percentage": 0.027
          },
          "Female: Associate's degree": {
            "value": 8,
            "margin_of_error": 12,
            "percentage": 0.013
          },
          "Female: Bachelor's degree": {
            "value": 230,
            "margin_of_error": 83,
            "percentage": 0.359
          },
          "Female: Master's degree": {
            "value": 298,
            "margin_of_error": 97,
            "percentage": 0.466
          },
          "Female: Professional school degree": {
            "value": 59,
            "margin_of_error": 45,
            "percentage": 0.092
          },
          "Female: Doctorate degree": {
            "value": 19,
            "margin_of_error": 19,
            "percentage": 0.03
          }
        },
        "Population with veteran status": {
          "meta": {
            "table_id": "B21001",
            "universe": "Civilian Population 18 Years And Over"
          },
          "Total": {
            "value": 1400,
            "margin_of_error": 288
          },
          "Veteran": {
            "value": 74,
            "margin_of_error": 50,
            "percentage": 0.053
          },
          "Nonveteran": {
            "value": 1326,
            "margin_of_error": 291,
            "percentage": 0.947
          },
          "Male": {
            "value": 682,
            "margin_of_error": 175,
            "percentage": 0.487
          },
          "Male: Veteran": {
            "value": 74,
            "margin_of_error": 50,
            "percentage": 0.109
          },
          "Male: Nonveteran": {
            "value": 608,
            "margin_of_error": 179,
            "percentage": 0.891
          },
          "Male: 18 to 34 years": {
            "value": 303,
            "margin_of_error": 154,
            "percentage": 0.444
          },
          "Male: 18 to 34 years: Veteran": {
            "value": 26,
            "margin_of_error": 30,
            "percentage": 0.086
          },
          "Male: 18 to 34 years: Nonveteran": {
            "value": 277,
            "margin_of_error": 157,
            "percentage": 0.914
          },
          "Male: 35 to 54 years": {
            "value": 309,
            "margin_of_error": 109,
            "percentage": 0.453
          },
          "Male: 35 to 54 years: Veteran": {
            "value": 34,
            "margin_of_error": 32,
            "percentage": 0.11
          },
          "Male: 35 to 54 years: Nonveteran": {
            "value": 275,
            "margin_of_error": 104,
            "percentage": 0.89
          },
          "Male: 55 to 64 years": {
            "value": 35,
            "margin_of_error": 36,
            "percentage": 0.051
          },
          "Male: 55 to 64 years: Veteran": {
            "value": 14,
            "margin_of_error": 23,
            "percentage": 0.4
          },
          "Male: 55 to 64 years: Nonveteran": {
            "value": 21,
            "margin_of_error": 26,
            "percentage": 0.6
          },
          "Male: 65 to 74 years": {
            "value": 16,
            "margin_of_error": 22,
            "percentage": 0.023
          },
          "Male: 65 to 74 years: Veteran": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Male: 65 to 74 years: Nonveteran": {
            "value": 16,
            "margin_of_error": 22,
            "percentage": 1
          },
          "Male: 75 years and over": {
            "value": 19,
            "margin_of_error": 21,
            "percentage": 0.028
          },
          "Male: 75 years and over: Veteran": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Male: 75 years and over: Nonveteran": {
            "value": 19,
            "margin_of_error": 21,
            "percentage": 1
          },
          "Female": {
            "value": 718,
            "margin_of_error": 143,
            "percentage": 0.513
          },
          "Female: Veteran": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: Nonveteran": {
            "value": 718,
            "margin_of_error": 143,
            "percentage": 1
          },
          "Female: 18 to 34 years": {
            "value": 403,
            "margin_of_error": 137,
            "percentage": 0.561
          },
          "Female: 18 to 34 years: Veteran": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: 18 to 34 years: Nonveteran": {
            "value": 403,
            "margin_of_error": 137,
            "percentage": 1
          },
          "Female: 35 to 54 years": {
            "value": 245,
            "margin_of_error": 90,
            "percentage": 0.341
          },
          "Female: 35 to 54 years: Veteran": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: 35 to 54 years: Nonveteran": {
            "value": 245,
            "margin_of_error": 90,
            "percentage": 1
          },
          "Female: 55 to 64 years": {
            "value": 21,
            "margin_of_error": 25,
            "percentage": 0.029
          },
          "Female: 55 to 64 years: Veteran": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: 55 to 64 years: Nonveteran": {
            "value": 21,
            "margin_of_error": 25,
            "percentage": 1
          },
          "Female: 65 to 74 years": {
            "value": 33,
            "margin_of_error": 29,
            "percentage": 0.046
          },
          "Female: 65 to 74 years: Veteran": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: 65 to 74 years: Nonveteran": {
            "value": 33,
            "margin_of_error": 29,
            "percentage": 1
          },
          "Female: 75 years and over": {
            "value": 16,
            "margin_of_error": 18,
            "percentage": 0.022
          },
          "Female: 75 years and over: Veteran": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Female: 75 years and over: Nonveteran": {
            "value": 16,
            "margin_of_error": 18,
            "percentage": 1
          }
        },
        "Period of military service for veterans": {
          "meta": {
            "table_id": "B21002",
            "universe": "Civilian Veterans 18 Years And Over"
          },
          "Total": {
            "value": 74,
            "margin_of_error": 50
          },
          "Gulf War (9/2001 or later), no Gulf War (8/1990 to 8/2001), no Vietnam War": {
            "value": 57,
            "margin_of_error": 45,
            "percentage": 0.77
          },
          "Gulf War (9/2001 or later) and Gulf War (8/1990 to 8/2001), no Vietnam War": {
            "value": 14,
            "margin_of_error": 23,
            "percentage": 0.189
          },
          "Gulf War (9/2001 or later), and Gulf War (8/1990 to 8/2001), and Vietnam War": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Gulf War (8/1990 to 8/2001), no Vietnam War": {
            "value": 3,
            "margin_of_error": 5,
            "percentage": 0.041
          },
          "Gulf War (8/1990 to 8/2001) and Vietnam War": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Vietnam War, no Korean War, no World War II": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Vietnam War and Korean War, no World War II": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Vietnam War and Korean War and World War II": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Korean War, no Vietnam War, no World War II": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Korean War and World War II, no Vietnam War": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "World War II, no Korean War, no Vietnam War": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Between Gulf War and Vietnam War only": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Between Vietnam War and Korean War only": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Between Korean War and World War II only": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          },
          "Pre-World War II only": {
            "value": 0,
            "margin_of_error": 13,
            "percentage": 0
          }
        },
        "meta": {
          "geography": "block_group"
        }
      }
    }
  }
...
```

We provide the data exactly as it is packaged by the Census Bureau in the breakouts it gives. The only change we have made is to add a "percentage" calculation to aid ease of use.

The data returned includes the following data points. For each data point, the data returned includes the value, margin of error, and percentage.

* Population by minimum level of education (Table #B15002)
  * No schooling, nursery to 4th grade, 5th and 6th grade, 7th and 8th grade, 9th grade, 10th grade, 11th grade, 12th grade - no diploma, high school graduate or equivalent, some college (1+ years, no degree), Associate's Degree, Bachelor's Degree, Master's Degree, professional school degree, Doctorate
  * Results broken out by all genders, female, and male
* Veteran status (Table #B21001)
  * Veteran, non-Veteran
  * Results broken out by all genders, female, and male as well as age groups
* Period of military service for veterans (Table #B21002)
  * Wars
    * Gulf War (9/2001 or later), no Gulf War (8/1990 to 8/2001), no Vietnam War
    * Gulf War (9/2001 or later), Gulf War (8/1990 to 8/2001), no Vietnam War
    * Gulf War (8/1990 to 8/2001), no Vietnam War
    * Gulf War (8/1990 to 8/2001) and Vietnam War
    * Vietnam War, no Korean War, no World War II
    * Vietnam War and Korean War, no World War II
    * Vietnam War and Korean War and World War II
    * Korean War, no Vietnam War, no World War II
    * Korean War and World War II, no Vietnam War
    * World War II, no Korean War, no Vietnam War
    * Between Gulf War and Vietnam War only
    * Between Korean War and World War II only
    * Pre-World War II only

## USPS ZIP+4
**Field name: `zip4`**

> To get `zip4` field appends for an address or a coordinate:

```shell
curl "https://api.geocod.io/v2/geocode?q=1109+N+Highland+St%2C+Arlington+VA&fields=zip4&api_key=YOUR_API_KEY"
curl "https://api.geocod.io/v2/reverse?q=38.886672,-77.094735&fields=zip4&api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

location = geocodio.geocode(['1109 N Highland St, Arlington VA'], ['zip4'])
location = geocodio.reverse(['38.886672,-77.094735'], ['zip4'])
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

response = client.geocode("1109 N Highland St, Arlington VA", fields=["zip4"])
response = client.reverse("38.886672,-77.094735", fields=["zip4"])
```

```php
<?php
$response = $geocoder->geocode('1109 N Highland St, Arlington VA', ['zip4']);
$response = $geocoder->reverse('38.886672,-77.094735', ['zip4']);
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocodio = new Geocodio('YOUR_API_KEY');

geocoder.geocode('1109 N Highland St, Arlington VA', ['zip4'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);

geocoder.reverse('38.886672,-77.094735', ['zip4'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example for "1109 N Highland St, Arlington VA":

```json
...
  "fields": {
    "zip4": {
      "record_type": {
        "code": "S",
        "description": "Street"
      },
      "residential": false,
      "carrier_route": {
        "id": "C007",
        "description": "City Delivery"
      },
      "building_or_firm_name": null,
      "plus4": [
        "2890"
      ],
      "zip9": [
        "22201-2890"
      ],
      "government_building": null,
      "facility_code": {
        "code": "P",
        "description": "Post Office"
      },
      "city_delivery": true,
      "valid_delivery_area": true,
      "exact_match": true
    }
  }
...
```

> **Note:** The `zip4` data append requires using `v1.5` of the Geocodio API or newer.

> In most cases, only a single ZIP4 code is assigned to a result. If that is the case each array has one item.

```json
...
"plus4": [
  "2890"
],
"zip9": [
  "22201-2890"
],
...
```

> For businesses with a range of ZIP4 codes, an array with 2 items is returned:

```json
...
"plus4": [
  "2890",
  "2900",
],
"zip9": [
  "22201-2890",
  "22201-2900"
],
...
```

> In some rare cases a ZIP4 record is returned but without a ZIP+4 code (e.g. when it is not a valid delivery area)

```json
...
"plus4": [],
"zip9": [],
...
```

> Example of a building or firm name being returned (316 Pennsylvania Ave. SE, Lobby, Washington, DC)

```json
...
"building_or_firm_name": "The Natl Capital Bank Of Washington",
...
```

> Example of a government building result (134 Union Blvd Ste 130 Lakewood, CO)

```json
...
"government_building": {
    "code": "B",
    "description": "Federal Government Building"
},
...
```

Geocodio can return the USPS ZIP+4 code for a given US address or coordinate pair, which lets you retrieve the full 9-digit ZIP Code&trade;, by combining the 5-digit ZIP code with the ZIP+4 code. Additional USPS delivery data is also returned.

Geocodio also returns additional USPS delivery data, including Carrier Route ID and RDI.

### Record Type
The type of ZIP+4 result. Possible values are:

* **F**: Firm
* **G**: General Delivery
* **H**: High-rise
* **P**: PO Box
* **R**: Rural Route/Contract
* **S**: Street

### Residential Delivery Indicator (RDI)

`residential` will be set to `true` for residential addresses and `false` for commercial addresses.

The value can also be `null` if there are no records that indicate the residential status of this property.

### Carrier Route ID
A 4-byte code that determines the type of postal route that that servers the address.
Possible values are:

* **Bxxx**: PO Box
* **Hxxx**: Contract
* **Rxxx**: Rural Route
* **Cxxx**: City Delivery
* **Gxxx**: General Delivery

### Building or Firm Name
A USPS-provided name associated with the address. This is available for businesses that have registered their name with USPS and for most federal and state government buildings including schools and offices.

The building or firm name field takes the secondary address unit into account if available.

If no name is available, the value is set to `null`.

> **Tip:** To return a more precise ZIP+4 code for a business, supply an [`addressee`](#the-addressee-parameter) with the firm name when you geocode. Geocodio compares it against USPS firm records to select the correct ZIP+4 for that business.

### ZIP+4 and ZIP9
The range of ZIP Codes that are associated with this result as representated by the minimum and maximum number.

The ZIP9 code consists of the ZIP5 code, a dash, and the +4 code.

### Government Building

Type of government building (if applicable).

If no name is available, the value is set to `null`.

* **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
* **G**: State Government Building and Firm Only

### Facility Code

Facility code associated with the 5-digit ZIP Code

Possible values are:

* **B**: Branch
* **C**: Community post office (CPO)
* **N**: Non-postal community name, former USPS facility, or place name
* **P**: Post Office
* **S**: Station
* **U**: Urbanization

### City Delivery Indicator

Indicates whether or not the local post office has a city delivery carrier route.

### Valid delivery area

In some cases an address exists but it is not a valid delivery point for postal purposes. This could for example be because it is an undeveloped lot.

### Exact match

An exact match means that there was no ambiguity with the lookup and that the given ZIP+4 code is the correct and only match for the given address.

Most often, not-exact matches are due to lookups for an apartment or office building that is missing a unit/apartment number.

In these cases it is not possible to determine an accurate ZIP+4 code without supplying secondary address line information.

> **Warning:** If no ZIP+4 data is available for the given query, the `zip4` field is omitted from the JSON output (and the field lookup does not count against your usage)

## FFIEC (Fair Lending)
**Field name: `ffiec`**

> To get `ffiec` field appends for an address or a coordinate:

```shell
curl "https://api.geocod.io/v2/geocode?q=1109+N+Highland+St%2C+Arlington+VA&fields=ffiec&api_key=YOUR_API_KEY"
curl "https://api.geocod.io/v2/reverse?q=38.886672,-77.094735&fields=ffiec&api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

location = geocodio.geocode(['1109 N Highland St, Arlington VA'], ['ffiec'])
location = geocodio.reverse(['38.886672,-77.094735'], ['ffiec'])
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

response = client.geocode("1109 N Highland St, Arlington VA", fields=["ffiec"])
response = client.reverse("38.886672,-77.094735", fields=["ffiec"])
```

```php
<?php
$response = $geocoder->geocode('1109 N Highland St, Arlington VA', ['ffiec']);
$response = $geocoder->reverse('38.886672,-77.094735', ['ffiec']);
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocodio = new Geocodio('YOUR_API_KEY');

geocoder.geocode('1109 N Highland St, Arlington VA', ['ffiec'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);

geocoder.reverse('38.886672,-77.094735', ['ffiec'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example for "1109 N Highland St, Arlington VA":

```json
...
  "fields": {
    "ffiec": {
      "collection_year": 2026,
      "msa_md_code": "11694",
      "fips_state_code": "51",
      "fips_county_code": "013",
      "census_tract": "101801",
      "principal_city": true,
      "small_county": {
        "flag": "T",
        "description": "Tract record"
      },
      "split_tract": {
        "flag": "N",
        "description": "Tract number occurs within one MA"
      },
      "demographic_data": {
        "flag": "D",
        "description": "Total persons/population and median family income are not 0"
      },
      "urban_rural_flag": {
        "flag": "U",
        "description": "Urban"
      },
      "msa_md_median_family_income": 135790,
      "msa_md_median_household_income": 115805,
      "tract_median_family_income_percentage": 133.95,
      "ffiec_estimated_msa_md_median_family_income": 173100,
      "income_indicator": "Upper",
      "cra_poverty_criteria": false,
      "cra_unemployment_criteria": false,
      "cra_distressed_criteria": false,
      "cra_remote_rural_low_density_criteria": false,
      "previous_year_cra_distressed_criteria": false,
      "previous_year_cra_underserved_criterion": false,
      "meets_current_previous_criteria": false,
      "tract_minority_population_percentage": 26.89
    }
  }
...
```

Geocodio's FFIEC field append allows you to get key data points, commonly used by financial institutions, lenders, and organizations that need to comply with Fair Lending regulations like HMDA and CRA. The data returned is for the 2026 data release, and is returned for all API versions.

You can read more about the individual values in the [FFIEC Documentation](https://www.ffiec.gov/data/census/flat-files).

## Riding: Canadian Federal Electoral District
**Field name: `riding`**

> To get `riding` field appends for an address or a coordinate:

```shell
curl "https://api.geocod.io/v2/geocode?q=300+King+St%2C+Sturgeon+Falls%2C+ON+P2B+3A1%2C+Canada&fields=riding&api_key=YOUR_API_KEY"
curl "https://api.geocod.io/v2/reverse?q=46.225866,-79.36316&fields=riding&api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

location = geocodio.geocode(['300 King St, Sturgeon Falls, ON P2B 3A1, Canada'], ['riding'])
location = geocodio.reverse(['46.225866,-79.36316'], ['riding'])
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

response = client.geocode("300 King St, Sturgeon Falls, ON P2B 3A1, Canada", fields=["riding"])
response = client.reverse("46.225866,-79.36316", fields=["riding"])
```

```php
<?php
$response = $geocoder->geocode('300 King St, Sturgeon Falls, ON P2B 3A1, Canada', ['riding']);
$response = $geocoder->reverse('46.225866,-79.36316', ['riding']);
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocodio = new Geocodio('YOUR_API_KEY');

geocoder.geocode('300 King St, Sturgeon Falls, ON P2B 3A1, Canada', ['riding'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);

geocoder.reverse('46.225866,-79.36316', ['riding'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example for "300 King St, Sturgeon Falls, ON P2B 3A1, Canada":

```json
...
  "fields": {
    "riding": {
      "year": 2023,
      "code": "35104",
      "ocd_id": "ocd-division/country:ca/ed:35104-2023",
      "name_french": "Sudbury-Est\u2014Manitoulin\u2014Nickel Belt",
      "name_english": "Sudbury East\u2014Manitoulin\u2014Nickel Belt",
      "source": "Federal Redistribution"
    }
  }
...
```

Geocodio can return Canadian electoral districts ([ridings](https://en.wikipedia.org/wiki/List_of_Canadian_federal_electoral_districts) ) for an address or coordinate pair. The riding code and OCD-ID is returned along with the French and English name for the riding.

The OCD-ID can be used to uniquely identify the district using the [Open Civic Data Division Identifiers](https://github.com/opencivicdata/ocd-division-ids) project.

In some cases, the French and English names will be the same.

## Riding: Canadian Provincial Electoral District
**Field name: `provriding` or `provriding-next`**

> To get `provriding` field appends for an address or a coordinate:

```shell
curl "https://api.geocod.io/v2/geocode?q=300+King+St%2C+Sturgeon+Falls%2C+ON+P2B+3A1%2C+Canada&fields=provriding&api_key=YOUR_API_KEY"
curl "https://api.geocod.io/v2/reverse?q=46.225866,-79.36316&fields=provriding&api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

location = geocodio.geocode(['300 King St, Sturgeon Falls, ON P2B 3A1, Canada'], ['provriding'])
location = geocodio.reverse(['46.225866,-79.36316'], ['provriding'])
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

response = client.geocode("300 King St, Sturgeon Falls, ON P2B 3A1, Canada", fields=["provriding"])
response = client.reverse("46.225866,-79.36316", fields=["provriding"])
```

```php
<?php
$response = $geocoder->geocode('300 King St, Sturgeon Falls, ON P2B 3A1, Canada', ['provriding']);
$response = $geocoder->reverse('46.225866,-79.36316', ['provriding']);
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocodio = new Geocodio('YOUR_API_KEY');

geocoder.geocode('300 King St, Sturgeon Falls, ON P2B 3A1, Canada', ['provriding'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);

geocoder.reverse('46.225866,-79.36316', ['provriding'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example for "300 King St, Sturgeon Falls, ON P2B 3A1, Canada":

```json
...
  "fields": {
    "provincial_riding": {
      "ocd_id": "ocd-division/country:ca/province:on/ed:timiskaming-cochrane",
      "name_french": "Timiskaming - Cochrane",
      "name_english": "Timiskaming - Cochrane",
      "is_upcoming_district": false,
      "source": "Elections Ontario"
    }
  }
...
```

Geocodio can return the [provincial or territorial electoral district (riding)](https://en.wikipedia.org/wiki/Canadian_provincial_electoral_districts) for the specified address in Canada. The OCD-ID is returned along with the French and English name for the riding.

The OCD-ID can be used to uniquely identify the district using the [Open Civic Data Division Identifiers](https://github.com/opencivicdata/ocd-division-ids) project.

In some cases, the French and English names will be the same.

### Using `provriding-next`

`provriding-next` is a preview of upcoming, redistricted provincial ridings.

> To get `provriding-next` field appends for an address or a coordinate:

```shell
curl "https://api.geocod.io/v2/geocode?q=203+Laycoe+Crescent%2C+Saskatoon%2C+SK%2C+Canada&fields=provriding-next&api_key=YOUR_API_KEY"
curl "https://api.geocod.io/v2/reverse?q=52.155106,-106.589896&fields=provriding-next&api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

location = geocodio.geocode(['203 Laycoe Crescent, Saskatoon, SK, Canada'], ['provriding-next'])
location = geocodio.reverse(['52.155106,-106.589896'], ['provriding-next'])
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

response = client.geocode("203 Laycoe Crescent, Saskatoon, SK, Canada", fields=["provriding-next"])
response = client.reverse("52.155106,-106.589896", fields=["provriding-next"])
```

```php
<?php
$response = $geocoder->geocode('203 Laycoe Crescent, Saskatoon, SK, Canada', ['provriding-next']);
$response = $geocoder->reverse('52.155106,-106.589896', ['provriding-next']);
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocodio = new Geocodio('YOUR_API_KEY');

geocoder.geocode('203 Laycoe Crescent, Saskatoon, SK, Canada', ['provriding-next'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);

geocoder.reverse('52.155106,-106.589896', ['provriding-next'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example for "203 Laycoe Crescent, Saskatoon, SK, Canada":

```json
...
  "fields": {
    "provincial_riding": {
      "ocd_id": "ocd-division/country:ca/province:sk/ed:49-2022",
      "name_french": "Saskatoon Silverspring",
      "name_english": "Saskatoon Silverspring",
      "is_upcoming_district": false,
      "source": "Elections Saskatchewan"
    }
  }
...
```

## Canadian statistical boundaries from Statistics Canada
**Field name: `statcan`**

> To get `statcan` field appends for an address or a coordinate:

```shell
curl "https://api.geocod.io/v2/geocode?q=300+King+St%2C+Sturgeon+Falls%2C+ON+P2B+3A1%2C+Canada&fields=statcan&api_key=YOUR_API_KEY"
curl "https://api.geocod.io/v2/reverse?q=46.225866,-79.36316&fields=statcan&api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

location = geocodio.geocode(['300 King St, Sturgeon Falls, ON P2B 3A1, Canada'], ['statcan'])
location = geocodio.reverse(['46.225866,-79.36316'], ['statcan'])
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

response = client.geocode("300 King St, Sturgeon Falls, ON P2B 3A1, Canada", fields=["statcan"])
response = client.reverse("46.225866,-79.36316", fields=["statcan"])
```

```php
<?php
$response = $geocoder->geocode('300 King St, Sturgeon Falls, ON P2B 3A1, Canada', ['statcan']);
$response = $geocoder->reverse('46.225866,-79.36316', ['statcan']);
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocodio = new Geocodio('YOUR_API_KEY');

geocoder.geocode('300 King St, Sturgeon Falls, ON P2B 3A1, Canada', ['statcan'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);

geocoder.reverse('46.225866,-79.36316', ['statcan'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example for "300 King St, Sturgeon Falls, ON P2B 3A1, Canada":

```json
...
  "fields": {
    "statcan": {
      "division": {
        "id": "3548",
        "name": "Nipissing",
        "type": "DIS",
        "type_description": "District"
      },
      "consolidated_subdivision": {
        "id": "3548055",
        "name": "West Nipissing / Nipissing Ouest"
      },
      "subdivision": {
        "id": "3548055",
        "name": "West Nipissing / Nipissing Ouest",
        "type": "M",
        "type_description": "Municipality / Municipalite\u0301"
      },
      "economic_region": "Northeast / Nord-est",
      "statistical_area": {
        "code": "997",
        "code_description": "Moderate",
        "type": "5",
        "type_description": "Census subdivision outside of census metropolitan area/census agglomeration area having moderate metropolitan influence"
      },
      "cma_ca": {
        "id": "997",
        "name": "Moderate metropolitan influenced zone (Ont.) / Zone d'influence m\u00e9tropolitaine mod\u00e9r\u00e9e (Ont.)",
        "type": "H",
        "type_description": "Not applicable (outside of CMA or CA)"
      },
      "tract": null,
      "designated_place": null,
      "population_centre": {
        "id": "350901",
        "name": "Sturgeon Falls",
        "type": "4",
        "type_description": "Population centre outside of a census metropolitan area or census agglomeration",
        "class": "2",
        "class_description": "Small population centre (1,000 to 29,999)"
      },
      "dissemination_area": {
        "id": "35480186"
      },
      "dissemination_block": {
        "id": "35480186023",
        "population": "458"
      },
      "census_year": 2021
    }
  }
...
```

Geocodio can return the [Statistics Canada geographies](https://en.wikipedia.org/wiki/Census_geographic_units_of_Canada) for an address or coordinate, such as dissemination areas, tracts, and economic regions. These boundaries can be matched with data from [Statistics Canada](https://www.statcan.gc.ca) to get further Census information, such as demographics.

> **Note:** Looking for US Census data? See the [`census`](#census-block-tract-fips-codes-amp-msa-csa-codes) field append.

If a given geography does not apply to the query, `null` will be returned instead.

> Example for "26 Johnson Avenue, Teslin, YT Y0A 1B0, Canada"

```json
...
"fields": {
  "statcan": {
    "division": {
      "id": "6001",
      "name": "Yukon",
      "type": "TER",
      "type_description": "Territory / Territoire"
    },
    "consolidated_subdivision": {
      "id": "6001045",
      "name": "Yukon, Unorganized"
    },
    "subdivision": {
      "id": "6001047",
      "name": "Johnsons Crossing",
      "type": "SÉ",
      "type_description": "Not applicable"
    },
    "economic_region": "Yukon",
    "statistical_area": {
      "code": "000",
      "code_description": "Territories, classification is not applicable",
      "type": "8",
      "type_description": "Census subdivision within a territory"
    },
    "cma_ca": null,
    "tract": null,
    "designated_place": null,
    "population_centre": {
      "id": "609960",
      "name": "Yukon Territory Rural Area / Région rurale: Territoire du Yukon",
      "type": "5",
      "type_description": "Rural area outside of a census metropolitan area or census agglomeration",
      "class": "1",
      "class_description": "Rural area"
    },
    "dissemination_area": {
      "id": "60010135"
    },
    "dissemination_block": {
      "id": "60010135008",
      "population": "10"
    },
    "census_year": 2021
  }
}
...
```

The following geographies may be found:

### `division`: Census division
One of the largest Census designated geographies. The `id`, `name` and `type` code for the query is returned. The `type_description` contains values such as "District", "County", "Region", among others.

### `consolidated_subdivision`: Census Consolidated Subdivision
A geographic unit that is in-between divisions and subdivisions in size. It is a combination of adjacent census subdivisions.

The `id` and `name` are returned for consolidated subdivisions

### `subdivison`: Census Subdivision
This generally corresponds to a municipality.

The subdivision `id` is returned along with it's `name` and `type` code. The `type_description` is an explanation of the `type code` and can contain values such as "Town", "Village", "Municipality" or "City" among many others.

### `economic_region`: Economic region name
Economic regions are mostly groupings of complete census divisions, created to allow for analysis of regional economic activity.

### `statistical_area`: Statistical Area
Statistical areas group census subdivisions based on what type of CMA/CA are they are part of.

### `cma_ca`: Census Metropolitan Area or Census Agglomeration

The Census Metropolitan Area or Census Agglomeration that the query is part of. `type_description` can be either of the following: "Census metropolitan area (CMA)", "Census agglomeration (CA) that is not tracted", "Census agglomeration (CA) that is tracted".

### `tract`: Census Tract Code

The full Canadian census tract code that this query is part of.

### `designated_place`: Designated place

A Designated Place (DPL) typically refers to a small community or settlement that doesn't fulfill Statistics Canada's requirements for being a census subdivision (an area with municipal status) or a population centre.

Provinces and territories work with Statistics Canada to establish designated places, which serve as data sources for submunicipal regions.

### `population_centre`: Population centre

Population centres in Canada have a population of at least 1,000 and a population density of 400 persons or more per square kilometre, based on the current census population count. Rural areas are defined as areas outside population centres. All of Canada is covered by either population centres or rural areas.

Population centres are grouped into three categories based on their population size: small, medium, and large. The population count for population centres includes all people living in the cores, secondary cores, and fringes of census metropolitan areas and census agglomerations, as well as those living in population centres outside of these areas.

### `dissemination_area` and `dissemination_block`: Dissemination area and block

The dissemination area is geographically one step lower than census tracts. Dissemination blocks are one step lower than dissemination areas.

> You can read more about the various code names from the [Statistics Canada technical specifications page](https://www150.statcan.gc.ca/n1/pub/92-151-g/92-151-g2021001-eng.htm). Statistics Canada also provides a helpful [hierarchy of geographic areas](https://www12.statcan.gc.ca/census-recensement/2021/ref/dict/fig/index-eng.cfm?ID=f1_1).

## United Kingdom political districts
**Field names: `uk-westminster`, `uk-devolved`, `uk-local` (and their `-next` variants)**

> To get all three UK political district appends for a single address:

```shell
curl "https://api.geocod.io/v2/geocode?q=10+Downing+Street,+London+SW1A+2AA&country=GB&fields=uk-westminster,uk-devolved,uk-local&api_key=YOUR_API_KEY"
```

Geocodio can return UK political districts at three levels for an address or coordinate in Great Britain or Northern Ireland. Coverage spans the full United Kingdom (England, Scotland, Wales, and Northern Ireland).

| `fields` value | Returns | Rows per result | OCD IDs |
|---|---|---|---|
| `uk-westminster` | Westminster (UK Parliament) constituency | 1 | 100% (all 650) |
| `uk-westminster-next` | Same, using upcoming boundaries | 1 | 100% |
| `uk-devolved` | Scottish Parliament, Senedd Cymru, or NI Assembly districts | 0–2 | Partial |
| `uk-devolved-next` | Same, using upcoming boundaries | 0–2 | Partial |
| `uk-local` | Ward (+ County Electoral Division in two-tier English areas) | 1–2 | None |
| `uk-local-next` | Same, using upcoming boundaries | 1–2 | None |

You can combine multiple field appends in a single request by comma-separating them (e.g. `fields=uk-westminster,uk-devolved,uk-local`). Each field append appears under its own key in the response's `fields` object.

> **Note:** The request parameter uses hyphens (e.g. `uk-westminster`); the response key uses underscores (e.g. `uk_westminster`).

> Example response for "10 Downing Street, London SW1A 2AA":

```json
{
  "results": [
    {
      "formatted_address": "10 Downing St, London SW1A 2AA",
      "location": { "lat": 51.503541, "lng": -0.12767 },
      "accuracy_type": "rooftop",
      "fields": {
        "uk_westminster": [
          {
            "district_type": "westminster_constituency",
            "gss_code": "E14001172",
            "ocd_id": "ocd-division/country:gb/part:eng/region:uki/ed:cities_of_london_and_westminster",
            "name": "Cities of London and Westminster",
            "is_upcoming_district": false,
            "source": "Office for National Statistics"
          }
        ],
        "uk_devolved": [],
        "uk_local": [
          {
            "district_type": "ward",
            "gss_code": "E05013806",
            "ocd_id": "ocd-division/country:gb/part:eng/ward:e05013806",
            "name": "St James's",
            "is_upcoming_district": false,
            "source": "Office for National Statistics"
          }
        ]
      }
    }
  ]
}
```

Three things to note in this single response:

1. `uk_westminster` returns a single constituency row with an `ocd_id`.
2. `uk_devolved` is an empty array because England has no devolved parliament.
3. `uk_local` returns only a ward (no County Electoral Division) because the City of Westminster is a single-tier local authority.

### Response shape

Every district object has the same shape across the three field appends:

```json
{
  "district_type": "westminster_constituency",
  "gss_code": "E14001172",
  "ocd_id": "ocd-division/country:gb/part:eng/region:uki/ed:cities_of_london_and_westminster",
  "name": "Cities of London and Westminster",
  "is_upcoming_district": false,
  "source": "Office for National Statistics"
}
```

* `district_type` – which kind of district this row represents (see table below).
* `gss_code` – the GSS code. Always populated. This is the canonical UK identifier; think of it as the UK equivalent of a US OCD-ID.
* `ocd_id` – the Open Civic Data identifier, when one exists. See [OCD IDs vs GSS codes](#ocd-ids-vs-gss-codes) below — coverage is uneven.
* `name` – human-readable district name.
* `is_upcoming_district` – `true` only when this row represents a future boundary (see [Redistricting and `-next` variants](#redistricting-and-next-variants)).
* `source` – upstream data publisher: "Office for National Statistics" for most districts, "Ordnance Survey" for Scottish Parliament boundaries, and "Welsh Government" for the 2026 Senedd constituencies.

All `district_type` values we return:

| `district_type` | Appears in | Notes |
|---|---|---|
| `westminster_constituency` | `uk-westminster` | All 650 UK seats |
| `scottish_parliament_constituency` | `uk-devolved` (SCT) | 73 constituencies (May 2026 boundaries) |
| `scottish_parliament_region` | `uk-devolved` (SCT) | 8 regional list seats |
| `senedd_constituency` | `uk-devolved` (WLS) | 16 constituencies (May 2026 boundaries) |
| `ni_assembly_constituency` | `uk-devolved` (NIR) | 18 (shares boundaries with Westminster NI) |
| `ward` | `uk-local` | Local council ward, all four nations |
| `county_electoral_division` | `uk-local` | England only, two-tier council areas |

### `uk-westminster`

Returns the Westminster (UK Parliament) constituency for the address. Exactly one row per result, and the `ocd_id` is always populated for Westminster rows (see the combined example above).

GSS prefixes for Westminster: `E14` (England, 543 seats), `S14` (Scotland, 57), `W07` (Wales, 32), `N05` (Northern Ireland, 18). Total 650.

### `uk-devolved`

Returns devolved-parliament districts for Scotland, Wales, and Northern Ireland. Returns an empty array `[]` for English addresses.

Scotland returns two rows (a constituency and a region). Wales returns one row (a constituency) — its five electoral regions were abolished in the May 2026 reform. Northern Ireland returns one row.

> **Scotland** — example response for "Bute House, Charlotte Square, Edinburgh EH2 4DR" with `fields=uk-devolved`:

```json
{
  "fields": {
    "uk_devolved": [
      {
        "district_type": "scottish_parliament_constituency",
        "gss_code": "S16000182",
        "ocd_id": "ocd-division/country:gb/part:sct/spc:edinburgh_central",
        "name": "Edinburgh Central",
        "is_upcoming_district": false,
        "source": "Ordnance Survey"
      },
      {
        "district_type": "scottish_parliament_region",
        "gss_code": "S17000022",
        "ocd_id": "ocd-division/country:gb/part:sct/spr:edinburgh_and_lothians_east",
        "name": "Edinburgh and Lothians East",
        "is_upcoming_district": false,
        "source": "Ordnance Survey"
      }
    ]
  }
}
```

Both rows carry an `ocd_id` — a Geocodio-generated, OCD-format identifier derived from the GSS code or name (see [OCD IDs vs GSS codes](#ocd-ids-vs-gss-codes)).

> **Wales** — example response for "Senedd, Cardiff Bay CF99 1SN" with `fields=uk-devolved`:

```json
{
  "fields": {
    "uk_devolved": [
      {
        "district_type": "senedd_constituency",
        "gss_code": "W09000053",
        "ocd_id": "ocd-division/country:gb/part:wls/senc:caerdydd_penarth",
        "name": "Caerdydd Penarth",
        "is_upcoming_district": false,
        "source": "Welsh Government"
      }
    ]
  }
}
```

Wales returns a constituency only — the five Senedd electoral regions were abolished in the May 2026 reform. The 16 new constituencies use canonical ONS codes in the existing `W09` series (`W09000048`–`W09000063`) and carry Welsh-language names. `uk-devolved-next` returns the same result, as there is no further upcoming Welsh boundary change.

> **Northern Ireland** — example response for "Stormont Estate, Upper Newtownards Rd, Belfast BT4 3SH" with `fields=uk-devolved`:

```json
{
  "fields": {
    "uk_devolved": [
      {
        "district_type": "ni_assembly_constituency",
        "gss_code": "N05000001",
        "ocd_id": "ocd-division/country:gb/part:nir/ed:belfast_east",
        "name": "Belfast East",
        "is_upcoming_district": false,
        "source": "Office for National Statistics"
      }
    ]
  }
}
```

NI Assembly constituencies share boundaries (and GSS codes) with Westminster NI constituencies, so the `gss_code` and `ocd_id` match what `uk-westminster` would return for the same address.

GSS prefixes for devolved: Scottish Parliament constituencies `S16`, regions `S17`; Senedd constituencies `W09`; NI Assembly constituencies `N05`.

### `uk-local`

Returns local-government districts. Every UK address gets at least a ward. English addresses in two-tier council areas (e.g. Surrey, Hampshire) also get a County Electoral Division; single-tier areas (London boroughs, unitary authorities, metropolitan districts) just get the ward.

> **Two-tier (ward + CED)** — example response for "Winchester Cathedral, The Close, Winchester SO23 9LS" with `fields=uk-local`:

```json
{
  "fields": {
    "uk_local": [
      {
        "district_type": "ward",
        "gss_code": "E05011004",
        "ocd_id": "ocd-division/country:gb/part:eng/ward:e05011004",
        "name": "St Michael",
        "is_upcoming_district": false,
        "source": "Office for National Statistics"
      },
      {
        "district_type": "county_electoral_division",
        "gss_code": "E58000597",
        "ocd_id": "ocd-division/country:gb/part:eng/ced:e58000597",
        "name": "Winchester Eastgate ED",
        "is_upcoming_district": false,
        "source": "Office for National Statistics"
      }
    ]
  }
}
```

`uk-local` rows include an `ocd_id`, but since wards and county electoral divisions aren't in the canonical Open Civic Data registry, it's a Geocodio-generated OCD-format identifier derived from the GSS code (e.g. `ocd-division/country:gb/part:eng/ward:e05013806`) rather than a canonical registry entry. The `gss_code` is always present and is the authoritative identifier for these districts.

GSS prefixes for local: wards are `E05` (England), `S13` (Scotland), `W05` (Wales), `N08` (NI). County Electoral Divisions are `E58` (England only).

### OCD IDs vs GSS codes

Two identifier systems exist for UK districts, and it's worth being explicit about when each one is available.

**GSS codes** are the authoritative UK government identifiers, published and maintained by the Office for National Statistics (ONS). Every district we return has a GSS code. If you're building a system that needs a stable, universally recognised ID for a UK district, use `gss_code`. Think of it as the UK analogue of a US OCD-ID.

**OCD IDs** come from the [Open Civic Data project](https://github.com/opencivicdata/ocd-division-ids). They are human-readable string identifiers (e.g. `ocd-division/country:gb/part:eng/region:uki/ed:cities_of_london_and_westminster`) that are useful if you already rely on Open Civic Data in other contexts (for example US congressional districts). They are not a canonical UK dataset — the registry focuses on Westminster and selected devolved bodies, and doesn't cover local government at all.

Coverage in the **canonical OCD registry** (districts outside the registry still receive a generated `ocd_id` — see below):

| `district_type` | OCD coverage | Notes |
|---|---|---|
| `westminster_constituency` | 650 / 650 (100%) | Complete |
| `ni_assembly_constituency` | 18 / 18 (100%) | Inherits from Westminster NI |
| `scottish_parliament_constituency` | 7 / 73 (10%) | |
| `senedd_constituency` | 0 / 16 | New 2026 seats, not yet in the OCD registry |
| `scottish_parliament_region` | 0 / 8 | Not in OCD |
| `ward` | 0 / 8,396 | Not in OCD |
| `county_electoral_division` | 0 / 1,366 | Not in OCD |

`ocd_id` is **always present on every row**, across all three field appends. Where the district has a canonical Open Civic Data ID (the rows above), that ID is returned. For districts not in the registry, Geocodio returns an OCD-format identifier derived from the GSS code or name (e.g. `ocd-division/country:gb/part:eng/ward:e05013806`) — it follows OCD syntax but is not a canonical registry entry, so don't rely on it resolving in the upstream Open Civic Data dataset.

> **Note:** The OCD ID registry is licensed under Creative Commons Attribution-ShareAlike 3.0 US. If you surface these IDs in a product, please attribute the [Open Civic Data project](https://github.com/opencivicdata/ocd-division-ids).

### Redistricting and `-next` variants

Every field append has a matching `-next` variant: `uk-westminster-next`, `uk-devolved-next`, `uk-local-next`. The `-next` variant returns the same district types, but using the next known set of boundaries for each district type.

If there is no upcoming boundary change for a particular district type, `-next` returns today's boundaries (i.e. the same result as the non-`-next` field append). The cutover is per-district-type, so different districts can flip on different dates.

**Current boundary effective dates:**

| District type | Boundaries effective | Source |
|---|---|---|
| Westminster constituency | 2024-07-04 (current) | ONS |
| NI Assembly constituency | 2024-07-04 (current) | ONS |
| Scottish Parliament constituency | 2026-05-07 (current) | Ordnance Survey |
| Scottish Parliament region | 2026-05-07 (current) | Ordnance Survey |
| Senedd constituency | 2026-05-06 (current) | Welsh Government |
| Ward | 2024-05-02 (current) | ONS |
| County Electoral Division | 2024-05-02 (current) | ONS |

**Known upcoming changes.** None are currently loaded into `-next`. The most recent redistricting — the **May 2026 Welsh Senedd reform** (constituencies reduced from 40 to 16 and the five regional seats abolished, effective **2026-05-06**) — has already taken effect and is reflected in the current data.

**Other upcoming changes we are tracking but not yet loaded.** These aren't in `-next` yet because the upstream authorities haven't published the new boundaries:

* **English ward reviews** (LGBCE): Swindon (25 new wards), Milton Keynes, Coventry, Wirral, and others take effect at the May 2026 local elections. ONS typically publishes the boundary files 2–3 months afterwards.
* **English County Electoral Division** revisions at councils with new ward arrangements.

We will ship these in `-next` as soon as the upstream data is published, and cut them over automatically on the effective date. Until then, `uk-devolved-next` and `uk-local-next` for those areas return today's boundaries (graceful degradation rather than an error).

Longer-term changes (Local Government Reorganisation in Surrey, Norfolk, Suffolk, Essex, Hampshire, Sussex; the NI ward review) are not expected in force during 2026.

### Coverage notes & edge cases

* **England + `uk-devolved`** returns `"uk_devolved": []` (empty array). England has no devolved parliament.
* **Postcode-only queries:** a bare postcode query (e.g. `GU1 1AA`) currently returns one result per place candidate within the outward code, with each place point-in-polygon'd against its centroid. Full-address queries with rooftop accuracy return a single canonical answer. If you need a single definitive answer per postcode, use a full address (street + postcode) or reverse geocode from coordinates for now. A cleaner postcode-only experience is on the roadmap.
* **Near national borders:** `uk-devolved` uses point-in-polygon against the geocoded coordinates. A result very close to a national boundary will resolve to whichever side the point lands on.

### Data sources & licensing

All district boundaries come from Open Government Licence v3.0 data:

* Westminster, Senedd (pre-2026), NI Assembly, wards, and CEDs – Office for National Statistics.
* Scottish Parliament constituencies and regions – Ordnance Survey.
* 2026 Senedd constituencies – Welsh Government / DataMap.Wales.
* Postcode and place data – ONS Postcode Directory (Royal Mail sub-licence permits postcode-to-district use within this API).
* OCD IDs (where present) – Open Civic Data project, CC BY-SA 3.0 US.

The `source` field on every response row identifies the specific upstream publisher.

## Timezone
**Field name: `timezone`**

> To get `timezone` field appends for an address or a coordinate:

```shell
curl "https://api.geocod.io/v2/geocode?q=1109+N+Highland+St%2C+Arlington+VA&fields=timezone&api_key=YOUR_API_KEY"
curl "https://api.geocod.io/v2/reverse?q=38.886672,-77.094735&fields=timezone&api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

location = geocodio.geocode(['1109 N Highland St, Arlington VA'], ['timezone'])
location = geocodio.reverse(['38.886672,-77.094735'], ['timezone'])
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

response = client.geocode("1109 N Highland St, Arlington VA", fields=["timezone"])
response = client.reverse("38.886672,-77.094735", fields=["timezone"])
```

```php
<?php
$response = $geocoder->geocode('1109 N Highland St, Arlington VA', ['timezone']);
$response = $geocoder->reverse('38.886672,-77.094735', ['timezone']);
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocodio = new Geocodio('YOUR_API_KEY');

geocoder.geocode('1109 N Highland St, Arlington VA', ['timezone'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);

geocoder.reverse('38.886672,-77.094735', ['timezone'])
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example for "1109 N Highland St, Arlington VA":

```json
...
  "fields": {
    "timezone": {
      "name": "America/New_York",
      "utc_offset": -5,
      "observes_dst": true,
      "abbreviation": "EST",
      "source": "\u00a9 OpenStreetMap contributors"
    }
  }
...
```

Geocodio can return the timezone for an address or coordinate using `timezone` in the `fields` query parameter.

The field will return the standardized name of the timezone as well as an abbreviation (see table below for examples), the UTC/GMT offset, and whether the location observes Daylight Saving Time (DST).

The standardized name follows the [tzdb](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) format. E.g. `America/New_York`.

Abbreviation | Description
------------ | -----------------------------------------------------------
AKST         | Alaska Standard Time
AST          | Atlantic Standard Time
ChST         | Chamorro Standard Time
CST          | Central Standard Time
EST          | Eastern Standard Time
HAST         | Hawaii-Aleutian Standard Time
MST          | Mountain Standard Time
PST          | Pacific Standard Time
SST          | Samoa Standard Time

# Skip Geocoding (extracting field data from coordinates)

> Skip geocoding for a single coordinate with timezone field:

```shell
curl "https://api.geocod.io/v2/reverse?q=38.9002898,-76.9990361&skipGeocoding&fields=timezone&api_key=YOUR_API_KEY"
```

> Example response:

```json
{
  "results": [
    {
      "location": {
        "lat": 38.9002898,
        "lng": -76.9990361
      },
      "accuracy_type": "coordinate",
      "fields": {
        "timezone": {
          "name": "America/New_York",
          "utc_offset": -5,
          "observes_dst": true,
          "abbreviation": "EST",
          "source": "© IANA Time Zone Database"
        }
      }
    }
  ]
}
```

The `skipGeocoding` parameter allows you to skip the reverse geocoding step entirely and apply [field appends](#data-appends-fields) directly to the supplied coordinates. This is useful when:

* You already have geocoded coordinates and only need field append data (e.g. timezone, census, congressional districts) without paying for the geocoding lookup again
* You have coordinates that don't necessarily correspond to a street address (e.g. a point in a national park or body of water) and want to determine what geographic boundaries they fall within

When `skipGeocoding` is set, no geocoding lookup is billed — only field appends are counted.

> **Note:** The `fields` parameter is required when using `skipGeocoding`.

The response when using `skipGeocoding` is simplified compared to a standard reverse geocoding response. It only contains the `location` (lat/lng), `accuracy_type` (always set to `coordinate`), and `fields`. No address components or address data is returned.

`skipGeocoding` is supported for both [single](#reverse-geocoding-single-coordinate) and [batch](#batch-reverse-geocoding) reverse geocoding requests.

# Distance

Geocodio's distance API endpoints allow you to calculate driving time, driving distance, and straight line (as the crow flies/haversine) distance between addresses or coordinates. One-to-one, one-to-many, and many-to-many matrices are supported, and you can limit results to a specified radius.

Like the geocoding API, the method you choose depends on your use case.

For distance, *batch size* is the total number of calculations (origins × destinations).

Name                                  | Batch size (calculations)         | Type         | Format           | Supports addresses & coordinates |
------------------------------------- | ------------------ | ------------ | ---------------- | --------------------------- |
[Single origin distance](#single-origin-distance)        | 100                  | Synchronous  | JSON             | Yes |
[Distance matrix](#distance-matrix)   | Up to 10,000       | Synchronous  | JSON             | Yes |
[Distance jobs](#distance-jobs-async)    | Up to 50,000  | Asynchronous | JSON    | Yes |

To use Geocodio's Distance API endpoints, you'll need to enable access on an API key level [via the dashboard](https://dash.geocod.io/apikey).

## Location formats

Geocodio's Distance API accepts coordinates and addresses in three formats:

Format | Example | Description
------ | ------- | -----------
Coordinate string | `"38.8977,-77.0365"` | Latitude and longitude separated by a comma
Coordinate string with ID | `"38.8977,-77.0365,DC"` | Includes a custom identifier that will be returned in the response
Coordinate object | `{"lat": 38.8977, "lng": -77.0365, "id": "DC"}` | JSON object with lat, lng, and optional id properties
Address string | `"1600 Pennsylvania Ave NW, Washington DC"` | A geocodable address (will be geocoded automatically)

Address strings are not limited to US addresses. Any address in a [supported country](#supported-countries) is geocoded the same way, for example `"525 University Ave, Toronto, ON, Canada"`, `"Avenida Paseo De La Reforma 489, 06500 Ciudad De México, CMX"`, or `"10 Downing Street, London SW1A 2AA"`.

> **Note:** When addresses are geocoded, the geocoding result will be included in the response under a `geocode` property, and the lookup will count towards your geocoding credits. If your source locations are already coordinates, you won't be charged for geocoding.

## Calculation modes

Mode         | Description                                           | Duration returned | Credit multiplier
------------ | ----------------------------------------------------- | ----------------- | -----------------
`straightline` | Great-circle distance (as the crow flies) using the Haversine formula | No | 1x
`driving`    | Driving distance and driving time using road networks         | Yes               | 2x

> **Note:** The `driving` distance mode uses 2x the lookup credits of `straightline` distance mode.

## Single origin distance

> Calculate distances from a single origin to one or multiple destinations:

```shell
curl "https://api.geocod.io/v2/distance?origin=38.8977,-77.0365,WhiteHouse&destinations[]=38.8895,-77.0353,WashingtonMonument&destinations[]=38.9072,-77.0369,DupontCircle&mode=driving&api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

origin = '38.8977,-77.0365,WhiteHouse'
destinations = [
  '38.8895,-77.0353,WashingtonMonument',
  '38.9072,-77.0369,DupontCircle'
]

response = geocodio.distance(
  origin,
  destinations,
  mode: :driving,
  units: :miles
)
```

```python
from geocodio import Geocodio, DISTANCE_MODE_DRIVING, DISTANCE_UNITS_MILES

client = Geocodio("YOUR_API_KEY")

origin = "38.8977,-77.0365,WhiteHouse"
destinations = [
    "38.8895,-77.0353,WashingtonMonument",
    "38.9072,-77.0369,DupontCircle"
]

response = client.distance(
    origin,
    destinations,
    mode=DISTANCE_MODE_DRIVING,
    units=DISTANCE_UNITS_MILES
)

for destination in response.destinations:
    print(f"{destination.id}: {destination.distance_miles} miles, {destination.duration_seconds} seconds")
```

```php
<?php
use Geocodio\Enums\DistanceMode;
use Geocodio\Enums\DistanceUnits;

$origin = '38.8977,-77.0365,WhiteHouse';
$destinations = [
    '38.8895,-77.0353,WashingtonMonument',
    '38.9072,-77.0369,DupontCircle'
];

$response = $geocoder->distance(
    $origin,
    $destinations,
    mode: DistanceMode::Driving,
    units: DistanceUnits::Miles
);
```

```javascript
const Geocodio = require('geocodio-library-node');
const { DistanceMode, DistanceUnits } = Geocodio;

const geocoder = new Geocodio('YOUR_API_KEY');

const origin = '38.8977,-77.0365,WhiteHouse';
const destinations = [
  '38.8895,-77.0353,WashingtonMonument',
  '38.9072,-77.0369,DupontCircle'
];

geocoder.distance(origin, destinations, {
    mode: DistanceMode.Driving,
    units: DistanceUnits.Miles
  })
  .then(response => {
    console.log(response.destinations);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example response:

```json
{
  "mode": "driving",
  "origin": {
    "query": "38.8977,-77.0365,WhiteHouse",
    "id": "WhiteHouse",
    "location": [38.8977, -77.0365]
  },
  "destinations": [
    {
      "query": "38.8895,-77.0353,WashingtonMonument",
      "id": "WashingtonMonument",
      "location": [38.8895, -77.0353],
      "distance_miles": 0.6,
      "distance_km": 1.0,
      "duration_seconds": 180
    },
    {
      "query": "38.9072,-77.0369,DupontCircle",
      "id": "DupontCircle",
      "location": [38.9072, -77.0369],
      "distance_miles": 1.2,
      "distance_km": 1.9,
      "duration_seconds": 420
    }
  ]
}
```

Calculate driving and straight line distances and travel times from a single origin to one or more destinations. This is useful for finding the nearest locations to a given point.

### HTTP Request

`GET https://api.geocod.io/v2/distance`

### URL Parameters

Parameter | Description
--------- | -----------
`origin` | **Required.** The origin location (coordinate string, coordinate with ID, or address)
`destinations[]` | **Required.** Array of destination locations (max 100 per request)
`api_key` | Your Geocodio API key
`mode` | Optional. `driving` or `straightline`. Default is `straightline`
`units` | Optional. `miles` or `km`. Default is `miles`
`max_results` | Optional. Maximum number of destinations to return
`max_distance` | Optional. Filter out destinations beyond this distance (in specified units)
`min_distance` | Optional. Filter out destinations closer than this distance (in specified units)
`max_duration` | Optional. Filter out destinations with travel time exceeding this value in seconds (driving mode only)
`min_duration` | Optional. Filter out destinations with travel time below this value in seconds (driving mode only)
`order_by` | Optional. Sort destinations by `distance` or `duration`. Default is `distance`
`sort_order` | Optional. Sort order: `asc` or `desc`. Default is `asc`

### Response headers

Header | Description
------ | -----------
`X-BILLABLE-DISTANCE-CALCULATIONS` | Number of distance calculations billed for this request
`X-BILLABLE-LOOKUPS-COUNT` | Number of geocode lookups performed (only present if addresses were geocoded)

## Distance matrix

> Calculate driving and straight line distances between multiple origins and multiple destinations:

```shell
curl -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "origins": [
      "38.8977,-77.0365,DC",
      "40.7128,-74.0060,NYC"
    ],
    "destinations": [
      "39.80,-89.66,Springfield",
      "41.8781,-87.6298,Chicago"
    ],
    "mode": "driving"
  }' \
  "https://api.geocod.io/v2/distance-matrix?api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

origins = [
  '38.8977,-77.0365,DC',
  '40.7128,-74.0060,NYC'
]

destinations = [
  '39.80,-89.66,Springfield',
  '41.8781,-87.6298,Chicago'
]

response = geocodio.distanceMatrix(
  origins,
  destinations,
  mode: :driving,
  units: :miles
)
```

```python
from geocodio import Geocodio, DISTANCE_MODE_DRIVING, DISTANCE_UNITS_MILES

client = Geocodio("YOUR_API_KEY")

origins = [
    "38.8977,-77.0365,DC",
    "40.7128,-74.0060,NYC"
]

destinations = [
    "39.80,-89.66,Springfield",
    "41.8781,-87.6298,Chicago"
]

response = client.distance_matrix(
    origins,
    destinations,
    mode=DISTANCE_MODE_DRIVING,
    units=DISTANCE_UNITS_MILES
)

for result in response.results:
    print(f"From {result.origin.id}:")
    for dest in result.destinations:
        print(f"  to {dest.id}: {dest.distance_miles} miles")
```

```php
<?php
use Geocodio\Enums\DistanceMode;
use Geocodio\Enums\DistanceUnits;

$origins = [
    '38.8977,-77.0365,DC',
    '40.7128,-74.0060,NYC'
];

$destinations = [
    '39.80,-89.66,Springfield',
    '41.8781,-87.6298,Chicago'
];

$response = $geocoder->distanceMatrix(
    $origins,
    $destinations,
    mode: DistanceMode::Driving,
    units: DistanceUnits::Miles
);
```

```javascript
const Geocodio = require('geocodio-library-node');
const { DistanceMode, DistanceUnits } = Geocodio;

const geocoder = new Geocodio('YOUR_API_KEY');

const origins = [
  '38.8977,-77.0365,DC',
  '40.7128,-74.0060,NYC'
];

const destinations = [
  '39.80,-89.66,Springfield',
  '41.8781,-87.6298,Chicago'
];

geocoder.distanceMatrix(origins, destinations, {
    mode: DistanceMode.Driving,
    units: DistanceUnits.Miles
  })
  .then(response => {
    console.log(response.results);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example response:

```json
{
  "mode": "driving",
  "results": [
    {
      "origin": {
        "query": "38.8977,-77.0365,DC",
        "id": "DC",
        "location": [38.8977, -77.0365]
      },
      "destinations": [
        {
          "query": "39.80,-89.66,Springfield",
          "id": "Springfield",
          "location": [39.80, -89.66],
          "distance_miles": 699.2,
          "distance_km": 1125.3,
          "duration_seconds": 36540
        },
        {
          "query": "41.8781,-87.6298,Chicago",
          "id": "Chicago",
          "location": [41.8781, -87.6298],
          "distance_miles": 695.2,
          "distance_km": 1118.9,
          "duration_seconds": 36000
        }
      ]
    },
    {
      "origin": {
        "query": "40.7128,-74.0060,NYC",
        "id": "NYC",
        "location": [40.7128, -74.0060]
      },
      "destinations": [
        {
          "query": "39.80,-89.66,Springfield",
          "id": "Springfield",
          "location": [39.80, -89.66],
          "distance_miles": 876.5,
          "distance_km": 1410.6,
          "duration_seconds": 45900
        },
        {
          "query": "41.8781,-87.6298,Chicago",
          "id": "Chicago",
          "location": [41.8781, -87.6298],
          "distance_miles": 790.1,
          "distance_km": 1271.5,
          "duration_seconds": 41400
        }
      ]
    }
  ]
}
```

Calculate driving distance, driving time, and straight line distance from multiple origins to multiple destinations (distance matrix). This is useful for route optimization, coverage analysis, and logistics planning.

> **Warning:** The matrix size (origins × destinations) is limited to 10,000 calculations per request. For larger matrices, use the [asynchronous distance jobs](#distance-jobs-async) endpoint.

### HTTP Request

`POST https://api.geocod.io/v2/distance-matrix`

### Request Body Parameters

Parameter | Description
--------- | -----------
`origins` | **Required.** Array of origin locations
`destinations` | **Required.** Array of destination locations
`mode` | Optional. `driving` or `straightline`. Default is `straightline`
`units` | Optional. `miles` or `km`. Default is `miles`
`max_results` | Optional. Maximum number of destinations to return per origin
`max_distance` | Optional. Maximum distance filter (in specified units)
`min_distance` | Optional. Minimum distance filter (in specified units)
`max_duration` | Optional. Maximum duration filter in seconds (driving mode only)
`min_duration` | Optional. Minimum duration filter in seconds (driving mode only)
`order_by` | Optional. Sort destinations by `distance` or `duration`. Default is `distance`
`sort_order` | Optional. Sort order: `asc` or `desc`. Default is `asc`

### URL Parameters

Parameter | Description
--------- | -----------
`api_key` | Your Geocodio API key

### Response headers

Header | Description
------ | -----------
`X-BILLABLE-DISTANCE-CALCULATIONS` | Number of distance calculations billed for this request
`X-BILLABLE-LOOKUPS-COUNT` | Number of geocode lookups performed (only present if addresses were geocoded)

## Distance jobs (async)

For large-scale distance calculations exceeding the synchronous limits, you can create asynchronous distance matrix jobs. Similar to the [Lists API](#geocoding-lists), jobs are processed in the background and results can be downloaded when complete.

> **Warning:** Distance job results are automatically deleted 72 hours after processing completes. The maximum job size is 50,000 calculations (origins × destinations).

### Create a distance matrix job

> Create a new distance matrix job:

```shell
curl -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Store to Customer Distances",
    "origins": [
      {"lat": 38.8977, "lng": -77.0365, "id": "Store1"},
      {"lat": 40.7128, "lng": -74.0060, "id": "Store2"}
    ],
    "destinations": [
      "39.80,-89.66,Customer1",
      "41.8781,-87.6298,Customer2",
      "34.0522,-118.2437,Customer3"
    ],
    "distance_mode": "driving",
    "max_results": 2,
    "order_by": "distance"
  }' \
  "https://api.geocod.io/v2/distance-jobs?api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

origins = [
  { lat: 38.8977, lng: -77.0365, id: 'Store1' },
  { lat: 40.7128, lng: -74.0060, id: 'Store2' }
]

destinations = [
  '39.80,-89.66,Customer1',
  '41.8781,-87.6298,Customer2',
  '34.0522,-118.2437,Customer3'
]

job = geocodio.createDistanceMatrixJob(
  'Store to Customer Distances',
  origins,
  destinations,
  mode: :driving,
  max_results: 2,
  order_by: :distance
)

puts job.identifier
```

```python
from geocodio import Geocodio, DISTANCE_MODE_DRIVING, DISTANCE_ORDER_BY_DISTANCE

client = Geocodio("YOUR_API_KEY")

origins = [
    {"lat": 38.8977, "lng": -77.0365, "id": "Store1"},
    {"lat": 40.7128, "lng": -74.0060, "id": "Store2"}
]

destinations = [
    "39.80,-89.66,Customer1",
    "41.8781,-87.6298,Customer2",
    "34.0522,-118.2437,Customer3"
]

job = client.create_distance_matrix_job(
    name="Store to Customer Distances",
    origins=origins,
    destinations=destinations,
    mode=DISTANCE_MODE_DRIVING,
    max_results=2,
    order_by=DISTANCE_ORDER_BY_DISTANCE
)

print(f"Job created: {job.identifier}")
```

```php
<?php
use Geocodio\Enums\DistanceMode;
use Geocodio\Enums\DistanceOrderBy;

$origins = [
    ['lat' => 38.8977, 'lng' => -77.0365, 'id' => 'Store1'],
    ['lat' => 40.7128, 'lng' => -74.0060, 'id' => 'Store2']
];

$destinations = [
    '39.80,-89.66,Customer1',
    '41.8781,-87.6298,Customer2',
    '34.0522,-118.2437,Customer3'
];

$job = $geocoder->createDistanceMatrixJob(
    name: 'Store to Customer Distances',
    origins: $origins,
    destinations: $destinations,
    mode: DistanceMode::Driving,
    maxResults: 2,
    orderBy: DistanceOrderBy::Distance
);

echo $job->identifier;
```

```javascript
const Geocodio = require('geocodio-library-node');
const { DistanceMode, DistanceOrderBy } = Geocodio;

const geocoder = new Geocodio('YOUR_API_KEY');

const origins = [
  { lat: 38.8977, lng: -77.0365, id: 'Store1' },
  { lat: 40.7128, lng: -74.0060, id: 'Store2' }
];

const destinations = [
  '39.80,-89.66,Customer1',
  '41.8781,-87.6298,Customer2',
  '34.0522,-118.2437,Customer3'
];

geocoder.createDistanceMatrixJob(
    'Store to Customer Distances',
    origins,
    destinations,
    {
      mode: DistanceMode.Driving,
      maxResults: 2,
      orderBy: DistanceOrderBy.Distance
    }
  )
  .then(job => {
    console.log(`Job created: ${job.identifier}`);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example response:

```json
{
  "identifier": "abc123xyz",
  "name": "Store to Customer Distances",
  "status": "ENQUEUED",
  "created_at": "2026-01-06T10:30:00Z",
  "origins_type": "coordinates",
  "origins_count": 2,
  "destinations_type": "coordinates",
  "destinations_count": 3,
  "distance_mode": "driving",
  "total_calculations": 6,
  "calculations_completed": 0,
  "progress": 0,
  "is_expired": false
}
```

Creates a new distance matrix job and starts processing in the background. The response returns a job identifier that can be used to check the status and download results when complete.

### HTTP Request

`POST https://api.geocod.io/v2/distance-jobs`

### Request Body Parameters

Parameter | Description
--------- | -----------
`name` | **Required.** A name for this distance matrix job (max 255 characters)
`origins` | **Required.** Array of origin locations, or an integer list ID from a previously uploaded spreadsheet
`destinations` | **Required.** Array of destination locations, or an integer list ID from a previously uploaded spreadsheet
`distance_mode` | Optional. `driving` or `straightline`. Default is `straightline`
`units` | Optional. `miles` or `km`. Default is `miles`
`max_results` | Optional. Maximum number of destinations to return per origin
`max_distance` | Optional. Maximum distance filter (in specified units)
`min_distance` | Optional. Minimum distance filter (in specified units)
`max_duration` | Optional. Maximum duration filter in seconds (driving mode only)
`min_duration` | Optional. Minimum duration filter in seconds (driving mode only)
`order_by` | Optional. Sort destinations by `distance` or `duration`. Default is `distance`
`sort_order` | Optional. Sort order: `asc` or `desc`. Default is `asc`
`fields` | Optional. Comma-separated list of data fields to append to geocoded results
`callback_url` | Optional. URL to receive a webhook notification when the job completes

### URL Parameters

Parameter | Description
--------- | -----------
`api_key` | Your Geocodio API key

### Using list IDs

You can reference previously uploaded spreadsheets by their list ID instead of providing inline coordinates:

```shell
curl -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Warehouse Distances",
    "origins": 123,
    "destinations": 456,
    "distance_mode": "driving"
  }' \
  "https://api.geocod.io/v2/distance-jobs?api_key=YOUR_API_KEY"
```

### See distance job status

> Get the status of a distance job:

```shell
curl "https://api.geocod.io/v2/distance-jobs/abc123xyz?api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

status = geocodio.distanceMatrixJobStatus('abc123xyz')

puts "Progress: #{status.progress}%"
puts "Status: #{status.status}"
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

status = client.distance_matrix_job_status("abc123xyz")

print(f"Progress: {status.progress}%")
print(f"Status: {status.status}")
```

```php
<?php
$status = $geocoder->distanceMatrixJobStatus('abc123xyz');

echo "Progress: {$status->progress}%";
echo "Status: {$status->status}";
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocoder = new Geocodio('YOUR_API_KEY');

geocoder.distanceMatrixJobStatus('abc123xyz')
  .then(status => {
    console.log(`Progress: ${status.progress}%`);
    console.log(`Status: ${status.status}`);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example response (processing):

```json
{
  "identifier": "abc123xyz",
  "name": "Store to Customer Distances",
  "status": "PROCESSING",
  "created_at": "2026-01-06T10:30:00Z",
  "origins_type": "coordinates",
  "origins_count": 2,
  "destinations_type": "coordinates",
  "destinations_count": 3,
  "distance_mode": "driving",
  "total_calculations": 6,
  "calculations_completed": 4,
  "progress": 66.67,
  "status_message": "Processing distance calculations",
  "time_left": "1 minute",
  "is_expired": false
}
```

> Example response (completed):

```json
{
  "identifier": "abc123xyz",
  "name": "Store to Customer Distances",
  "status": "COMPLETED",
  "created_at": "2026-01-06T10:30:00Z",
  "origins_type": "coordinates",
  "origins_count": 2,
  "destinations_type": "coordinates",
  "destinations_count": 3,
  "distance_mode": "driving",
  "total_calculations": 6,
  "calculations_completed": 6,
  "progress": 100,
  "download_url": "https://api.geocod.io/v2/distance-jobs/abc123xyz/download",
  "is_expired": false
}
```

### HTTP Request

`GET https://api.geocod.io/v2/distance-jobs/{identifier}`

### URL Parameters

Parameter | Description
--------- | -----------
`identifier` | The job identifier returned when the job was created
`api_key` | Your Geocodio API key

### Job status values

Status | Description
------ | -----------
`ENQUEUED` | Job is waiting to be processed
`PROCESSING` | Job is currently being processed
`COMPLETED` | Job is complete, results available for download
`FAILED` | Job processing failed

### List all distance jobs

> List all distance jobs:

```shell
curl "https://api.geocod.io/v2/distance-jobs?api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

# Get page 1 (default)
jobs = geocodio.distanceMatrixJobs

jobs.data.each do |job|
  puts "#{job.name}: #{job.status}"
end
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

# Get all jobs (page 1 by default)
jobs = client.distance_matrix_jobs()

for job in jobs.data:
    print(f"{job.name}: {job.status}")
```

```php
<?php
// Get page 1 (default)
$jobs = $geocoder->distanceMatrixJobs();

foreach ($jobs->data as $job) {
    echo "{$job->name}: {$job->status}";
}
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocoder = new Geocodio('YOUR_API_KEY');

// Get page 1 (default)
geocoder.distanceMatrixJobs()
  .then(response => {
    response.data.forEach(job => {
      console.log(`${job.name}: ${job.status}`);
    });
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example response:

```json
{
  "data": [
    {
      "identifier": "abc123xyz",
      "name": "Store to Customer Distances",
      "status": "COMPLETED",
      "created_at": "2026-01-06T10:30:00Z",
      "total_calculations": 6,
      "progress": 100,
      "is_expired": false
    }
  ],
  "links": {
    "first": "https://api.geocod.io/v2/distance-jobs?page=1",
    "last": "https://api.geocod.io/v2/distance-jobs?page=1",
    "prev": null,
    "next": null
  },
  "meta": {
    "current_page": 1,
    "last_page": 1,
    "per_page": 20,
    "total": 1
  }
}
```

Returns a paginated list of all distance matrix jobs.

### HTTP Request

`GET https://api.geocod.io/v2/distance-jobs`

### URL Parameters

Parameter | Description
--------- | -----------
`api_key` | Your Geocodio API key
`page` | Optional. Page number for pagination (default: 1)

### Download distance job results

> Download results for a completed job:

```shell
curl "https://api.geocod.io/v2/distance-jobs/abc123xyz/download?api_key=YOUR_API_KEY" \
  -o results.json
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

# Get results as parsed JSON
results = geocodio.getDistanceMatrixJobResults('abc123xyz')

# Or download to a file
geocodio.downloadDistanceMatrixJob('abc123xyz', 'results.json')
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

# Get results as parsed JSON
results = client.get_distance_matrix_job_results("abc123xyz")

for result in results.results:
    print(f"From {result.origin.id}:")
    for dest in result.destinations:
        print(f"  to {dest.id}: {dest.distance_miles} miles")

# Or download to a file
client.download_distance_matrix_job("abc123xyz", "results.json")
```

```php
<?php
// Get results as parsed JSON
$results = $geocoder->getDistanceMatrixJobResults('abc123xyz');

foreach ($results->results as $result) {
    echo "From {$result->origin->id}:";
    foreach ($result->destinations as $dest) {
        echo "  to {$dest->id}: {$dest->distance_miles} miles";
    }
}

// Or download to a file
$geocoder->downloadDistanceMatrixJob('abc123xyz', 'results.json');
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocoder = new Geocodio('YOUR_API_KEY');

// Get results as parsed JSON
geocoder.getDistanceMatrixJobResults('abc123xyz')
  .then(results => {
    results.results.forEach(result => {
      console.log(`From ${result.origin.id}:`);
      result.destinations.forEach(dest => {
        console.log(`  to ${dest.id}: ${dest.distance_miles} miles`);
      });
    });
  })
  .catch(err => {
    console.error(err);
  }
);

// Or download to a file
geocoder.downloadDistanceMatrixJob('abc123xyz', 'results.json');
```

Download the results of a completed distance matrix job as a JSON file. The response format is the same as the [distance matrix endpoint](#distance-matrix).

> **Warning:** Results are only available when the job status is `COMPLETED`. Results expire 72 hours after processing completes.

### HTTP Request

`GET https://api.geocod.io/v2/distance-jobs/{identifier}/download`

### URL Parameters

Parameter | Description
--------- | -----------
`identifier` | The job identifier
`api_key` | Your Geocodio API key

### Delete a distance job

> Delete a distance job:

```shell
curl -X DELETE "https://api.geocod.io/v2/distance-jobs/abc123xyz?api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

geocodio.deleteDistanceMatrixJob('abc123xyz')
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

client.delete_distance_matrix_job("abc123xyz")
```

```php
<?php
$geocoder->deleteDistanceMatrixJob('abc123xyz');
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocoder = new Geocodio('YOUR_API_KEY');

geocoder.deleteDistanceMatrixJob('abc123xyz')
  .then(() => {
    console.log('Job deleted successfully');
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Example response:

```json
{
  "message": "Distance matrix job deleted successfully"
}
```

Deletes a distance matrix job and its results.

### HTTP Request

`DELETE https://api.geocod.io/v2/distance-jobs/{identifier}`

### URL Parameters

Parameter | Description
--------- | -----------
`identifier` | The job identifier
`api_key` | Your Geocodio API key

# Address components

Geocodio parses and standardizes all address results, and all results come with an `address_components` dictionary. This is an overview of all of the possible keys that you may find.

The key will not be present if there is no valid value for it. For example, if the address does not have a `predirectional`, this key will not be present.

Name               | Notes
------------------ | ---------------------------
number             | House number, e.g. "2100" or "250 1/2"
predirectional     | Directional that comes before the street name, 1-2 characters, e.g. N or NE
prefix             | Abbreviated street prefix, particularly common in the case of French addresses e.g. Rue, Boulevard, Impasse
street             | Name of the street without number, prefix or suffix, e.g. "Main"
suffix             | Abbreviated street suffix, e.g. St., Ave. Rd.
postdirectional    | Directional that comes after the street name, 1-2 characters, e.g. N or NE
unit_type          | Unit designator parsed from a secondary address, e.g. "Apt" or "Ste"
unit_number        | Secondary unit number, e.g. "204"
city               |
county             |
state_province     | State, province, or other top-level administrative area
postal_code        | 5-digit ZIP code for US addresses. For Canadian results, only the 3-character FSA is returned (full postal codes cannot be redistributed under Canada Post licensing). A full postal code you supply is echoed back when its FSA matches the geocoded result (and noted in `source`)
country            |
formatted_street   | Fully formatted street, including all directionals, suffix/prefix but not house number

# Accuracy score
Each geocoded result from Geocodio is returned with an accuracy score, which is a decimal number ranging from 0.00 to 1.00. This score is generated by the internal Geocodio engine based on how accurate the result is believed to be. The higher the score, the better the result. Results are always returned ordered by accuracy score.

For example, if against all odds an address simply can't be found, instead of returning no results, Geocodio will return a geocoded point based on the postal code or city but with a much lower accuracy score and accuracy type set to "place".

Generally, accuracy scores that are larger than or equal to `0.8` are the most accurate, whereas results with lower accuracy scores might be very rough matches.

An accuracy type is also returned with all results. The accuracy types are different for forward and reverse geocoding results.

We recommend using a combination of the accuracy score and accuracy type to evaluate and filter the returned results.

### Forward geocoding

Value                 | Description
--------------------- | -----------
rooftop               | The exact point was found with rooftop level accuracy
point                 | The exact point was found from address range interpolation where the range contained a single point
range_interpolation   | The point was found by performing [address range interpolation](http://en.wikipedia.org/wiki/Geocoding#Address_interpolation)
nearest_rooftop_match | The exact house number was not found, so a close, neighboring house number was used instead
intersection          | The result is an intersection between two streets
street_center         | The result is a geocoded street centroid
place                 | The point is a city/town/place zip code centroid
county                | The point is a county centroid
state                 | The point is a state centroid

![Visual guide to the most common accuracy types](https://www.geocod.io/docs/images/accuracy-types-b0200132.png)

*Visual guide to the most common accuracy types*

### Reverse geocoding

Value               | Description
------------------- | -----------
rooftop             | We found the exact point with rooftop level accuracy
nearest_street      | Nearest match for a specific street with estimated street number
nearest_place       | Closest city/town/place

## Match Type

All geocoding results include a `match_type` field that indicates the type of coordinate match. This field provides additional granularity beyond `accuracy_type` and can help you understand the source of the returned coordinates.

Unlike `accuracy_type`, the `match_type` value can be `null` when no specific match type information is available.

Value               | Description
------------------- | -----------
`building_centroid` | Coordinates derived from a building footprint centroid. Pairs with `rooftop` and `nearest_rooftop_match` accuracy types
`parcel_centroid`   | Coordinates derived from a property parcel centroid. Pairs with `rooftop` and `nearest_rooftop_match` accuracy types
`unit`              | Unit-level coordinates from [secondary address line geocoding](#secondary-address-line-geocoding). The result has been matched to a specific apartment, suite, or unit within a building
`null`              | No specific match type information is available. This can apply to any accuracy type, including `rooftop` results where the coordinate source type is not known, as well as `range_interpolation`, `street_center`, `place`, and other result types

> **Note:** The `match_type` field is additive and does not change the behavior of existing `accuracy_type` values. It is returned for all API versions.

# Stable Address Keys

> Example `stable_address_key` in a geocoding result:

```json
{
  "results": [
    {
      "address_components": { ... },
      "formatted_address": "1109 N Highland St, Arlington, VA 22201",
      "location": {
        "lat": 38.886665,
        "lng": -77.094733
      },
      "accuracy": 1,
      "accuracy_type": "rooftop",
      "source": "Virginia GIS Clearinghouse",
      "stable_address_key": "gcod_usnbfvbm5l57cc8b8bnfnyrua9ym3"
    }
  ]
}
```

Every geocoding result includes a `stable_address_key`, a deterministic identifier that uniquely represents the geocoded address.

For `rooftop`, `range_interpolation`, and other house number-level results, the key is unique to a specific house number on a street. For `street_center` results, the key is unique to a specific street.

### Unit suffixes

When a secondary address component is provided (e.g. apartment, suite, or unit number), the stable address key includes a unit suffix appended with a dash separator. For example: `gcod_usnbfvbm5l57cc8b8bnfnyrua9ym3-a1b2c3`.

The base key (before the dash) identifies the street address, while the suffix identifies the specific unit. This means:

* `gcod_usnbfvbm5l57cc8b8bnfnyrua9ym3` &mdash; the building at 734 Ave C, El Campo TX
* `gcod_usnbfvbm5l57cc8b8bnfnyrua9ym3-a1b2c3` &mdash; Unit A at 734 Ave C, El Campo TX
* `gcod_usnbfvbm5l57cc8b8bnfnyrua9ym3-d4e5f6` &mdash; Unit B at 734 Ave C, El Campo TX

The full key with unit suffix can be used as input for geocoding and distance calculations. If the specific unit is not found in our database, the lookup falls back to the building-level result.

The unit suffix is computed regardless of whether we have unit-level coordinates &mdash; if a unit is specified in the input address, the suffix is always included in the key.

We recommend always storing the stable address key alongside your geocoded results. Stable address keys are useful for:

* **Deduplication:** Two addresses that resolve to the same location will share the same stable address key, making it easy to identify and deduplicate addresses in your database
* **Updated results:** Store the stable address key and use it to retrieve the latest geocoding data for an address in the future. For example, an address that currently returns a `range_interpolation` result may be upgraded to a `rooftop` result as our coverage improves
* **Data enrichment:** Request additional [field appends](#data-appends-fields) for previously geocoded addresses without paying for geocoding again (see [billing](#stable-address-key-billing) below)

### Guarantees

* **Persistent:** A stable address key, once issued, will always remain valid and can be used to look up the same address in the future
* **Deterministic:** The same address will always produce the same stable address key, regardless of minor formatting differences (e.g. "Street" vs "St", "North" vs "N")
* **Cross-version:** Stable address keys work across all API versions

### What to expect

* **Results may improve over time:** The coordinates or accuracy type returned for a stable address key may change as our data coverage improves. This is by design, and you will always get the best available result
* **New keys may be issued:** As coverage expands, an address that previously returned a `street_center`-level key may return a more specific house number-level key in the future

> **Note:** Treat the stable address key as an opaque string. Do not parse or rely on the internal format of the key, as it may change for newly issued keys. The length of the string is not guaranteed to be fixed. Existing keys will always remain valid.

### Using stable address keys as input

> Using a stable address key as input for geocoding:

```shell
curl "https://api.geocod.io/v2/geocode?q=gcod_usnbfvbm5l57cc8b8bnfnyrua9ym3&api_key=YOUR_API_KEY"
```

```ruby
require 'geocodio/gem'

geocodio = Geocodio::Gem.new('YOUR_API_KEY')

location = geocodio.geocode(['gcod_usnbfvbm5l57cc8b8bnfnyrua9ym3'])
```

```python
from geocodio import Geocodio

client = Geocodio("YOUR_API_KEY")

response = client.geocode("gcod_usnbfvbm5l57cc8b8bnfnyrua9ym3")
```

```php
<?php
$response = $geocoder->geocode('gcod_usnbfvbm5l57cc8b8bnfnyrua9ym3');
```

```javascript
const Geocodio = require('geocodio-library-node');
const geocoder = new Geocodio('YOUR_API_KEY');

geocoder.geocode('gcod_usnbfvbm5l57cc8b8bnfnyrua9ym3')
  .then(response => {
    console.log(response);
  })
  .catch(err => {
    console.error(err);
  }
);
```

> Using a stable address key with field appends (does not count as a geocoding lookup):

```shell
curl "https://api.geocod.io/v2/geocode?q=gcod_usnbfvbm5l57cc8b8bnfnyrua9ym3&fields=census,cd&api_key=YOUR_API_KEY"
```

Stable address keys can be used anywhere an address is accepted as input. This includes [single geocoding](#geocoding), [batch geocoding](#batch-geocoding), [distance](#distance) endpoints, and [list geocoding](#geocoding-lists). Simply pass the stable address key as the `q` parameter or as an item in a batch request.

### Billing

When you look up a stable address key, it counts as a regular geocoding lookup. However, if you request [field appends](#data-appends-fields) using a stable address key, the geocoding portion is free and you only pay for the field appends. This means you can enrich already-geocoded addresses with additional data without paying for geocoding again.

# Address formats
Geocodio supports geocoding the following address components:

* Streets with or without house numbers (requires a city or a zip in conjuction)
* [Intersections](#intersections)
* Cities
* Zip codes
* Counties
* States
* PO Boxes (coordinates will be returned as a centroid of the zip code)
* Second address lines such as unit and apartment numbers (used for [unit-level geocoding](#secondary-address-line-geocoding) when data is available)

If a city is provided without a state, Geocodio will automatically guess and add the state based on what it is most likely to be. Geocodio also understands shorthands for both streets and cities, for example *NYC*, *SF*, etc., are acceptable city names.

Geocoding queries can be formatted in various ways:

* [1109 N Highland St, Arlington VA](https://api.geocod.io/v2/geocode?q=1109+N+Highland+St%2c+Arlington+VA&api_key=YOUR_API_KEY)
* [1109 N Highland Street, Arlington VA](https://api.geocod.io/v2/geocode?q=1109+N+Highland+Street%2c+Arlington+VA&api_key=YOUR_API_KEY)
* [1109 North Highland Street, Arlington VA](https://api.geocod.io/v2/geocode?q=1109+North+Highland+Street%2c+Arlington+VA&api_key=YOUR_API_KEY)
* [1109 N Highland St, Arlington VA](https://api.geocod.io/v2/geocode?q=1109+N+Highland+St%2c+Arlington+VA&api_key=YOUR_API_KEY)
* [1109 N Highland St, 22201](https://api.geocod.io/v2/geocode?q=1109+N+Highland+St,+22201&api_key=YOUR_API_KEY)
* [Arlington, VA](https://api.geocod.io/v2/geocode?q=Arlington%2c+VA&api_key=YOUR_API_KEY)
* [Arlington](https://api.geocod.io/v2/geocode?q=Arlington&api_key=YOUR_API_KEY)
* [VA](https://api.geocod.io/v2/geocode?q=VA&api_key=YOUR_API_KEY)
* [22201](https://api.geocod.io/v2/geocode?q=22201&api_key=YOUR_API_KEY)
* [PO Box 4735, Tulsa OK](https://api.geocod.io/v2/geocode?q=PO+Box+4735,+Tulsa+OK&api_key=YOUR_API_KEY)
* [Santa Clara County](https://api.geocod.io/v2/geocode?q=Santa%20Clara%20County&api_key=YOUR_API_KEY)
* [Santa Clara County, CA](https://api.geocod.io/v2/geocode?q=Santa%20Clara%20County%2C%20CA&api_key=YOUR_API_KEY)
* [1 Infinite Loop, Santa Clara County](https://api.geocod.io/v2/geocode?q=1%20Infinite%20Loop%2C%20Santa%20Clara%20County&api_key=YOUR_API_KEY)
* [1 Infinite Loop, Santa Clara County, CA](https://api.geocod.io/v2/geocode?q=1%20Infinite%20Loop%2C%20Santa%20Clara%20County%2C%20CA&api_key=YOUR_API_KEY)
* [1 Infinite Loop, Santa Clara County, Cupertino CA](https://api.geocod.io/v2/geocode?q=1%20Infinite%20Loop%2C%20Santa%20Clara%20County%2C%20Cupertino%20CA&api_key=YOUR_API_KEY)

If a country is not specified in the query, the Geocodio engine will assume the country to be USA. Pass the [`country` parameter](#specifying-country) — or include the country in the query itself — for any address outside the US. The examples below cover the countries Geocodio supports today; see [Supported Countries](#supported-countries) for the current list.

Examples of Canadian lookups:

* [525 University Ave, Toronto, ON, Canada](https://api.geocod.io/v2/geocode?q=525+University+Ave%2C+Toronto%2C+ON%2C+Canada&api_key=YOUR_API_KEY)
* [7515 118 Ave NW, Edmonton, AB T5B 0X2, Canada](https://api.geocod.io/v2/geocode?q=7515+118+Ave+NW%2C+Edmonton%2C+AB+T5B+0X2%2C+Canada&api_key=YOUR_API_KEY)
* [300 King St, Sturgeon Falls, ON P2B 3A1, Canada](https://api.geocod.io/v2/geocode?q=300+King+St%2C+Sturgeon+Falls%2C+ON+P2B+3A1%2C+Canada&api_key=YOUR_API_KEY)
* [203 Laycoe Crescent, Saskatoon, SK, Canada](https://api.geocod.io/v2/geocode?q=203+Laycoe+Crescent%2C+Saskatoon%2C+SK%2C+Canada&api_key=YOUR_API_KEY)
* [Vancouver, BC, Canada](https://api.geocod.io/v2/geocode?q=Vancouver%2C+BC%2C+Canada&api_key=YOUR_API_KEY)
* [M5G](https://api.geocod.io/v2/geocode?q=M5G&country=Canada&api_key=YOUR_API_KEY) (FSA on its own)

Examples of Mexican lookups. Mexican addresses put the house number after the street name and the postal code before the city:

* [Avenida Paseo De La Reforma 489, 06500 Ciudad De México, CMX](https://api.geocod.io/v2/geocode?q=Avenida+Paseo+De+La+Reforma+489%2C+06500+Ciudad+De+M%C3%A9xico%2C+CMX&country=Mexico&api_key=YOUR_API_KEY)
* [Avenida Paseo De La Reforma 489, Ciudad De México](https://api.geocod.io/v2/geocode?q=Avenida+Paseo+De+La+Reforma+489%2C+Ciudad+De+M%C3%A9xico&country=Mexico&api_key=YOUR_API_KEY)
* [Guadalajara, Jalisco](https://api.geocod.io/v2/geocode?q=Guadalajara%2C+Jalisco&country=Mexico&api_key=YOUR_API_KEY)
* [Monterrey, Nuevo Leon](https://api.geocod.io/v2/geocode?q=Monterrey%2C+Nuevo+Leon&country=Mexico&api_key=YOUR_API_KEY)
* [06500](https://api.geocod.io/v2/geocode?q=06500&country=Mexico&api_key=YOUR_API_KEY) (postal code on its own)

Examples of United Kingdom lookups. GB addresses are not distinguishable from US ones by format alone, so always send `country=GB`:

* [10 Downing Street, London SW1A 2AA](https://api.geocod.io/v2/geocode?q=10+Downing+Street%2C+London+SW1A+2AA&country=GB&api_key=YOUR_API_KEY)
* [SW1A 2AA](https://api.geocod.io/v2/geocode?q=SW1A+2AA&country=GB&api_key=YOUR_API_KEY) (postcode on its own)
* [SW1A](https://api.geocod.io/v2/geocode?q=SW1A&country=GB&api_key=YOUR_API_KEY) (outward code on its own)
* [Edinburgh](https://api.geocod.io/v2/geocode?q=Edinburgh&country=GB&api_key=YOUR_API_KEY)

## Intersections

You can also geocode intersections. Just specify the two streets that you want to geocode in your query. We support various formats:

* [E 58th St and Madison Ave, New York, NY](https://api.geocod.io/v2/geocode?q=E+58th+St+and+Madison+Ave%2C+New+York%2C+NY&api_key=YOUR_API_KEY)
* [Market and 4th, San Francisco](https://api.geocod.io/v2/geocode?q=Market+and+4th%2C+San+Francisco&api_key=YOUR_API_KEY)
* [Commonwealth Ave at Washington Street, Boston, MA](https://api.geocod.io/v2/geocode?q=Commonwealth+Ave+at+Washington+Street%2C+Boston%2C+MA&api_key=YOUR_API_KEY)
* [Florencia & Perlita, Austin TX](https://api.geocod.io/v2/geocode?q=Florencia+%26+Perlita%2C+Austin+TX&api_key=YOUR_API_KEY)
* [Quail Trail @ Dinkle Rd, Edgewood, NM](https://api.geocod.io/v2/geocode?q=Quail+Trail+%40+Dinkle+Rd%2C+Edgewood%2C+NM&api_key=YOUR_API_KEY)
* [8th St SE/I St SE, 20003](https://api.geocod.io/v2/geocode?q=8th+St+SE%2FI+St+SE%2C+20003&api_key=YOUR_API_KEY)

An extra `address_components_secondary` property will be exposed for intersection results, but otherwise, the schema format is the same.

```json
{
  ...
  "results": [
    {
      "address_components": {
        "street": "4th",
        "suffix": "St",
        "formatted_street": "4th St",
        "city": "San Francisco",
        "county": "San Francisco County",
        "state_province": "CA",
        "postal_code": "94103"
      },
      "address_components_secondary": {
        "street": "Market",
        "suffix": "St",
        "formatted_street": "Market St",
        "city": "San Francisco",
        "county": "San Francisco County",
        "state_province": "CA",
        "postal_code": "94103"
      },
      [
        "4th St and Market St",
        "",
        "San Francisco, CA 94103"
      ],
      "formatted_address": "4th St and Market St, San Francisco, CA 94103",
      "location": {
        "lat": 37.785725,
        "lng": -122.405807
      },
      "accuracy": 1,
      "accuracy_type": "intersection",
      "source": "TIGER/Line® dataset from the US Census Bureau"
    }
  ]
  ...
}
```

# Errors
> Here is an example of a 422 Unprocessable Entity response:

```json
{
  "error": "Could not geocode address, zip code or city/state are required"
}
```

> This error message is returned with a 403 HTTP status code when you exceed the free tier with no payment method on file:

```json
{
  "error": "You can't make this request as it is above your daily maximum. You can configure billing at https://dash.geocod.io"
}
```

The Geocodio API employs semantic HTTP status codes:

Error Code | Meaning
---------- | -------
200 OK | Hopefully you will see this most of the time. Note that this status code will also be returned even though no geocoding results were available.
403 Forbidden | Invalid API key, or other reason why access is forbidden.
422 Unprocessable Entity | A client error prevented the request from executing successfully (e.g. invalid address provided). A JSON object will be returned with an error key containing a full error message.
429 Too Many Requests | You've reached the Pay as You Go rate limit. Please inspect the following HTTP headers: `X-RateLimit-Remaining`, `X-RateLimit-Limit`, `X-RateLimit-Period` and stop making requests until the end of the `X-RateLimit-Period` value.
500 Server Error | Hopefully you will never see this...it means that something went wrong in our end. Whoops.

If you encounter any unexpected errors, please check [status.geocod.io](https://status.geocod.io) for the latest platform status updates.

# Warnings

The Geocodio API implements the concept of "warnings". This is meant to assist and guide developers when implementing our API.

Warnings are represented with a `_warnings` key, and it can be applied to either an individual geocoding result or an overall geocoding query.

If no warnings have been triggered, the `_warnings` key will not be part of the JSON output at all.

> Here's an example where the query parameter `postalcode` accidentally was used instead of `postal_code`

```json
{
  "results": [
    ...
  ],
  "_warnings": [
    "Ignoring parameter \"postalcode\" as it was not expected. Did you mean \"postal_code\"? See full list of valid parameters here: https://www.geocod.io/docs/"
  ]
}
```

> Warnings can also be triggered for individual results, such as when an FFIEC field append was specified for a city-level query:

```json
{
  "results": [
    {
      ...
      "_warnings": [
        "ffiec field was skipped since result is not street-level"
      ]
    }
  ]
}
```

# CORS
> To Geocode an address using the JavaScript `fetch` API:

```html
<script>
const address = '1109 N Highland St, Arlington VA';
const apiKey = 'YOUR_API_KEY';
const url = `https://api.geocod.io/v2/geocode?q=${encodeURIComponent(address)}&api_key=${encodeURIComponent(apiKey)}`;

fetch(url)
  .then(response => response.json())
  .then(data => {
    console.log(data.results);
  })
  .catch(error => {
    console.error('Error:', error);
  });
</script>
```

The Geocodio API supports `CORS` using the `Access-Control-Allow-Origin` *HTTP* header.

This means that you will be able to make requests directly to the API using JavaScript in the browser.

(See an example to the right.)

> **Note:** **Note:** This will expose your API Key publicly, make sure that you understand and accept the implications of this approach, and consider setting [usage limits](https://dash.geocod.io/billing#limits) on your account if applicable.

# Google Maps Compatibility

Geocodio provides a Google Maps-compatible geocoding endpoint, enabling you to migrate from Google Maps with minimal code changes. Simply point your existing Google Maps SDK to `https://api.geocod.io` and use your Geocodio API key.

The examples to the right show how to configure the official Google Maps SDKs for Python and Node.js to use Geocodio's endpoint. The compatibility layer returns responses in Google Maps' format, so your existing response parsing code continues to work unchanged.

For new integrations or to access Geocodio's full feature set (like data appends and batch geocoding), we recommend using the [native Geocodio API](#geocoding).

> Using Google Maps SDKs with Geocodio:

```shell
# Direct API call
curl "https://api.geocod.io/maps/api/geocode/json?address=1109+N+Highland+St,+Arlington+VA&key=YOUR_API_KEY"

# Reverse geocoding
curl "https://api.geocod.io/maps/api/geocode/json?latlng=38.886665,-77.094733&key=YOUR_API_KEY"
```

```python
# Install: pip install googlemaps
import googlemaps

# Configure client to use Geocodio endpoint
gmaps = googlemaps.Client(
    key='YOUR_GEOCODIO_API_KEY',
    base_url='https://api.geocod.io'
)

# Forward geocoding - same code as Google Maps!
geocode_result = gmaps.geocode('1109 N Highland St, Arlington VA')
location = geocode_result[0]['geometry']['location']
print(f"Lat: {location['lat']}, Lng: {location['lng']}")

# Reverse geocoding - same code as Google Maps!
reverse_result = gmaps.reverse_geocode((38.886665, -77.094733))
print(reverse_result[0]['formatted_address'])
```

```javascript
// Install: npm install @googlemaps/google-maps-services-js
const { Client } = require("@googlemaps/google-maps-services-js");

const client = new Client({});

// Forward geocoding - add 'url' parameter to use Geocodio
client.geocode({
  params: {
    address: "1109 N Highland St, Arlington VA",
    key: "YOUR_GEOCODIO_API_KEY"
  },
  url: "https://api.geocod.io/maps/api/geocode/json"
})
.then(response => {
  const location = response.data.results[0].geometry.location;
  console.log(`Lat: ${location.lat}, Lng: ${location.lng}`);
});

// Reverse geocoding - add 'url' parameter to use Geocodio
client.reverseGeocode({
  params: {
    latlng: "38.886665,-77.094733",
    key: "YOUR_GEOCODIO_API_KEY"
  },
  url: "https://api.geocod.io/maps/api/geocode/json"
})
.then(response => {
  console.log(response.data.results[0].formatted_address);
});
```

### HTTP Request

`GET https://api.geocod.io/maps/api/geocode/json`

### URL Parameters

Parameter | Description | Required
--------- | ----------- | --------
`address` | The address to geocode (for forward geocoding) | Either `address` or `latlng`
`latlng` | Coordinates in `lat,lng` format (for reverse geocoding) | Either `address` or `latlng`
`key` | Your Geocodio API key | Yes
`components` | Address component filters (e.g., `country:US`) | No

## What's Supported

**Request Parameters:**

* ✅ `address` - Forward geocoding
* ✅ `latlng` - Reverse geocoding
* ✅ `key` - API authentication
* ✅ `components` - Address component filtering (see below for details)

**Address Components:**

The endpoint transforms Geocodio's address components into Google Maps format with these component types:

* `street_number` - House/building number
* `route` - Street name (includes predirectional, prefix, street, suffix, postdirectional)
* `locality` - City name
* `administrative_area_level_2` - County
* `administrative_area_level_1` - State/province (with full name expansion, e.g., VA → Virginia, ON → Ontario)
* `country` - Country code and full name
* `postal_code` - ZIP/postal code

**Component Filtering:**

The `components` parameter supports filtering results:

* `country:XX` - Filter by country code (US, CA, MX)
* `postal_code:XXXXX` - Filter by postal code
* `locality:CityName` - Filter by city/locality
* `administrative_area:State` - Filter by state/province
* `route:StreetName` - Filter by street name
* Multiple filters can be combined: `components=country:US|postal_code:22201`

**Supported Countries:**

* 🇺🇸 United States (US)
* 🇨🇦 Canada (CA) - with proper province expansion (e.g., ON → Ontario, QC → Quebec)
* 🇲🇽 Mexico (MX)

**Response Format:**

* ✅ `address_components` - Typed address component arrays with proper component types
* ✅ `formatted_address` - Full formatted address string
* ✅ `geometry.location` - Latitude and longitude coordinates
* ✅ `geometry.location_type` - Accuracy indicator (ROOFTOP, RANGE_INTERPOLATED, GEOMETRIC_CENTER, APPROXIMATE)
* ✅ `geometry.viewport` - Bounding box for the result
* ✅ `types` - Result type indicators
* ✅ `status` - Response status (OK, ZERO_RESULTS, REQUEST_DENIED, etc.)
* ✅ `place_id` - Geocodio [stable address key](#stable-address-key) for each result
* ✅ `partial_match` - Added when accuracy < 1.0

**Additional Features:**

* **State/Province Expansion** - Short codes expanded to full names (VA → Virginia, ON → Ontario, QC → Quebec)
* **Street Components** - Properly combines predirectional (N, S, E, W), street name, suffix (St, Ave), and postdirectional (NW, SE)
* **Location Type Mapping** - Maps Geocodio accuracy to Google's location types (ROOFTOP, RANGE_INTERPOLATED, GEOMETRIC_CENTER, APPROXIMATE)
* **Partial Match Indicator** - Automatically adds `partial_match: true` flag when accuracy is less than 1.0

## What's Different

**Differences in Responses:**

* ✅ `place_id` - Returns the Geocodio [stable address key](#stable-address-key) for each result (e.g., `gcod_usnbfvbm5l57cc8b8bnfnyrua9ym3`). Note: these are Geocodio identifiers, not Google Place IDs
* ❌ `plus_code` - Google Plus Codes are not provided
* ⚠️ `geometry.viewport` - Provided but approximated (not based on actual address boundaries)

**Parameter Limitations:**

* ❌ `bounds` - Viewport biasing not supported (parameter ignored if provided)
* ❌ `region` - Region biasing not supported (parameter ignored if provided)
* ⚠️ `components` - Supports `country`, `postal_code`, `locality`, `administrative_area`, and `route` filtering (other component types are not supported)

**Coverage:**

* ⚠️ **US, Canada, and Mexico only** - Geocodio currently supports US, Canadian, and Mexican addresses. Requests for other countries will return `ZERO_RESULTS` status

**Error Responses:**

All responses return HTTP 200 with status information in the response body (matching Google's behavior). Possible status values include:

* `OK` - Request successful
* `ZERO_RESULTS` - No results found
* `REQUEST_DENIED` - Invalid API key
* `INVALID_REQUEST` - Missing or invalid parameters
* `OVER_QUERY_LIMIT` - Rate limit exceeded

> **Note:** For new integrations, we recommend using the [native Geocodio API](#geocoding) for access to advanced features like data appends, batch geocoding, and more detailed address parsing.

> **Warning:** This endpoint supports US, Canada, Mexico, and UK addresses. Requests for addresses in other countries will return a `ZERO_RESULTS` status.
>
> UK addresses require a plan that includes UK access and a signed UK Terms of Service attachment, exactly as they do on the native geocoding endpoints. A UK request from an account without UK access returns `INVALID_REQUEST` with the reason in `error_message` &mdash; not `ZERO_RESULTS`, and still with an HTTP 200 response code.

# Migrating to API v2

API v2 changes a few response field names, removes the top-level `input` object, and adds `state_province` as the state/province input parameter. For most integrations the update is a short find-and-replace. This guide lists every change with before-and-after examples so you can migrate quickly.

**What changed:**

* Base URL prefix is now `v2`, e.g. `https://api.geocod.io/v2/`
* The top-level `input` object is gone. Read parsed components from `results[].address_components`
* Several `address_components` keys have new names (listed below)
* Component input uses `state_province` for the state/province field
* Canadian results echo a full postal code you supply when its FSA matches the result

> **Note:** Nothing changes for your integration until you switch the version prefix in your request URLs to `v2`. v1.12 and earlier stay available for as long as you need.

## Upgrade with an AI assistant

Use the button below to copy a ready-made prompt for your AI coding assistant (such as Claude, Cursor, or GitHub Copilot). Paste it in along with your geocoding code, and the assistant will make the changes for you. It handles both direct API calls and the official client libraries.

```
Upgrade my code from the Geocodio API v1.x to v2. Apply only the changes below, and only to code that calls the Geocodio API or reads Geocodio responses. Do not rename unrelated variables that happen to be called "state" or "zip".
What changed in Geocodio v2:
1. Base URL: the version prefix changed from v1.x (for example v1.12) to v2, so requests now go to https://api.geocod.io/v2/...
2. The top-level "input" object was removed from /geocode and /reverse responses. The parsed address is in each result under "address_components" (results[].address_components).
3. Keys renamed in the response, inside "address_components" and "address_components_secondary":
   - zip -> postal_code
   - state -> state_province
   - secondaryunit -> unit_type
   - secondarynumber -> unit_number
4. When sending address components as input parameters, the state/province field is now "state_province" (the old "state" still works, so this is optional). The postal code input parameter remains "postal_code".
What to do:
- If I use an official Geocodio client library, update it to the latest version and set the API version to "2" if the library lets me choose a version.
- If I build the HTTP requests myself, change the URL version prefix to v2.
- Update code that reads responses: stop using the "input" object and read parsed components from results[].address_components, and rename the keys listed above wherever they are read from a Geocodio response.
- Leave field appends (the "fields" parameter) and all other parameters unchanged.
When you are done, show me a summary of every file and line you changed.
```

Prefer to make the changes yourself? The sections below walk through each one.

## Update the base URL

Change the version prefix in your request URLs from `v1.12` (or earlier) to `v2`:

`https://api.geocod.io/v2/geocode?q=...`

## Read the parsed address from `results`

Earlier versions repeated your parsed query in a top-level `input` object. v2 removes it. The parsed address is in each result under `address_components`, so if you read from `input` today, switch to `results[].address_components`.

> Before (v1.12):

```json
{
  "input": {
    "address_components": { "...": "..." },
    "formatted_address": "1109 N Highland St, Arlington, VA 22201"
  },
  "results": [ "..." ]
}
```

> After (v2):

```json
{
  "results": [ "..." ]
}
```

## Renamed `address_components` keys

These keys in `address_components` and `address_components_secondary` have new names in v2. The renames apply everywhere address components appear, including `/geocode`, `/reverse`, `/distance`, and `/lists`.

Old key (v1.12)   | New key (v2)
----------------- | ------------
`zip`             | `postal_code`
`state`           | `state_province`
`secondaryunit`   | `unit_type`
`secondarynumber` | `unit_number`

> Before (v1.12):

```json
{
  "state": "VA",
  "zip": "22201",
  "secondaryunit": "Ste",
  "secondarynumber": "R500"
}
```

> After (v2):

```json
{
  "state_province": "VA",
  "postal_code": "22201",
  "unit_type": "Ste",
  "unit_number": "R500"
}
```

> **Note:** When supplying an address as individual components, v2 uses the same vocabulary as the response: `state_province` and `postal_code` (see [Accepted Address Components](#accepted-address-components)). The legacy `state` parameter is still accepted as an alias, so existing integrations keep working.

## Canadian full postal codes

Geocodio is not permitted to redistribute full Canadian postal codes (a licensing restriction imposed by Canada Post), so geocoded Canadian results return only the 3-character FSA (Forward Sortation Area).

As an exception, if you supply a full postal code in your request and its FSA (the first 3 characters) matches the FSA of the geocoded result, v2 echoes your own postal code back in `postal_code`, exactly as you provided it. This is your own input being returned to you rather than licensed data being redistributed. The `source` field notes when a postal code came from your input.

If the supplied postal code's FSA does not match the geocoded result, only the FSA is returned.

## Spreadsheet (lists) output

The downloaded spreadsheet columns follow the same renamed vocabulary in v2 (for example "State / Province", "Postal Code", "Unit Type", and "Unit Number").

# Integrations

Geocodio integrations bring geocoding and data enrichment directly into the tools you already use.

## Snowflake

> Forward geocode an address from SQL:

```sql
SELECT geocodio.v1.geocode('1600 Pennsylvania Ave NW, Washington DC 20500') AS result;
```

Geocode addresses and enrich location data directly in your Snowflake warehouse, using the Geocodio API. No CSV exports, no pipelines, and no data leaving your account for anywhere other than the Geocodio API. You write SQL, and coordinates and location data come back as standard Snowflake results you can store wherever you like.

This section covers how to install the app, set it up, and use every function it provides.

Geocodio for Snowflake is a Native App that calls the Geocodio API from SQL. You bring your own Geocodio API key, and the app gives you functions you can drop into any query:

- **Forward geocoding**: turn a street address into latitude and longitude, with address correction, parsing, and completion. Stable address keys are included for free for easy de-duping.
- **Component geocoding**: build a query from structured address parts (street, city, state, postal code).
- **Reverse geocoding**: turn coordinates back into an address.
- **Data enrichment**: every function can also request Geocodio [field appends](#data-appends-fields), such as Congressional districts, timezones, and Census data, so a single query returns coordinates and the extra location context you need.
- **Driving distance**: calculate driving distance, driving time, and distance radii.

Results come back as standard Snowflake data, so you control where they go: create a new table, update rows in place, or filter to only the addresses that still need coordinates.

The app is free to install. You pay only for Geocodio API usage on your own Geocodio account, at your existing Geocodio rate. Geocodio lets you store geocoded results, with no per-record storage fees.

### Prerequisites

- A Snowflake account, with a role that can install a Native App and grant it privileges (an `ACCOUNTADMIN` role, or a role with the equivalent grants).
- A Geocodio API key. You can create one for free at [dash.geocod.io](https://dash.geocod.io).
- A warehouse to run your queries.

### Install and set up

> Activate the app after saving your API key:

```sql
CALL geocodio.config.activate();
```

After you install the app from the Snowflake Marketplace, there are four one-time setup steps. Each takes a few seconds.

1. **Grant the external access privilege.** When you install the app, Snowflake asks you to grant it the `CREATE EXTERNAL ACCESS INTEGRATION` privilege. This lets the app create the secure connection it uses to reach `api.geocod.io`. Grant it on the install screen.
2. **Open the app and approve the external access integration.** Click **Open** to open the app in Snowsight, review the external access integration, and click **Save**.
3. **Add your Geocodio API key.** Go to the **Configurations** tab and enter your key in the **Geocodio API Key** field. The key is stored as a sensitive configuration, so it never appears in query history or in `SHOW CONFIGURATIONS`. Only the app can read it.
4. **Activate the app.** Run `CALL geocodio.config.activate();` once. It reads your key and creates the geocoding functions.

> **Note:** If you ever change your API key, update it in the Configurations tab and run `activate()` again.

### The result format
Geocoding is exposed as functions you call inline in SQL. Run them over a whole table by selecting from it: they batch automatically, so a large table stays efficient. You decide where the results go.

The geocoding functions return a `VARIANT` with these top-level keys:

- `formatted_address`: the standardized address string
- `lat`: latitude
- `lng`: longitude
- `accuracy`: a score from 0 to 1
- `accuracy_type`: how the match was made (for example, `rooftop`)
- `source`: the data source for the match

When you request field appends, the result also includes a `fields` object with the data you asked for. Pull any value out with Snowflake's colon notation, for example `result:lat::float`.

### `geocode(address [, country] [, options])`

> Forward geocode a free-form address string:

```sql
SELECT geocodio.v1.geocode('1600 Pennsylvania Ave NW, Washington DC 20500') AS result;
```

> Pull latitude and longitude into their own columns:

```sql
SELECT
  g:formatted_address::string AS matched_address,
  g:lat::float                AS latitude,
  g:lng::float                AS longitude,
  g:accuracy::float           AS accuracy
FROM (
  SELECT geocodio.v1.geocode('1600 Pennsylvania Ave NW, Washington DC 20500') AS g
);
```

Forward geocode a free-form address string.

### `geocode_components(components OBJECT [, options])`

> Geocode from structured address parts:

```sql
SELECT geocodio.v1.geocode_components(
  OBJECT_CONSTRUCT(
    'street', '1600 Pennsylvania Ave NW',
    'city', 'Washington',
    'state', 'DC',
    'postal_code', '20500'
  )
) AS result;
```

Geocode from structured address parts instead of a single string. Useful when your data already has separate columns for street, city, state, and postal code.

### `reverse_geocode(lat, lng [, options])`

> Turn coordinates back into an address:

```sql
SELECT
  geocodio.v1.reverse_geocode(38.897675, -77.036547):formatted_address::string
    AS address;
```

Turn coordinates back into an address.

### Options: field appends, limit, and country

> Request Congressional district and timezone appends:

```sql
SELECT geocodio.v1.geocode(
  '1600 Pennsylvania Ave NW, Washington DC',
  OBJECT_CONSTRUCT('fields', ARRAY_CONSTRUCT('cd', 'timezone'), 'limit', 1)
):fields AS appended_fields;
```

> To set a country, pass it as the second argument, with options third:

```sql
SELECT geocodio.v1.geocode(
  address,
  'US',
  OBJECT_CONSTRUCT('fields', ARRAY_CONSTRUCT('census'))
)
FROM my_addresses;
```

The geocoding functions accept an options object as their last argument, built with `OBJECT_CONSTRUCT`. It supports these keys:

| Key | Type | Description |
|---|---|---|
| `fields` | array | Field appends to include in the result, such as `cd` (Congressional districts), `timezone`, and `census`. Any Geocodio append is accepted, see [Fields](#data-appends-fields) for the full list. |
| `limit` | integer | The maximum number of results to return. |

Country is not an options key. It is its own positional argument: pass it as the second argument to `geocode()`, with options third. If you skip country, options can be the second argument.

The `distance()` function takes a different set of options, listed in its section below.

### `distance(origin, destinations [, options])`

> Driving distance from an address to two destinations:

```sql
SELECT geocodio.v1.distance(
  '1600 Pennsylvania Ave NW, Washington DC 20500',
  ARRAY_CONSTRUCT('38.9072,-77.0369,Downtown', '38.8462,-77.3064,Fairfax'),
  OBJECT_CONSTRUCT('mode', 'driving')
) AS result;
```

> Coordinate overload, for tables that already have latitude and longitude columns:

```sql
SELECT geocodio.v1.distance(
  lat,
  lng,
  ARRAY_CONSTRUCT('1600 Pennsylvania Ave NW, Washington DC 20500'),
  OBJECT_CONSTRUCT('mode', 'driving', 'units', 'km')
)
FROM my_locations;
```

Calculate driving or straight line distance from each row's origin to a list of destinations, using Geocodio's [distance matrix endpoint](#distance-matrix). A coordinate overload, `distance(lat, lng, destinations [, options])`, matches the shape of `reverse_geocode()` so you do not have to concatenate coordinate columns into a string.

Origins and destinations accept any Distance API location format: `'lat,lng[,id]'` strings, address strings, or coordinate objects such as `OBJECT_CONSTRUCT('lat', 38.9, 'lng', -77.03, 'id', 'HQ')`. Addresses are geocoded automatically and billed as geocode lookups.

The result is a `VARIANT` with an `origin` object and a `destinations` array. Each destination entry includes `distance_miles`, `distance_km`, and, in driving mode, `duration_seconds`. See the [distance matrix endpoint](#distance-matrix) for the full response format.

The options object supports the Distance API parameters:

| Key | Description |
|---|---|
| `mode` | `driving` or `straightline`. Default is `straightline`. |
| `units` | `miles` or `km`. Default is `miles`. |
| `max_results` | Maximum number of destinations to return per origin. |
| `max_distance` / `min_distance` | Distance filters, in the specified units. |
| `max_duration` / `min_duration` | Duration filters in seconds (driving mode only). |
| `order_by` | Sort destinations by `distance` or `duration`. Default is `distance`. |
| `sort_order` | `asc` or `desc`. Default is `asc`. |

Like the geocoding functions, `distance()` batches automatically: rows that share the same destinations and options are sent to the distance matrix endpoint as a single request, with the rows as the origins. The matrix endpoint caps each request at 10,000 calculations (origins × destinations), and the app splits requests as needed to stay under it.

### Example workflow: geocode a whole table

> 1. Make a sample table of addresses:

```sql
CREATE OR REPLACE TABLE customers (id INT, name STRING, address STRING);

INSERT INTO customers (id, name, address) VALUES
  (1, 'White House',      '1600 Pennsylvania Ave NW, Washington DC 20500'),
  (2, 'Empire State',     '350 5th Ave, New York NY 10118'),
  (3, 'Space Needle',     '400 Broad St, Seattle WA 98109'),
  (4, 'Willis Tower',     '233 S Wacker Dr, Chicago IL 60606'),
  (5, 'Golden Gate Park', '501 Stanyan St, San Francisco CA 94117');
```

> 2. Geocode the whole table into a new one with latitude and longitude columns:

```sql
CREATE OR REPLACE TABLE customers_geocoded AS
WITH geocoded AS (
  SELECT c.*, geocodio.v1.geocode(c.address) AS g
  FROM customers c
)
SELECT
  * EXCLUDE (g),
  g:lat::float                AS latitude,
  g:lng::float                AS longitude,
  g:formatted_address::string AS matched_address,
  g:accuracy::float           AS accuracy
FROM geocoded;
```

> To geocode in place, filling in only the rows where latitude is NULL:

```sql
UPDATE customers_geocoded AS t
  SET latitude        = s.g:lat::float,
      longitude       = s.g:lng::float,
      matched_address = s.g:formatted_address::string,
      accuracy        = s.g:accuracy::float
  FROM (
    SELECT id, geocodio.v1.geocode(address) AS g
    FROM customers_geocoded
    WHERE latitude IS NULL
  ) AS s
  WHERE t.id = s.id;
```

A common task is geocoding a table of addresses into a new table with latitude and longitude columns. Because `geocode()` batches automatically, you can geocode the whole table with a single select.

If some rows are already geocoded, you can update the table in place instead. The `UPDATE` example only sends rows where `latitude` is `NULL` to the API, so you never pay to geocode the same address twice.

### How batching works

Geocodio for Snowflake is built for bulk. When you run a geocode function over a table, it does not make one API call per row. It batches automatically, in two layers.

First, Snowflake hands the function up to 1,000 rows at a time as a single group, rather than calling it once per row. A table of 2,500 addresses arrives in three groups (1,000, 1,000, and 500).

Second, within each group, the app sends the addresses that share the same country and options to Geocodio's batch endpoint in a single request. Geocodio returns the results in order, and the app matches each result back to its original row.

The result: geocoding a table of 800 addresses that share the same options becomes one batch request to Geocodio, not 800 separate calls. This keeps large jobs fast and makes efficient use of your Geocodio rate limits.

If a single query mixes options, for example some rows set a country and others do not, the app groups the rows accordingly and sends one batch request per group. You do not need to sort or split your data. The batching happens for you.

### Good to know

- **You own your results.** Geocoded data is standard Snowflake data in your account. Geocodio lets you store it, with no per-record storage fees.
- **Your data goes only to Geocodio.** Addresses are sent to `api.geocod.io` and nowhere else. There is no third-party gateway in between.
- **Built for bulk.** The functions send rows to Geocodio's batch endpoint, grouping rows that share the same country and options into a single request.
- **Billing.** The app is free. Geocoding usage is billed to your Geocodio account at your normal rate. See [geocod.io/pricing](https://www.geocod.io/pricing/).
- **Field appends.** For the full list of fields you can request, see [Fields](#data-appends-fields).

Questions or trouble? Email [support@geocod.io](mailto:support@geocod.io).

# Changelog

The Geocodio API is continuously improved. Most updates require no changes for API users, but in some cases we might have to introduce breaking changes.

Breaking changes are introduced with new API versions, allowing you to "upgrade" to the newest version at your own pace. Older API versions are guaranteed to be available for at least 12 months after they have been replaced by a newer version, but may be supported for longer.

Major changes, that are not breaking are also documented here.

> **Note:** Breaking changes are defined as changes that remove or rename properties in the JSON output of any API endpoint. Your API client should be able to gracefully support addition of new JSON properties, as this is not considered a breaking change.

## v2

*Released on August 27, 2026*

* [`stateleg-next`](#state-legislative-districts): Michigan Senate districts now return the remedial map that the Michigan Independent Citizens Redistricting Commission adopted in 2024, following the federal court decision in *Agee v. Benson*. The redrawn districts cover Metro Detroit. They will be promoted to [`stateleg`](#state-legislative-districts) on January 1, 2027, when senators elected under the new map take office. Until then, `stateleg` continues to return the current districts. Michigan House districts were already updated and are unchanged
* The [Census ACS](#geographies) field appends support four new geographies: `zcta` (ZIP Code Tabulation Area), `division`, `region` and `nation`. They are available on all five ACS categories, e.g. `acs-demographics-zcta`, `acs-economics-division`, `acs-families-region`, `acs-housing-nation`, `acs-social-zcta`. These geographies are only returned when requested explicitly and are never selected automatically. Note that not every USPS ZIP code has a matching ZCTA — when one does not exist, the `acs` field is omitted from the response and a warning is returned (see [ZIP Code Tabulation Areas vs. ZIP codes](#zip-code-tabulation-areas-vs-zip-codes)). The new field values are available for all API versions, so no changes are required on your end

*Released on July 21, 2026*

* Updated [`ffiec`](#ffiec-fair-lending) field append to 2026 FFIEC data release (using 2025 Census geographies). This includes updated MSA/MD median family incomes, income level designations, and CRA distressed/underserved tract criteria. The updated data is returned for all API versions, so no changes are required on your end

*Released on July 13, 2026*

* The [`ffiec`](#ffiec-fair-lending) field append now returns `tract_minority_population_percentage`, the minority population as a percentage of the tract population. Island Area tracts without demographic data return `null`

*Released on June 11, 2026*

* United Kingdom geocoding has been released, adding forward geocoding, reverse geocoding, and distance calculations for Great Britain and Northern Ireland (see [Supported Countries](#supported-countries)). New UK field appends return political districts at three levels — [`uk-westminster`, `uk-devolved`, and `uk-local`](#united-kingdom-political-districts)

*Released on June 5, 2026*

API v2 brings a few naming updates that make responses clearer and more consistent across countries. The [migration guide](#migrating-to-api-v2) walks through each one with before-and-after examples. v1.12 and earlier keep working, so you can upgrade whenever it suits you.

* **Breaking:** The base URL is now `https://api.geocod.io/v2/`
* **Breaking:** The top-level `input` object has been removed from `/geocode` and `/reverse` responses. The parsed address is available in each result's `address_components`
* **Breaking:** Several [`address_components`](#address-components) keys have been renamed for clarity and international consistency. This applies to `address_components` and `address_components_secondary` across all endpoints:
    * `zip` is now `postal_code`
    * `state` is now `state_province`
    * `secondaryunit` is now `unit_type`
    * `secondarynumber` is now `unit_number`
* When you supply a full Canadian postal code whose FSA matches the geocoded result, it is now echoed back in `postal_code` exactly as provided. Canadian results otherwise continue to return only the 3-character FSA (full postal codes cannot be redistributed under Canada Post licensing). The `source` field notes when a postal code was provided by the user

## v1.12

*Released on June 1, 2026*

* [`cd120`](#congressional-districts): Updated with redistricted boundaries for Alabama, Florida, and Tennessee

*Released on March 24, 2026*

* **Breaking:** Mexican addresses are now formatted as `<street> <house number>`, matching the correct local convention. Previous API versions returned the house number before the street name

## v1.11

*Released on March 11, 2026*

* [Secondary address line geocoding](#secondary-address-line-geocoding) is now supported at the unit level. When a secondary address component is provided (e.g. apartment, suite, or unit number), Geocodio will attempt to return unit-specific coordinates. Different units at the same street address may now return different coordinates
* All geocoding results now include a [`match_type`](#match-type) field that indicates the coordinate match granularity. Possible values are `building_centroid`, `parcel_centroid`, `unit`, and `null`
* **Breaking:** [Stable address keys](#stable-address-keys) now include a unit suffix for addresses with secondary address components (e.g. `gcod_usnbfvbm5l57cc8b8bnfnyrua9ym3-a1b2c3`). The full key with unit suffix can be used as input for geocoding and distance calculations

## v1.10

*Released on March 11, 2026*

* Added forward geocoding support for Mexico
* Updated [`ffiec`](#ffiec-fair-lending) field append to 2025 FFIEC data release (using 2024 Census geographies)

*Released on March 2, 2026*

* Added [`skipGeocoding`](#skip-geocoding-extracting-field-data-from-coordinates) parameter for reverse geocoding endpoints. This allows applying field appends directly to coordinates without performing a geocoding lookup, so only field append lookups are billed

*Released on February 24, 2026*

* **Breaking:** ACS 2024 data is now returned for all [Census ACS appends](#census-acs-american-community-survey). ACS 2024 uses 2023 Census boundaries (the `census2023` data append). Changes include:
  * The [`acs-social`](#social-education-veteran-status-census) field append has renamed row labels in Table #B21002 (Period of military service for veterans): "Vietnam Era" has been changed to "Vietnam War"
  * No other ACS field appends have breaking table changes
* [`cd120`](#congressional-districts): Updated with redistricted boundaries for California, Missouri, North Carolina, Ohio, and Utah
* All geocoding results now include a [stable address key](#stable-address-keys) (`stable_address_key`) that uniquely identifies an address. Stable address keys can be used as input in any API endpoint and enable free field appends on already-geocoded addresses

## v1.9

*Released on January 6, 2026*

* Added new [Distance](#distance) endpoints for calculating distances and travel times between locations
  * New `/distance` endpoint for single origin to multiple destinations
  * New `/distance-matrix` endpoint for multiple origins to multiple destinations (up to 10,000 calculations)
  * New `/distance-jobs` endpoints for asynchronous large-scale distance calculations (up to 50,000 calculations)
  * Distance calculations can also be added to geocoding results via the `destinations[]` parameter on `/geocode` and `/reverse` endpoints

*Released on December 16, 2025*

* The [`census2025`](#census-blocktract-fips-codes-msacsa-codes) field append is now available (the `census` data append will now default to `census2025`)

*Released on November 19, 2025*

* Added [Google Maps API compatibility endpoint](#google-maps-compatibility) at `/maps/api/geocode/json`. This allows developers to migrate from Google Maps by using existing Google Maps SDKs with Geocodio by simply changing the endpoint and API key

*Released on November 18, 2025*

* The [`cd120`](#congressional-districts) field has been added for the 120th Congress. It remains in preview until finalized. cd119 continues to be the default.

*Released on June 17, 2025*

* **Breaking:** We've done a bit of "spring" cleaning to better standardize state legislative district names and numbers. The changes does not apply to API version below v1.9 and OCD ids are not affected. To compare the differences, you can compare the following URLs: [https://api.geocod.io/v1.8/ocd-ids/stateleg](https://api.geocod.io/v1.8/ocd-ids/stateleg) and [https://api.geocod.io/v1.9/ocd-ids/stateleg](https://api.geocod.io/v1.9/ocd-ids/stateleg)
* The lists API endpoint now includes the updated header names recently introduced to the spreadsheet geocoding tool as well as state legislator data

## v1.8

*Released on June 6, 2025*

* The [state legislative districts](#state-legislative-districts) field append now return the current legislators for the district
* The [congressional districts](#congressional-districts) field append now return a `photo_url` along with each legislator

*Released on June 2, 2025*

* Updated [state legislative districts](#state-legislative-districts) for North Dakota

*Released on May 16, 2025*

* **Breaking:** 2023 data is now returned for all [Census ACS appends](/#census-acs-american-community-survey). Changes include:
  * 2023 Census boundaries and ACS data are returned instead of 2021
  * The [`acs-families`](#census-households) field append has certain table titles renamed ("wife" or "husband" replaced with "spouse") &mdash; no other ACS field appends has renamed tables
  * Support for additional Census Geographies (prior to v1.8 all ACS data was returned at the Census Block Group level). The geography is now automatically selected based on the `accuracy_type` of the result and [can be explicitly specified](/#census-acs-american-community-survey)
* ACS Table #B19301 was added for the [`acs-economics`](#census-income) field append
* ACS Tables #B11003, #B25010, and #B09002 were added for the [`acs-families`](#census-households) field append

  There are no other breaking changes for *v1.8*.

## v1.7

*Released on May 6, 2025*

* Added [`address_lines`](#single-address) along with each geocoding result.

*Released on March 25, 2025*

* Added new [`ffiec`](#ffiec-fair-lending) field append

*Released on March 24, 2025*

* The Canadian elections have been called! [`riding`](#riding-canadian-federal-electoral-district) is now returning the new, redistricted ridings. `riding-next` continues to return the redistricted ridings as well, but is otherwise no longer in use.

*Released on March 10, 2025*

* Added the ability to use the `Authorization` header for [API authentication](#authentication)
* [List geocoding](#geocoding-lists) is now available for Geocodio Enterprise

*Released on February 27, 2025*

* The `current_legislators` data for the `cd` field append now return sorted legislators. The representative is always returned first, senators are then returned sorted by seniority. In addition, a new `seniority` key can be used to determine if a senator is `senior` or `junior`. The value is `null` for representatives.

*Released on January 17, 2025*

* Added support for `street2` and `county` as input address components. Available for both [single geocoding](#single-address) and [batch geocoding](#batch-geocoding)

*Released on January 9, 2025*

* The [`census2024`](#census-blocktract-fips-codes-msacsa-codes) field append is now available (the `census` data append will now default to `census2024`)
* The senate districts for California has been updated with new post-election boundaries

*Released on December 16, 2024*

* The [`cd119`](#congressional-districts) field append has been added, for the 119th congress. This will be the new default congressional district append, starting on January 3rd, 2025

*Released on November 4, 2024*

* The [`zip4`](#usps-zip-4) field append now returns a residential delivery indicator (RDI) with the new `residential` property

*Released on September 27, 2024*

* The `provriding-next` data append is now available. Upcoming provincial ridings for Saskatchewan can be previewed. The `provriding` will be returning these new ridings as of 10/28/2024

*Released on September 20, 2024*

* `provriding`: New district boundaries are now used for British Columbia

*Released on April 29, 2024*

* `stateleg-next`: Upcoming districts boundaries were added for Minnesota House & Senate districts, they will be promoted to `stateleg` on 1/14 2025

*Released on April 24, 2024*

* Added Census County Subdivisions to the [`census`](#census-blocktract-fips-codes-msacsa-codes) field append

*Released on April 16, 2024*

* `cd118`: District boundaries were updated for North Carolina, Louisana and New York
* `stateleg`: Wisconsins and Michigan House district boundaries were updated. New Mexico Senate district boundaries were updated.
* `stateleg-next`: Upcoming districts boundaries were added as follows:
  * New York Assembly districts, will be promoted to `stateleg` on 1/1 2025
  * Ohio House & Senate districts, will be promoted to `stateleg` on 1/1 2025
  * Washington House & Senate districts, will be promoted to `stateleg` on 8/6 2024

*Released on April 8, 2024*

* Introduced the [`riding-next`](#riding-canadian-federal-electoral-district) which allows federal electoral district lookups in Canada, based on redistricting ridings

*Released on January 18, 2024*

* Introduced `census2023` data append (the `census` data append will now default to `census2023`)
* Corrected an issue where census field appends always returned county FIPS codes for most recent census year. This primarily affects census county lookups in Connecticut as this state [switched to a new county-equivalent system](https://www.census.gov/programs-surveys/acs/technical-documentation/user-notes/2023-01.html) as of the 2022 census release.

*Released on November 8, 2023*

* Updated state legislative districts for North Carolina

*Released on August 14, 2023*

* Corrected an issue that caused batch geocoding requests to only return results from the first country when addresses from mixed countries were present in a single batch. The original issue was inadvertently introduced on July 24th.

*Released on April 26, 2023*

* Added upcoming redistricted boundaries for Montana with the `stateleg-next` data append
* Corrected boundaries current senate state legislative districts for California. Districts with odd numbers were incorrectly using upcoming boundaries. Geocodio is now applying special logic required due to partial redistricting. You can read more [here](https://sdmg.senate.ca.gov/Current).
* Updated Statistics Canada data to latest 2021 census release. The following additional values has been added as well:
  * Designated place
  * Population centre
  * Dissemination area
  * Dissemination block

*Released on March 14, 2023*

* Updated Alaska state legislative district boundaries

*Released on February 7, 2023*

* Corrected version of state legislative districts returned for:
  * NM State Senate. New districts will be returned when the next session commences 1/21/2025
  * KS State Senate. New districts will be returned when the next session commences 1/15/2025
  * SC State Senate. New districts will be returned when the next session commences 1/7/2025
* Redistricted state boundaries can still be requested early by using the `stateleg-next` data append

*Released on February 1, 2023*

* ~~Corrected version of state legislative districts returned for New Mexico Senate. New districts will be returned when the next session commences 1/21/2025, or using the `stateleg-next` data append.~~ *(This was rolled back and postponed to February 7th)*
* Corrected the following Massachusetts state legislative district OCD ids:
  * Changed "ocd-division/country:us/state:ma/sldu:berkshire_hampshire_franklin_and_hampden" to "ocd-division/country:us/state:ma/sldu:berkshire_hampden_franklin_and_hampshire"
  * Changed "ocd-division/country:us/state:ma/sldu:1st_hampden_and_hampshire" to "ocd-division/country:us/state:ma/sldu:hampden_and_hampshire"
  * Changed "ocd-division/country:us/state:ma/sldu:1st_middlesex_and_norfolk" to "ocd-division/country:us/state:ma/sldu:middlesex_and_norfolk"
  * Changed "ocd-division/country:us/state:ma/sldu:norfolk_bristol_and_plymouth" to "ocd-division/country:us/state:ma/sldu:norfolk_plymouth_and_bristol"

*Released on January 23, 2023*

* Updated congressional district and state legislative district boundaries for Wisconsin
* Corrected an issue where 4th Middlesex and 5th Middlesex in Massachusetts was returning an incorrect OCD id

*Released on January 17, 2023*

* Census ACS data has been updated to the latest release (2021 ACS data)
* The `ocd_id` value is now set for all `stateleg` district result (previously, it was `null` for pre-redistricting districts)

*Released on January 11, 2023*

* Introduced `census2022` data append (the `census` data append will now default to `census2022`)
* `stateleg` data append now returns redistricted boundaries for all states except MS, NJ, LA, MT and VA. For these states, use `stateleg-next` to get redistricted data instead

*Released on May 19, 2022*

* The `stateleg-next` and `cd118` field appends now return OCD identifiers

*Released on March 7, 2022*

* When using the `stateleg-next` data append, the `is_upcoming_state_legislative_district` property will now return `false` in cases where the state's data has not been updated yet

*Released on February 11, 2022*

* Added the new `provriding` field append for provincial/territorial legislative districts in Canada

*Released on February 10, 2022*

* The `cd118` and `stateleg-next` data appends has been updated with the addition of updated districts for California, Massachusetts and Virginia

*Released on January 17, 2022*

* Introduced `census2021` data append (the `census` data append will now default to `census2021`)

*Released on January 13, 2022*

* Introduced `census2000` data append for 2000 vintage census boundaries
* Updated `cd118` and `stateleg-next` data appends with data for additional redistricted states

*Released on November 12, 2021*

* **Breaking:** The `state_legislative_districts` key from the [`stateleg`](#state-legislative-districts) field append now returns an array of `house` and `senate` districts instead of a single object
* The [`stateleg-next`](#state-legislative-districts) field append is back! Now returning a preview from upcoming state legislative district changes. As with congressional districts, we are updating district data on an ongoing basis as more states complete their redistricting process
* [`stateleg`](#state-legislative-districts) and [`stateleg-next`](#state-legislative-districts) can now return all districts that intersect with a zip code boundary along with the proportion of overlap
* [`cd118`](#congressional-districts) has been added as a field append, returning districts for the upcoming 118th congress. Districts are updated on an ongoing basis as more states complete their redistricting process

## v1.6
*Released on September 15, 2021*

* Introduced the `format` parameter for single [forward](#single-address) and [reverse](#reverse-geocoding) geocoding requests

*Released on June 16, 2021*

* Counties can now be geocoded in the U.S. Either standalone, or as part of an adddress

*Released on March 1, 2021*

* `stateleg` now returns the same data as `stateleg-next`. `stateleg-next` may be used again for future legislative district changes

*Released on February 25, 2021*

* Introduced `census2020` data append (the `census` data append will now default to `census2020`)
* Update all Census ACS data to most recent 5-year release (2015-2019)

*Released on May 28, 2020*

* **Breaking:** This fixes a bug which has backwards-incompatible consequences for `acs-families` and `acs-demographics` field appends
* *Non-breaking:* The `acs-social` table, Population with veteran status (Table B21001) now includes age breakdowns

The following ACS data tables have titles changed and/or values corrected:

**`acs-families`**

* Household type by household (Table B11001)
* Household type by population (Table B11002)
* Marital status (Table B12001)

**`acs-demographics`**

* Race and ethnicity (Table B03002)

> **Warning:** [See a full diff](/docs/acs-diff.html) of ACS output changes between API v1.5 and v1.6

## v1.5
*Released on May 13, 2020*

* **Breaking:** PO Box and second address lines (e.g. apartment/unit/suite numbers) are now returned as `results` and appear within the `formatted_address` keys
* The [`zip4`](#usps-zip-4) data append is now generally available

## v1.4
*Released on September 18th, 2019*

**`census` appends:**

* **Breaking:** The `census` append now supports vintage years, data is keyed by year instead of just returning a single year

## v1.3
*Released on March 12th, 2018*

**`timezone` appends:**

* **Breaking:** `name` property has been renamed to `abbreviation`
* `name` is now the full timezone name in a [tzdb](https://www.iana.org/time-zones)-compatible format. [Read more](#timezone)

## v1.2
*Released on January 20th, 2018*

**`cd` (Congressional district) appends:**

* **Breaking:** `current_legislator` property has been renamed to `current_legislators` and is now an array instead of an object
* Both house and senate legislators are now returned

## v1.1
*Released on January 8th, 2018*

**`cd` (Congressional district) appends:**

* **Breaking:** `congressional_district` property has been renamed to `congressional_districts`
* **Breaking:** Postal code lookups will now return multiple Congressional districts if the zip code area spans more than one district
* Current legislator information is now returned with Congressional districts

# Contact & Support
Have any questions? Just reach out to us at [support@geocod.io](mailto:support@geocod.io).
