---
title: "Geocode an address (all supported countries)"
method: GET
path: "/geocode"
tags: ["Geocoding"]
---

# Geocode an address (all supported countries)

`GET /geocode`

## Request

- Base URL: `https://api.acuris-geo.com`
- URL: `https://api.acuris-geo.com/geocode`
- Auth: one of:
  - API key in header `X-Acuris-Key`
  - HTTP bearer
  - API key in header `X-API-Key`
  - API key in query parameter `key`
  - none

Provide `country` and either a single-line `q` or fielded address
components. Resolution runs the same parse → infer → lookup chain
`/validate` uses — if `/validate` can place an input, `/geocode`
places it, by construction. **No component is required at the
gate**: `street`, `city`/`town` and `state` are all optional,
including for USA and Canada. Omitting `street` degrades the match
to a locality/postcode tier rather than failing.

**Portugal (`country=prt`):** a city-only or neighbourhood-only
request (no street) returns a **labelled approximate point**: a 200
with `approximate: true`, `resolved_level`, `resolved_name`, reason
`street_missing`, `accuracy_type` `locality_centroid` or
`admin_centroid`. A place name that is a
locality in several municipalities is never guessed: 404 with
`reasons: ["locality_ambiguous", "street_missing"]` and the
candidates in `did_you_mean`. A place name not found at all returns
400 `Missing required field: street`. A street sent without a city
is placed when exactly one town holds it (the town is filled in);
otherwise the 404 lists the candidate towns in `did_you_mean`. When
the street cannot be placed in the town sent, the town centre may be
served with `approximate: true` and reason `fell_back_to_locality`.
This includes an estate, urbanisation or neighbourhood name sent with
a town we can place (for example "Cerrado do Poço" in Porto Salvo),
or with the town as the last words of the text and no city field
(for example "Tapada Vale dos Lobos Belas"):
the 200 is a labelled town-level point, and its `reasons` then carry
`street_not_found` next to `fell_back_to_locality`. A street-type name
(Rua, Avenida, ...) that is not found, or a name sent with an
ambiguous or unknown town, stays a 404.
When the house number is not in the reference data, the 200 carries
`nearby_house_numbers` (see `ForwardGeocodeResponse`).

A single-line free-text address may be passed as `q` instead of the
fielded parameters; it is parsed with the same parser the `/validate`
path uses. This works for every supported country, including the
eight (aus, bra, can, jpn, mex, mys, tur, usa) that used to require
fielded `street`/`city`/`state` and 400 on single-line input.
Explicit fielded parameters, when present, take precedence over the
parsed single line.

**Response vocabulary:** the response is a whitelist of
geocoding-only fields — `lat`, `lng`, `accuracy_type`,
`point_coordinate`, `standardized`, `formatted_address`, and,
conditionally, `arrival_point`, `input_modified`, `attribution`,
`uprn` and `digipin`. See `ForwardGeocodeResponse` below. It never carries the
`/validate` verdict vocabulary (`status`, `match_type`,
`match_score`, `confidence`, `corrections`, and similar fields) — a
miss is a plain `{"error": "no_match", "message": "..."}` body, not
a verdict with everything zeroed out.

**Credits:** A geocode costs **1 Stripe-plan transaction** (`geocode=1`). Combined AV+GEO pool since 2026-07-23: an address validation costs one transaction and includes coordinates at no extra cost; a standalone geocode also costs one transaction, from the same plan allowance. The trial
pool decrements **1** regardless of endpoint weight. Anonymous callers consume one
free slot per IP (per-product daily free limits apply — check remaining via
`/geocode-credits`).

## Query parameters

- `key` string
- `country` string, required
- `q` string
- `street` string
- `hno` string: House number
- `city` string
- `town` string
- `state` string
- `postalcode` string
- `sublocality` string
- `db_version` string

## Response `200`

Geocode result — a whitelist of geocoding-only fields.

- ForwardGeocodeResponse: Response for `GET /geocode` and `POST /v1/geocode`. A strict whitelist of geocoding-only fields — every key that can appear is listed below, and no `/validate` AV field (`status`, `deliverable`, `corrections`, `match_components`, `match_details`, `match_score`, `match_type`, `confidence`, `confidence_level`, `input_corrected`, `provided_components`, `parsed`, `partial_match`, `house_number_not_found`, `hno_range_verified`, `enrichment`, or any legacy variant) can appear here. `lat`, `lng`, `accuracy_type`, `point_coordinate`, `standardized` and `formatted_address` are always present on a 200; the rest — including the billing tail (`balance`/`validation_credits`/`free_remaining`/ `key_class`/`free_daily_limit`) and the country-conditional fields (`attribution`, `uprn`, `digipin`, and for Portugal `reasons`, `nearby_house_numbers`, `approximate`, `resolved_level`, `resolved_name`) — are emitted only when applicable.
  - `lat` number, float, required
  - `lng` number, float, required
  - `accuracy_type` string, nullable, required: What the returned coordinate represents. `null` on `no_match`. **This is an OPEN set.** New tiers are added as reference data improves. Clients MUST pass unrecognized values through rather than throwing, and SHOULD branch on `point_coordinate` rather than on these literals. A **point coordinate** identifies one address: * `rooftop` — a point on the building itself. * `arrival_point` — the address's entrance, gate or curb-side access point. A point for *this* address, typically a few metres from the roof — deliberately not claimed as the building footprint. Everything else is derived rather than observed — a segment or an area, not an address: * `street_interpolated` — HNO estimated along a street segment polyline (SEG cascade) from the position of neighbouring house numbers. * `street_centroid` — street confirmed; exact HNO not located. **Singapore:** block numbers are not linear along a road and a letter-suffixed block (e.g. `700D`) is a separate building with its own postcode, so Singapore never returns `street_interpolated`. An unconfirmed block (or a street with no block) answers `street_centroid` at the street's centre, and `standardized.postcode` is left empty unless you supplied a postcode that exists on that street — a postcode names one building, and another building's postcode is never shown as yours. * `landmark_proximity` — India only. The address itself resolved no further than its postcode/locality, so the coordinate is that of a LANDMARK the caller named in the input ("opp. Swami Samarth Math"). It is a point on a *neighbouring* place, never the address, and it is only ever used when it out-ranks what would otherwise be returned. The landmark used is named back to you in `landmark_used` (`name`, `matched_from`, `scope`, `source`). * `postcode_centroid` — only postcode matched. * `locality_centroid` — only city/locality matched. * `admin_centroid` — only admin region (state/province) matched.
  - `point_coordinate` boolean, required: `true` when the coordinate identifies one address (`rooftop` or `arrival_point`), `false` for any derived/area tier. Branch on this rather than on `accuracy_type` literals — it stays correct when new tiers are added.
  - `standardized` object, required: The matched address, componentized. Only the components the match actually resolved are present — an unresolved component (e.g. no `state` for a country that does not use one) is simply absent from the object, never emitted as `null` or `""`.
    - `street` string
    - `house_number` string
    - `postcode` string
    - `city` string
    - `state` string
    - `country` string
    - `dependent_locality` string: Royal Mail PAF sub-element (GBR) / secondary locality line. Present only when the matched row carries one — e.g. the village between street and post town ("10 HAYDEN LANE / CHELTENHAM" would otherwise drop it, leaving two same-named streets in different villages indistinguishable).
    - `double_dependent_locality` string: Royal Mail PAF sub-element (GBR), finer than dependent_locality.
    - `dependent_street` string: Royal Mail PAF sub-element (GBR) — a secondary street name.
    - `street_type` string: Thoroughfare type carried in its own DB column rather than folded into `street` (e.g. Malaysia's UPU S42 type).
    - `suburb` string: NZ Post's line between street and post town (NZL). Omitted when it just repeats `city`.
    - `province` string: Province sigla for the mandatory Poste Italiane locality line (ITA).
  - `formatted_address` string, required: Printable multi-line address block, e.g. for a shipping label.
  - `arrival_point` object: Entrance / access coordinate of the matched premise. Present only when the matched row has one — house-number-level matches — and absent on street/locality fallbacks and when the served coordinate came from a POI. Never `null`; never derived from `lat`/`lng`.
    - `lat` number, float
    - `lng` number, float
  - `input_modified` string[]: Lowercase names of the components the engine changed from what the caller sent in a single-line `q=` input (e.g. `["street", "city"]`), deduped. States a fact about the input, not a verdict about the address — it is not a re-admission of the forbidden `corrections` / `input_corrected` AV fields. Present only when non-empty: no key at all when nothing was modified, never an empty array.
  - `attribution` string: GBR only.
  - `uprn` string: GBR only. Ordnance Survey Unique Property Reference Number, present when known.
  - `digipin` string: IND only. India Post DIGIPIN, a deterministic 10-character code derived purely from `lat`/`lng` (never from address existence — it says nothing about whether the address itself was verified). Present only when this deployment has DIGIPIN enabled; not guaranteed on every India response even from a deployment that has it enabled (omitted if no coordinate was resolved, or the encoder found none).
  - `reasons` FailureReason[]: PRT only, optional. Present when the point is not a confirmed house: what could not be pinned down (e.g. `house_number_unconfirmed` + `house_number_not_in_reference`, `below_verification_threshold` + `house_number_missing`, or `street_missing` / `fell_back_to_locality` on an approximate point). Same codes as `/validate`.
  - `nearby_house_numbers` NearbyHouseNumbers: **Portugal (`country: prt`) only.** Present on a 200 answer when the street was matched but the house number you sent is not in the reference data — the answer is then either street-level (`street_centroid`) or `street_interpolated` at a point between the nearest same-parity house numbers (`pin_between`). It lists which numbers of that street ARE held, on the same side of the street (odd and even numbers usually face each other). Informational only: it never changes the coordinate, tier, confidence or `deliverable`. Sent with reason `house_number_not_in_reference`. Pass unrecognized fields through.
    - `requested` string: The house number as you sent it.
    - `parity` string
    - `before` NearbyHouseNumber
      - `hno` string
      - `lat` number, float, nullable
      - `lng` number, float, nullable
      - `accuracy` string, nullable: The coordinate tier of that house number (e.g. `rooftop`), `null` without a coordinate.
      - `has_coordinates` boolean: `false` when the number exists in the reference data without its own coordinate (`lat`/`lng`/`accuracy` are then `null`).
    - `after` NearbyHouseNumber
      - `hno` string
      - `lat` number, float, nullable
      - `lng` number, float, nullable
      - `accuracy` string, nullable: The coordinate tier of that house number (e.g. `rooftop`), `null` without a coordinate.
      - `has_coordinates` boolean: `false` when the number exists in the reference data without its own coordinate (`lat`/`lng`/`accuracy` are then `null`).
    - `pin_between` string[], nullable: The two held numbers the interpolated point was placed between (both may be the same number, e.g. `41` for a requested `41B`); `null` when the answer is street-level rather than interpolated.
    - `same_parity_available` string[]: Up to 40 held numbers on the same side nearest to the requested one, in ascending order (letter suffixes such as `2A` included).
    - `total_doors` integer: Number of distinct house numbers held for the street.
    - `coordinated_doors` integer: How many of those carry their own coordinate.
  - `street_postcodes` object[]: Netherlands only, optional. Present only on STREET-LEVEL answers (`accuracy_type` `street_centroid`, `street_segment_centroid` or `street_interpolated`): the postcodes the matched street covers, each with its house-number range. Sorted by `house_number_from`, then `postcode`; at most 50 entries (see `street_postcodes_total` and `street_postcodes_truncated`). Ranges count numeric house numbers only; addresses whose number carries letters are not counted. Absent on rooftop and other house-number-level answers.
    - `postcode` string
    - `house_number_from` integer
    - `house_number_to` integer
    - `parity` 'odd' | 'even' | 'both': Which side(s) of the street the postcode covers within that range.
  - `street_postcodes_total` integer: With `street_postcodes`, how many postcodes the street covers (not capped).
  - `street_postcodes_truncated` boolean: With `street_postcodes`, `true` when the street covers more postcodes than are listed.
  - `postcode_range` object: Netherlands only, optional. Sent with `street_postcodes` when the street covers MORE THAN ONE postcode: the lowest and highest postcode over the whole street (an outer bound, not a continuous run; `street_postcodes` lists the exact ones). In that case `standardized.postcode` carries `text` instead of a single postcode and `standardized.formatted_address` prints it. Check for this field before treating `standardized.postcode` as one postcode.
    - `from` string
    - `to` string
    - `text` string
  - `approximate` boolean: PRT only, optional. `true` when the point is a town / area centre standing in for the address — a city- or neighbourhood-only request (`street_missing`) or a street that could not be placed (`fell_back_to_locality`). `accuracy_type` is then `locality_centroid` or `admin_centroid`.
  - `resolved_level` string: **Portugal (`country: prt`) only.** Which kind of place an approximate point (`approximate: true`) stands for. Open set — pass unknown values through. * `locality` — a locality (village / town). * `postal_town` — the town name of the postal address. * `municipality` — a municipality (concelho). * `district` — a district. * `lisbon_parish` — a Lisbon parish or neighbourhood name; the point is Lisbon's.
  - `resolved_name` string: PRT only, with `approximate`. The place's name as spelled in the reference data.
  - `balance` integer: Remaining geocode transactions after a keyed, non-free-tier call.
  - `validation_credits` integer
  - `free_remaining` integer: Free calls left today, for anonymous and non-`free_av_geo` free-tier callers.
  - `key_class` string: Present only for verified `free_av_geo` keys — `"free_av_geo"`. See `/check-key`.
  - `free_daily_limit` integer: Present only for verified `free_av_geo` keys. Always `1000` (the shared daily allowance).

## Other responses

- `400`: Missing `country` (`Missing parameter: country`), unsupported `country` (`Unsupported country`), or neither `q` nor any fielded component supplied (`Missing parameters. Provide q (single-line address) or street/city fields.`). Portugal: a city-only request whose place name is not found returns `Missing required field: street`.
- `403`: Invalid key, no transaction balance, or anonymous geocode limit reached. Key-level 403s: `{"error": "key_blocked", "message"}` when the API key has been blocked (the `message` says why), and `{"error": "ip_not_allowed", "message", "ip"}` when the key is restricted to approved source IP addresses and this request came from another one (`ip` is the address we saw). Source-IP restriction is optional and set up per key on request via support.
- `404`: No match. Body is `{"error": "no_match", "message": "..."}` — never the `/validate` match-quality contract (no `match_type`, `match_score`, `match_components`, `input_corrected`). Portugal: may also carry `reasons`, `did_you_mean` and `did_you_mean_truncated`, with a specific `message` (see `ForwardGeocodeErrorBody`).
- `422`: Input could not be interpreted (e.g. neither a string nor a fielded object). Same `{"error": "no_match", "message": "..."}` shape as 404.
- `429`: Too many requests (anonymous limit or WAF/limiter)
- `500`: Internal error during geocoding. Body: `{"error": "Internal error"}` — the real cause is logged server-side, never echoed to the caller.
- `503`: Reference database not available, or another engine-level failure.
- `504`: Geocode lookup timed out.

---

[API](https://skmtc.dev/acuris-geo/apis/acuris-geo-api.md) · [All operations](https://skmtc.dev/acuris-geo/apis/acuris-geo-api/llms.txt) · [OpenAPI document](https://skmtc.dev/acuris-geo/apis/acuris-geo-api/revisions/8547b31dd96a?raw)
