{"openapi":"3.0.3","info":{"title":"Acuris Geo API","description":"REST API for **address validation**, **geocoding**, and **address suggestions**\nacross supported countries (see **Country codes** below).\n\n**AI agents / MCP:** the same capabilities are exposed as self-describing MCP\ntools at `https://api.acuris-geo.com/mcp` (streamable HTTP; authenticate with\n`Authorization: Bearer <key>`). See [/docs/mcp](https://api.acuris-geo.com/docs/mcp).\n\n### Authentication\nPresent your API key using any of the following (listed in priority order):\n- **`X-Acuris-Key: <key>`** header — preferred for keys issued via Stripe Checkout.\n- **`Authorization: Bearer <key>`** header — standard OAuth-style bearer; works for any key.\n- **`X-API-Key: <key>`** header.\n- **`?key=<key>`** query parameter (legacy).\n- **`{\"key\": \"...\"}`** JSON body field on `POST /validate` (legacy).\n\nHeader auth is preferred: query-param secrets can leak into access logs, Referer\nheaders, and browser history. A `password` parameter is **not** an API-key\nchannel anywhere (query or body) — it is reserved for account login.\n\nWithout a key, **anonymous free tier** access is rate-limited per IP, and per-product\ndaily free limits apply. Check remaining free calls via `/validate-credits` and\n`/geocode-credits`; see the pricing page at https://www.acuris-geo.com/acuris-pricing/ for details.\n**This anonymous path is being retired for validate/geocode/reverse/postcode-lookup in favor of\nrequiring a free account** — see **Free tier (verified account)** below for the allowance you get\nonce you sign up, and the forthcoming anonymous-access change.\n\n### Versioned namespace (`/v1/*`)\nA stable, versioned `/v1/*` namespace mirrors the core endpoints (e.g. `/v1/validate`,\n`/v1/validate/batch`, `/v1/geocode`, `/v1/reverse`). Behavior is identical to the unversioned\nroutes; prefer `/v1/*` for long-lived integrations. Details are documented on the individual\npath items.\n\n#### RapidAPI\nWhen consumed via the RapidAPI marketplace, the RapidAPI gateway is the identity\nprovider: it injects `X-RapidAPI-Proxy-Secret` (a shared secret verified server-side),\n`X-RapidAPI-Key`, `X-RapidAPI-User`, and `X-RapidAPI-Subscription` on every request.\nPlan quotas are enforced upstream by RapidAPI; no Acuris account or transaction balance is required\nfor traffic routed through RapidAPI. Direct (non-RapidAPI) calls continue to use the\nauthentication methods above.\n\n### Country codes (validation & geocode `country`)\nWe hold reference databases for **~250 countries**, roughly **130** of them\nwith house-number-level data, and a street-segment interpolation cascade\nlive in **~95 countries**. Full multi-tier precision (an address-level\nreference DB plus the street-segment cascade) covers a flagship set\nincluding `usa`, `can`, `gbr`, `deu`, `aut`, `che`, `fra`, `esp`, `bel`,\n`nld`, `dnk`, `fin`, `swe`, `nor`, `ita`, `jpn`, `sgp`, among others.\nThe United Kingdom is served at full Royal Mail PAF precision (UPRN / UDPRN)\non its dedicated host — see **United Kingdom host** below. Belgium is fully\ntrilingual (NL / FR / DE).\nThe **acceptance set is far larger than the full-precision tier**: any country in the\n`COUNTRY_GEOCODE` table validates (~223 live today, and growing), returning the\nbest tier its reference data supports — from a point coordinate down to an\nadmin-area centroid.\nInspect `accuracy_type` in each response to see which tier was returned for a\ngiven lookup. Additional countries are being onboarded — see the roadmap on\n[acuris-geo.com](https://www.acuris-geo.com/).\n\n### United Kingdom host\nAll `country=gbr` traffic — `/validate`, `/suggest`, `/reverse`, and the\nUK-only endpoints `/postcode-lookup` and `/geocode-uk` — is served from\n**https://paf.acuris-geo.com** (see Servers). A `gbr` request sent to the\nmain host is refused rather than silently degraded: it returns **400**\n`{\"error\": \"country_not_served_by_this_endpoint\", \"use_instead\": \"https://paf.acuris-geo.com\"}`.\n\n### Free enrichment\nValidated addresses in **eighteen countries** — USA, Canada, Germany,\nAustria, Switzerland, France, the United Kingdom, Belgium, Spain, Portugal,\nIreland, the Netherlands, Finland, Sweden, Luxembourg, Japan, Singapore and\nHong Kong — automatically carry a free `enrichment` block of official\nstatistical geography (no extra charge, no request parameter); see the\n`enrichment` property on `ValidateResponse` for the fields and the\nprecision gates.\n\n### Free tier (verified account)\nA verified account — any key with `key_class: free_av_geo`, which is what `POST /register` +\nemail verification grants by default — gets a **recurring, non-expiring daily allowance** for\naddress validation, geocoding, and reverse geocoding. This is **not** a depleting trial pool:\nit never runs out and the account never expires (`trial_expires_at` is `null` for these keys).\n\n- **1,000 requests per UTC day, one shared allowance** — `/validate`, `/geocode` (and its\n  `/geocode-usa` alias), and `/reverse` all draw from the same single 1,000/day bucket (not one\n  bucket per product), which resets at UTC midnight, for as long as the account exists.\n- **The UK is excluded from the 1,000/day allowance and is metered separately, because Royal\n  Mail PAF data is licensed per lookup and cannot ride the general allowance.** Any\n  `country=gbr` request — on `/validate`, `/reverse`, or the UK-only `/postcode-lookup` and\n  `/geocode-uk` endpoints, all served from `https://paf.acuris-geo.com` (see **United Kingdom\n  host** above) — is capped at **5 per UTC day** for a registered key (anonymous UK callers:\n  **3 per UTC day** per IP) instead, and never draws from or combines\n  with the 1,000/day figure. See `uk_trial` (`cap` / `used` / `remaining`) on `GET /check-key`.\n- **`/postcode-lookup` only ever serves `country=gbr`** — any other country is rejected before\n  any transaction check runs — so it is always billed under the UK daily cap, **never** the\n  1,000/day allowance, regardless of key class.\n- **`/suggest` (autocomplete) has its own metering rules, never the UK daily\n  cap described above — and its numbers depend on the same launch flag as the anonymous\n  403 described below (`AV_GEO_REQUIRE_SIGNUP`, or the dedicated `AV_GEO_SUGGEST_METER` if\n  set):**\n    - **As of this writing, that flag is off in production**, so `/suggest` behaves as it has\n      historically: a genuinely valid API key is completely exempt from metering here, and\n      anonymous widget-token callers are bounded only by a per-IP flask-limiter soft cap of\n      **5/second, 60/minute, 500/day** (per gunicorn worker — a first-line burst backstop,\n      not an authoritative cross-fleet limit; the handler does not authenticate against a\n      quota pool or decrement one in this state).\n    - **Once the flag is switched on**, any genuinely valid key — other than the\n      policy-exempt `stripe` / `integration` / `partner` classes, which stay unmetered — draws\n      from the same shared recurring **1,000 requests per UTC day** allowance that\n      `/validate`/`/geocode`/`/reverse` draw from (same bucket, same `free_remaining` field on\n      a `200`), refused with `free_limit_reached` (`403`) once\n      exhausted. Anonymous callers are capped at **40 per UTC day per IP** instead (refused\n      with `rate_limit_exceeded`, `429`), and the flask-limiter decorator's daily figure drops\n      from 500 to 40 at the same moment as a redundant first-line backstop. `country: \"gbr\"`\n      requests draw from this SAME bucket, never the UK daily cap — see the `/suggest`\n      operation below for why.\n  `country: \"gbr\"` suggest requests carry one further, independent layer regardless of flag\n  state — a per-IP anti-scrape velocity cap (`PAF_SUGGEST_IP_RPM`, **600/minute** by default,\n  10x that for a genuinely valid non-test API key, allowlisted keys exempt) that degrades to\n  an empty `{\"suggestions\": [], \"limit\": \"reached\"}` result rather than an error when tripped.\n  See the `/suggest` operation below for the full contract.\n- `GET /check-key` reports `key_class`, and for `free_av_geo` keys also `free_remaining`\n  (a single integer: today's remaining count in the shared daily allowance) and\n  `free_daily_limit` (`1000`). The legacy `validation_credits` / `geocode_credits` fields on these keys are a\n  frozen signup-time snapshot, not a live balance — use `free_remaining` instead.\n- **Commercial use of the free tier requires a permanent, visible attribution link back to\n  acuris-geo.com** on any page or product that displays results derived from it — see the\n  Terms of Service for the exact wording required.\n- **Anonymous (no-key) access to these endpoints is being retired — not yet live in production.**\n  Once the `AV_GEO_REQUIRE_SIGNUP` flag is enabled, a request to `/validate`, `/geocode`,\n  `/reverse`, or `/postcode-lookup` with no API key at all will return **403**\n  `{\"error\": \"signup_required\", \"message\": \"Create a free account to use this endpoint — ...\"}`\n  instead of being served under the anonymous per-IP daily limits described under\n  **Authentication** above, directing the caller to register for the allowance described here.\n  As of this writing that flag is **off** in production: anonymous per-IP limits still apply\n  exactly as documented above until it is switched on.\n\n### Match quality contract (validate and geocode)\nEvery successful or not-found response carries a machine-readable precision tier:\n- **`accuracy_type`** — what the returned coordinate represents. **This is an\n  OPEN set**: new tiers are added as reference data improves, so pass\n  unrecognized values through rather than treating them as a failure.\n  *Point coordinates* (a coordinate for one address): `rooftop` (a point on\n  the building) and `arrival_point` (its entrance / gate / curb-side access\n  point). *Derived tiers* (a segment or an area, not an address):\n  `street_interpolated` (HNO estimated along a street-segment polyline),\n  `street_segment_centroid` (street confirmed, exact HNO not in DB; the pin is\n  the centre of the known house numbers nearest the one typed),\n  `street_centroid` (street confirmed, exact HNO not in DB; the pin is the\n  middle of the street),\n  `postcode_centroid`, `locality_centroid`, `admin_centroid`. `null` on\n  `no_match`.\n- **`point_coordinate`** — boolean; `true` for `rooftop` and `arrival_point`,\n  `false` for every derived tier. **Branch on this rather than on\n  `accuracy_type` string literals** — a literal comparison silently\n  reclassifies each newly-added tier as imprecise. Not yet emitted by\n  `/reverse` — derive it from `accuracy_type` there.\n- `match_type` — internal/legacy tier with a numeric score table:\n  `rooftop` (1.0), `parcel_centroid` (0.9), `interpolated` (0.8),\n  `street_level` (0.6), `zip_centroid` (0.4), `city_centroid` (0.2), `no_match` (0.0).\n  Retained for backward compat; `accuracy_type` is the recommended field.\n- `match_score` — float `0.0`–`1.0` mirroring `match_type`.\n- `match_components` — object indicating which input fields were confirmed by the match.\n- `input_corrected` — `true` when any input field was normalized or corrected.\n\n**Cascade behavior on geocode:** when the addresses DB has no rooftop record for the\nsubmitted address, the engine falls back to a street-segment DB (SEG) and emits the\nhighest-precision tier available (interpolated → street centroid → postcode centroid →\nlocality centroid). `/validate` follows the same cascade for the returned `lat`/`lng`,\nbut `confidence_level` (high/medium/low/none) reflects whether the address was *confirmed*,\nnot where the coordinate came from — SEG-derived results stay at low/none since SEG can attest\nto plausibility but not existence.\n\nValidation also exposes:\n- `suggestions` — ranked near-misses when exact match fails, or alternates when a fuzzy match succeeds.\n- `alternative_matches` — same street + house number found in a different state (USA / CAN only).\n- `reasons` — failure classifications (`street_not_found`, `city_not_matching`, `locality_unknown`).\n  For Portugal, `street_not_found` can also appear on a 200 `approximate` town-level answer.\n  On centroid-fallback responses, `reasons` also includes a `validation_failed:*` marker explaining\n  which validator/matcher error triggered the fallback.\n- `partial_match` — `true` when the address itself could not be validated against the DB but the\n  cascade still inferred a centroid coordinate (postcode / locality / admin). Always inspect this\n  before claiming an address is \"valid and deliverable\": `partial_match: true` means only the\n  coordinate is trustworthy, the address fields were not confirmed.\n- `match_type_legacy` / `match_score_legacy` — retained for backward compatibility with pre-2026 clients\n  (old values: `exact` / `fuzzy`, and the string label `\"Perfect match\"`, etc.).\n\n### Centroid-fallback on `/validate`\nWhen the v1/v2 lookup cannot match the input against the addresses DB (`street_not_found`,\nor required fields like `street` are missing but a postcode/locality is present),\n`/validate` falls through to the SEG cascade and — if a `postcode_centroid` / `locality_centroid` / `admin_centroid`\ncan be inferred — returns **200** with `lat`/`lng` set, `accuracy_type` populated, and `partial_match: true`.\nIf SEG also has nothing usable, the original **404** (or **400** for missing-required-field) is returned unchanged.\nThis means a 200 response no longer *necessarily* means the address itself validated — always check `partial_match`.\n\n### HTTP status codes\n- **200** match found, **or** centroid-fallback returned (`partial_match: true`, see below).\n- **400** missing required field (e.g. `country`). On `/validate` a missing `street`/`city` only returns 400 when SEG also has nothing — otherwise a 200 centroid-fallback is returned. Also returned for `country=gbr` requests sent to the main host instead of the PAF host (`country_not_served_by_this_endpoint`, with `use_instead`).\n- **401** invalid or inactive API key.\n- **402** payment required — subscription canceled or a prepaid transaction pack expired (paid data endpoints).\n- **403** insufficient transaction balance, trial expired, or anonymous limit reached.\n  When a free **daily** allowance is used up — `free_limit_reached` (the shared 1,000/day\n  allowance) or `uk_trial_cap_reached` (the UK Royal Mail PAF daily cap) — the body also\n  carries `resets_at` (ISO 8601 UTC, the next UTC midnight, e.g. `2026-10-09T00:00:00Z`) and\n  `retry_after_seconds` (integer, at least 1), the response has a standard `Retry-After`\n  header with the same number of seconds, and `message` states the reset time in UTC plus UK\n  (and, for `free_limit_reached`, Germany) local time. Error codes, status and the existing\n  fields (`free_remaining`, `uk_trial_cap` / `uk_trial_used` / `uk_trial_remaining`,\n  `key_accepted`) are unchanged.\n  **UK PAF evaluation (when enabled):** a free key's UK lookups can also be refused with\n  `uk_terms_acceptance_required` (the key's owner has not accepted the\n  [UK PAF Evaluation Terms](https://api.acuris-geo.com/legal/uk-evaluation-terms); accept them in\n  the console, or request a dev key with `\"accept_terms\": true`) or `uk_evaluation_expired`\n  (the key's UK evaluation has ended: 90 days after acceptance, or for keys issued before\n  acceptance was required, 90 days after creation with a 14-day minimum once enforced; request a\n  new key and accept the terms, or buy a UK transaction pack). Both are 403 with `error`\n  and `message`. Keys with a paid UK transaction pack are not affected.\n- **404** address not found **and** the SEG cascade had no centroid to offer. Body still includes `match_type: \"no_match\"`, plus `suggestions` and `reasons` when available.\n- **422** input could not be parsed (e.g. `input` was neither a string nor an object on `/validate`).\n- **429** rate limit exceeded (`rate_limit_exceeded`).\n- **501** reverse geocoding not yet enabled for this country (spatial index missing).\n- **503** reference database not available on this deployment.\n- **504** validation timed out.\n\nHuman-friendly **register / login** flows: HTML pages at `/register` and `/login` (browser). Obtain an API key from the customer dashboard after signup at [acuris-geo.com/dashboard](https://www.acuris-geo.com/dashboard).\n","version":"1.9.3","x-last-updated":"2026-10-11","x-changelog":"UK PAF evaluation terms (2026-10-11, additive): /dev-key accepts accept_terms (boolean) and may return 400 terms_acceptance_required when terms acceptance is enforced; its response may carry uk_evaluation_expires_at; /check-key gains a uk_eval block (mode, accepted_at, uk_eval_expires_at, days_remaining); UK lookups on free keys may be refused with 403 uk_terms_acceptance_required or uk_evaluation_expired. Prior entry: Daily-cap reset info (2026-10-08, additive): free_limit_reached and uk_trial_cap_reached 403 bodies gain resets_at and retry_after_seconds plus a Retry-After header, and their message now says when the daily allowance resets (UTC, UK and Germany time). The UK free cap is documented as 5/day registered, 3/day anonymous (was 40/day). No field removed, no code or status changed. Prior entry: Netherlands postcode + house number (2026-10-07, additive, NLD only): /validate accepts postcode + house_number with no street and no city; postcode spellings 3999NN / 3999 nn are accepted; FailureReason gains postcode_house_number_ambiguous and house_number_extension_missing; ValidateResponse documents city_backfilled_from_postcode and gains street_backfilled_from_postcode; ValidateErrorBody did_you_mean entries gain house_number (NLD). Prior entry: Free-tier allowance doc fix (2026-10-01, docs only, no API change): the verified-account (free_av_geo) daily allowance has been 1,000 per UTC day since 2026-09-28, not 3,000, and it is ONE shared bucket for validate, geocode, reverse and (once the signup flag is on) suggest, not one bucket per product. Corrected the Free tier prose, the /suggest metering prose, free_daily_limit (example and \"Always 1000\") on /check-key and ForwardGeocodeResponse, and the /check-key free_remaining schema, which the server returns as a single integer, not a {validate, geocode} object. Prior entry: Portugal explanations (2026-10-01, additive, PRT only): FailureReason gains city_not_found, city_missing, street_found_in_multiple_localities, street_type_mismatch, street_particle_mismatch, street_spelling_mismatch, locality_ambiguous, street_missing, fell_back_to_locality, house_number_not_in_reference, house_number_missing (city_missing and street_found_in_multiple_localities were already emitted for some other countries and are now documented). ForwardGeocodeErrorBody gains optional reasons, did_you_mean, did_you_mean_truncated (PRT); ValidateErrorBody did_you_mean documents the PRT entry fields (municipality, district, doors, match) and gains did_you_mean_truncated. ValidateResponse and ForwardGeocodeResponse gain optional nearby_house_numbers, approximate, resolved_level, resolved_name (ForwardGeocodeResponse also reasons, PRT only). New component schemas NearbyHouseNumbers, NearbyHouseNumber, ResolvedLevel, DidYouMeanEntry. /geocode documents the PRT city-only labelled approximate point, the ambiguous-place 404 and the street-without-city 404. No field removed, no type changed. Prior entry: /geocode facade doc fix (2026-09-04): ForwardGeocodeResponse was missing digipin — _attach_digipin (usa-app.py) adds it to real /geocode and /v1/geocode responses whenever country=ind and ACURIS_DIGIPIN is enabled (it is, on this deployment), so the schema's \"no key outside this list ships\" claim was false the moment it shipped. Added digipin (string, IND-only, present only when the feature flag is on and a coordinate resolved) to the schema and to both endpoints' response-vocabulary prose; corrected the same omission in docs/superpowers/specs/2026-09-03-geocoding-product-design.md §2, the spec these docs derive from. No other post-projection response mutation was missed — walked the full route tail (usa-app.py ~29746 through its single `return jsonify(resp)` at ~29799) key by key. Prior entry: /geocode facade cutover (2026-09-04, ratified breaking change — pre-customer, ~139 lifetime geocode calls, essentially all internal): GET /geocode and POST /v1/geocode now run the same parse -> infer -> lookup chain as /validate, so the fielded gate (\"Missing parameters. Street, City and State are required.\") is gone for all 8 countries that used to hit it (aus, bra, can, jpn, mex, mys, tur, usa) — street/city/state are optional everywhere, including USA/CAN, and a single-line q= now resolves any supported country. The response is a strict geocoding-only whitelist (ForwardGeocodeResponse): lat, lng, accuracy_type, point_coordinate, standardized, formatted_address always; arrival_point, input_modified, attribution (gbr) and uprn (gbr) conditionally. No AV vocabulary (status, match_type, match_score, confidence, corrections, etc.) ships on these two routes any longer. A miss is a plain {\"error\": \"no_match\", \"message\": \"...\"} body (ForwardGeocodeErrorBody) at 404, the same shape at 422 for uninterpretable input, and a genuine engine/server failure is 503 or 500 — never a match-quality verdict with everything zeroed out. The legacy /geocode-usa and /geocode-uk shorthand routes are unchanged and still return the original AV-vocabulary shape (GeocodeResponse/GeocodeErrorBody). Prior entry: Whole-branch review fixes (2026-08-27): reconciled the two /suggest metering descriptions with the code — they previously said /suggest \"is metered by neither the 3,000/day allowance nor the 40/day UK cap\" and quoted a flat 500/day, which the metering commits in this same branch (2455789d, e4f047a1) had already made untrue, AND which the launch-flag fix (P0-1) then made conditional. Both /suggest sections now state the honest, flag-conditional truth: unmetered/500-per-day-soft-cap while AV_GEO_REQUIRE_SIGNUP is off (the production state as of this writing), 40/day anonymous + 3,000/day per registered key once the flag flips on. Also deleted the unbacked \"Service level\" block (99.9% uptime target, p95 < 500ms latency target, contractual SLA with uptime credits) — the company is pre-revenue with zero paying customers and none of that is backed by an actual agreement. Prior entry: AV/GEO free-tier relaunch: replaced the \"four independent trial pools (1,000 credits / 28 days each)\" description with the real model — a verified free_av_geo account now gets a recurring, non-expiring 3,000-requests-per-UTC-day allowance per product for validate/geocode/reverse, never a depleting pool. Added the explicit UK carve-out (Royal Mail PAF licensed per lookup, capped separately at 40/UTC day, never drawn from the 3,000) and stated /postcode-lookup is UK-only and therefore always under the 40/day cap, never 3,000. Split email/phone verification into their own subsection: unchanged, still 1,000 credits / 28 days each. Documented key_class, free_remaining, and free_daily_limit on /check-key; corrected uk_trial from \"lifetime cap\" to \"per UTC day\". Added the free-tier commercial-use attribution requirement and the forthcoming (not yet live in production) signup_required 403 for anonymous validate/geocode/reverse/postcode-lookup calls behind AV_GEO_REQUIRE_SIGNUP. Prior entry: Retired GET /search (now 410 gone); added the UK (PAF) server entry and country=gbr routing note; corrected coverage prose (~250 reference DBs, ~130 with house numbers, ~95 street-segment countries, flagship tier named); documented the 11-country free enrichment; removed the password auth channel (use ?key= or headers); phone verdict not_in_service + range_coverage; txn_pack_* Stripe plans; email spam-trap / domain-age fields; identity sanctions / area_deprivation additions; refreshed stale examples. Endpoint-level corrections: /validate — canonical form always in standardized (corrected key reserved), non_deliverable MatchType + 400 body, FailureReason now an open set with the live codes, reasons/suggestions on 200 partials, disclosure fields documented (unverified_fields, postcode_unverified, postcode forensics, accuracy_label, uprn_match_m), 402/403 bodies, alternative_matches marked reserved; /suggest — 19-country coverage, postcode-first input, state + lat/lng bias params, JPN two-stage zip/oaza/chome, SuggestItem schema (count, locality, UK delivery-point labels, kanji fields), hint/limit response fields, /widget/token documented; /reverse — Stripe billing is flat 1/request (per-address applies to trial keys), irl now serves reverse; /postcode-lookup — full PAF element set (post_town, address_lines, administrative_county, uprn_match_m); /geocode — city/town required in practice, q accepted on GET; /check-key — key_type, uk_trial, plan fields + 402; phone batch/match response codes completed.","contact":{"name":"Acuris Geo Support","email":"support@acuris-geo.com","url":"https://www.acuris-geo.com/"}},"servers":[{"url":"https://api.acuris-geo.com","description":"Production"},{"url":"https://paf.acuris-geo.com","description":"United Kingdom (PAF) — all country=gbr requests are served here"}],"security":[{"acurisKeyHeader":[]},{"bearerAuth":[]},{"apiKeyHeader":[]},{"apiKeyQueryLegacy":[]},{}],"tags":[{"name":"Validation","description":"Address validation and free-tier transactions"},{"name":"Geocoding","description":"Rooftop / reference-database geocoding"},{"name":"Suggest","description":"Autocomplete-style suggestions"},{"name":"Postcode lookup","description":"UK postcode → all addresses (Royal Mail PAF)"},{"name":"Account","description":"Key check and account-related helpers"},{"name":"Config","description":"Client configuration for forms"},{"name":"Billing","description":"Stripe-hosted self-serve subscription checkout"},{"name":"Versioned aliases (v1)","description":"Stable `/v1/*` mirrors of the core endpoints. Behaviour is identical to the unversioned routes above — same engine, same response schema — but the path is guaranteed not to change, so prefer these for long-lived integrations. Listed separately only to keep the sections above free of duplicate entries."}],"paths":{"/validate":{"post":{"tags":["Validation"],"summary":"Validate an address","description":"Accepts a single-line address string **or** structured fields in `input`,\nplus required `country` (ISO-style code).\n\n**Body formats:** JSON (`Content-Type: application/json`) is the documented\nformat. A form-encoded (`application/x-www-form-urlencoded`) or `multipart/form-data`\nbody with the same flat field names (`country`, `street`, `city`, ...) is also\naccepted, and `country_code` / `countryCode` are accepted as aliases of `country`.\nAddress fields are never read from the query string.\n\n**Street-level answers (Netherlands):** a street sent without a house number (or\nwith one that is not on file) is answered at street level (`street_centroid`,\n`street_segment_centroid`, `street_interpolated`). Such an answer lists the\npostcodes the street covers in `street_postcodes`; when there is more than one,\n`postcode_range` and `standardized.postcode` state the range as `from 9573 PA to\n9573 PH`, and `standardized.formatted_address` prints it with two spaces before the\ntown (PostNL convention). A street sent with no city that exists in several places\nis refused with the count and a request to add a city or postcode (see\n`ValidateErrorBody.locality_count`); when a postcode was sent but is not on\nfile, the message asks for a city only.\n\n**Postcode + house number (Netherlands):** `postcode` (PC6, e.g. `3999 NN`,\n`3999NN` or `3999 nn`) and `house_number` alone, with no street and no city, is\na complete Dutch address and is accepted (single line too: `3999 NN 27`). When\nexactly one street holds that number at that postcode, the answer is that\naddress (`rooftop`, status `verified`, `corrections: []`) and the derived parts\nare disclosed with `street_backfilled_from_postcode: true` and\n`city_backfilled_from_postcode: true` (they are not corrections: nothing you sent\nwas wrong). A letter (huisletter, `17a`) selects that letter's own address. When\nseveral streets hold the number at that postcode the request is a 404 with\n`reasons: [\"street_missing\", \"postcode_house_number_ambiguous\"]` and\n`did_you_mean` entries (`street`, `city`, `postcode`, `house_number`; at most 6).\nWhen the number exists only with letters (`3A`, `3B`, ...) and none was sent, the\nanswer adds reason `house_number_extension_missing` and lists the letters in\n`did_you_mean`. A number not on file at that postcode is answered at the\npostcode (`postcode_centroid`, `partial_match: true`, reason\n`house_number_not_in_reference`, empty `standardized.street`), never with a\n400. A street or city you send is used as sent (this lookup does not run).\n\n**Credits:** A validation costs **1 Stripe-plan transaction** (`validate=1`). The trial\npool decrements **1** regardless of endpoint weight. Anonymous callers consume one\nfree slot per IP (per-product daily free limits apply — check remaining via\n`/validate-credits`; anonymous access is rate-limited per IP).\n\n**Response add-ons (opt-in):**\n- **ISO 20022 / CBPR+** — pass `\"iso20022\": true` in the body (or `?iso20022=1`)\n  to add an `iso20022` block mapping the result onto Swift CBPR+ postal-address\n  shapes (`structured` / `hybrid`) plus explicit truth `assertions`, hard-negative\n  `refutation`s, and `unresolved` coverage gaps. Opt-in/**beta**; the default\n  response shape is unchanged when the flag is absent. See `Iso20022Block`.\n  The flag also switches PO-box handling: without it, non-deliverable input is\n  rejected with 400; with `iso20022: true` it is accepted and labelled via\n  `non_deliverable_type` (ISO 20022 postal addresses may be PO boxes).\n- **`mode=interactive` (AD-parity resolver)** — pass `\"mode\": \"interactive\"` with a\n  **fielded** `input` object to get a ranked pick-list / valid house-number-range\n  envelope (`process_status`, `results[]`) instead of the single batch verdict.\n  Opt-in/**beta**; billed identically to a batch validation (1 transaction). The default\n  `mode: batch` contract is untouched. See `InteractiveEnvelope`.\n","operationId":"validateAddress","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateRequest"},"examples":{"oneLine":{"summary":"Single-line (USA)","value":{"input":"1600 Pennsylvania Ave NW, Washington, DC 20500","country":"usa"}},"keyed":{"summary":"With API key in body","value":{"input":"Eckenbertstraße 31, 67549 Worms","country":"deu","key":"YOUR_API_KEY"}}}}}},"responses":{"200":{"description":"Validation succeeded **or** partial fallback returned. Inspect `partial_match`\nto distinguish: when `true`, the address was not fully confirmed — either the\nstreet resolved but not the house number (`street_interpolated` /\n`street_centroid`), or the SEG cascade inferred a `postcode_centroid` /\n`locality_centroid` / `admin_centroid` for `lat`/`lng`. `reasons` states what\ncould not be pinned down.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateResponse"}}}},"400":{"description":"Missing country, unsupported country, or bad payload. A missing `street`/`city`\nonly surfaces as 400 when the SEG cascade also has no centroid to offer — when SEG\ncan supply one, a 200 with `partial_match: true` is returned instead. Netherlands:\n`postcode` + `house_number` with no street and no city is never a 400 (see the\nNetherlands postcode + house number note in the `/validate` description). Portugal: a\nstreet without a city is a 404 (see below), not a 400; a city-only request\nreturns a labelled approximate 200 (`approximate: true`) when the place is\nfound. Also returned\nfor `country: gbr` requests sent to this host — the UK is served from\n`https://paf.acuris-geo.com` (body: `country_not_served_by_this_endpoint`\nwith `use_instead`).\n\nAlso returned for **non-deliverable input** (PO Box, Postfach, Rural Route, …):\nthe body then carries the full match-quality contract with\n`match_type: \"non_deliverable\"`, `non_deliverable_type` (e.g. `po_box`) and\n`reasons: [\"non_deliverable_address\"]` — see `MatchType`. With `iso20022: true`\nthe same input is instead accepted as a labelled 200 (`non_deliverable_type` on\nthe success body), since ISO 20022 postal addresses may legitimately be PO boxes.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"401":{"description":"Invalid or inactive API key"},"402":{"description":"Payment required (Stripe-plan keys): `subscription_canceled`,\n`pack_expired` (body includes `expired_at`), or `credits_wrong_region`\n(body includes `country`, `have_regions`, `needed` — the key's credit\npacks do not cover the requested country's region).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"403":{"description":"Insufficient transaction balance. Body shapes: `{\"error\": \"quota_exceeded\", \"pool\", \"limit\",\n\"used\", \"message\"}` for exhausted plan quota; trial keys return\n`{\"error\": \"insufficient_credits\" | \"trial_expired\", \"key_accepted\": true,\n\"credits_remaining\", \"validation_credits_remaining\", \"geocode_credits_remaining\"}`.\nKey-level 403s: `{\"error\": \"key_blocked\", \"message\"}` when the\nAPI key has been blocked (the `message` says why), and `{\"error\": \"ip_not_allowed\",\n\"message\", \"ip\"}` when the key is restricted to approved source IP addresses and\nthis request came from another one (`ip` is the address we saw). Source-IP\nrestriction is optional and set up per key on request via support.\n"},"404":{"description":"Address not found **and** SEG cascade had no centroid to offer. Body includes\n`match_type: no_match`, `suggestions` (if any near-misses scored ≥ 0.5), and `reasons`.\nWhen SEG _does_ have a centroid, the response is 200 with `partial_match: true`\ninstead of 404.\n\nPortugal (`country: prt`): `reasons` names the cause (e.g. `city_not_found`,\n`street_not_found`, `street_found_in_multiple_localities` + `city_missing`,\n`locality_ambiguous` + `street_missing`), and `did_you_mean` lists what the input\nmost likely meant (never applied automatically) — alongside the unchanged\n`suggestions`. A street sent without a city returns this 404 (with the candidate\ntowns in `did_you_mean`) rather than a 400, unless exactly one town holds the\nstreet, in which case that town is used and disclosed as a `City` correction.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateErrorBody"}}}},"422":{"description":"Input could not be parsed (e.g. `input` was neither a string nor an object).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateErrorBody"}}}},"429":{"$ref":"#/components/responses/RateLimitExceeded"},"504":{"description":"Validation timed out","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}}}}},"/validate-credits":{"get":{"tags":["Validation"],"summary":"Free validations remaining (anonymous)","description":"Returns how many **free** validations remain for this IP today (UTC-based server tracking).\nPer-product daily free limits apply; anonymous access is rate-limited per IP. Use this\n(and `/geocode-credits`) to read the remaining free allowance before it is exhausted.\n","operationId":"validateCredits","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["free_remaining"],"properties":{"free_remaining":{"type":"integer","example":15}}}}}},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/geocode":{"get":{"tags":["Geocoding"],"summary":"Geocode an address (all supported countries)","description":"Provide `country` and either a single-line `q` or fielded address\ncomponents. Resolution runs the same parse → infer → lookup chain\n`/validate` uses — if `/validate` can place an input, `/geocode`\nplaces it, by construction. **No component is required at the\ngate**: `street`, `city`/`town` and `state` are all optional,\nincluding for USA and Canada. Omitting `street` degrades the match\nto a locality/postcode tier rather than failing.\n\n**Portugal (`country=prt`):** a city-only or neighbourhood-only\nrequest (no street) returns a **labelled approximate point**: a 200\nwith `approximate: true`, `resolved_level`, `resolved_name`, reason\n`street_missing`, `accuracy_type` `locality_centroid` or\n`admin_centroid`. A place name that is a\nlocality in several municipalities is never guessed: 404 with\n`reasons: [\"locality_ambiguous\", \"street_missing\"]` and the\ncandidates in `did_you_mean`. A place name not found at all returns\n400 `Missing required field: street`. A street sent without a city\nis placed when exactly one town holds it (the town is filled in);\notherwise the 404 lists the candidate towns in `did_you_mean`. When\nthe street cannot be placed in the town sent, the town centre may be\nserved with `approximate: true` and reason `fell_back_to_locality`.\nThis includes an estate, urbanisation or neighbourhood name sent with\na town we can place (for example \"Cerrado do Poço\" in Porto Salvo),\nor with the town as the last words of the text and no city field\n(for example \"Tapada Vale dos Lobos Belas\"):\nthe 200 is a labelled town-level point, and its `reasons` then carry\n`street_not_found` next to `fell_back_to_locality`. A street-type name\n(Rua, Avenida, ...) that is not found, or a name sent with an\nambiguous or unknown town, stays a 404.\nWhen the house number is not in the reference data, the 200 carries\n`nearby_house_numbers` (see `ForwardGeocodeResponse`).\n\nA single-line free-text address may be passed as `q` instead of the\nfielded parameters; it is parsed with the same parser the `/validate`\npath uses. This works for every supported country, including the\neight (aus, bra, can, jpn, mex, mys, tur, usa) that used to require\nfielded `street`/`city`/`state` and 400 on single-line input.\nExplicit fielded parameters, when present, take precedence over the\nparsed single line.\n\n**Response vocabulary:** the response is a whitelist of\ngeocoding-only fields — `lat`, `lng`, `accuracy_type`,\n`point_coordinate`, `standardized`, `formatted_address`, and,\nconditionally, `arrival_point`, `input_modified`, `attribution`,\n`uprn` and `digipin`. See `ForwardGeocodeResponse` below. It never carries the\n`/validate` verdict vocabulary (`status`, `match_type`,\n`match_score`, `confidence`, `corrections`, and similar fields) — a\nmiss is a plain `{\"error\": \"no_match\", \"message\": \"...\"}` body, not\na verdict with everything zeroed out.\n\n**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\npool decrements **1** regardless of endpoint weight. Anonymous callers consume one\nfree slot per IP (per-product daily free limits apply — check remaining via\n`/geocode-credits`).\n","operationId":"geocode","parameters":[{"$ref":"#/components/parameters/Password"},{"name":"country","in":"query","required":true,"schema":{"type":"string","example":"usa"}},{"name":"q","in":"query","schema":{"type":"string"},"description":"Single-line free-text address, parsed into components with the `/validate` parser. Works for every supported country. Explicit fielded parameters, when present, take precedence."},{"name":"street","in":"query","required":false,"schema":{"type":"string"},"description":"Optional for every country, including USA/CAN. Omitting it degrades the match to a locality/postcode tier rather than failing."},{"name":"hno","in":"query","schema":{"type":"string","description":"House number"}},{"name":"city","in":"query","schema":{"type":"string"},"description":"City or locality (USA/CAN style). Optional — a single-line `q` or `postalcode` alone can still resolve a match."},{"name":"town","in":"query","schema":{"type":"string"},"description":"Alternative to `city` for some countries. Optional."},{"name":"state","in":"query","schema":{"type":"string"},"description":"State (USA) or province (Canada). Optional — omitting it does not fail the gate, though it can widen the fallback tier."},{"name":"postalcode","in":"query","schema":{"type":"string"},"description":"Postcode. The aliases `postcode`, `zip`, `zipcode`, `zip_code` and `postal_code` are also accepted; `postalcode` wins when several are sent."},{"name":"sublocality","in":"query","schema":{"type":"string"},"description":"Administrative tier below the city — Vietnamese phường/xã, Indonesian kelurahan, Thai tambon, Philippine barangay. Aliases: `ward`, `subdistrict`. It narrows the match and can never veto one: a value we do not hold returns the same result as omitting it. Wired for `vnm`; accepted and ignored elsewhere."},{"name":"db_version","in":"query","schema":{"type":"string"},"description":"Ignored. Reference DBs are configured at server startup via ref_dbs.json under GEOCODE_REF_DB_ROOT."}],"responses":{"200":{"description":"Geocode result — a whitelist of geocoding-only fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForwardGeocodeResponse"},"examples":{"rooftop":{"summary":"Rooftop match (DEU)","value":{"lat":52.538189,"lng":13.412664,"accuracy_type":"rooftop","point_coordinate":true,"standardized":{"street":"Schönhauser Allee","house_number":"36","postcode":"10435","city":"Berlin","country":"deu"},"formatted_address":"Schönhauser Allee 36\n10435 Berlin\nGERMANY"}},"arrivalPointWithDisclosure":{"summary":"Arrival point + input disclosure (IND)","value":{"lat":19.07283,"lng":72.88261,"accuracy_type":"arrival_point","point_coordinate":true,"standardized":{"street":"Linking Road","house_number":"84","postcode":"400050","city":"Mumbai","country":"ind"},"formatted_address":"84 Linking Road\nMumbai 400050\nINDIA","arrival_point":{"lat":19.07283,"lng":72.88261},"input_modified":["street"]}},"gbr":{"summary":"GBR match (attribution + UPRN) — served from https://paf.acuris-geo.com, not api.acuris-geo.com","value":{"lat":51.507322,"lng":-0.127647,"accuracy_type":"rooftop","point_coordinate":true,"standardized":{"street":"Downing Street","house_number":"10","postcode":"SW1A 2AA","city":"London","country":"gbr"},"formatted_address":"10 Downing Street\nLondon\nSW1A 2AA","attribution":"Contains OS data © Crown copyright and database right 2026","uprn":"10033589054"}},"prtHouseNumberNotHeld":{"summary":"House number not in the reference data, placed between neighbours (PRT; abridged)","value":{"lat":38.711001,"lng":-9.395425,"accuracy_type":"street_interpolated","point_coordinate":false,"standardized":{"street":"AVENIDA DE PORTUGAL","house_number":"46","city":"ESTORIL","country":"prt"},"formatted_address":"AVENIDA DE PORTUGAL 46\nESTORIL\nPORTUGAL","reasons":["house_number_unconfirmed","house_number_not_in_reference"],"nearby_house_numbers":{"requested":"46","parity":"even","before":{"hno":"44","lat":38.71059,"lng":-9.395437,"accuracy":"rooftop","has_coordinates":true},"after":{"hno":"50","lat":38.711824,"lng":-9.395401,"accuracy":"rooftop","has_coordinates":true},"pin_between":["44","50"],"same_parity_available":["32","38","40","44","50","50A","86"],"total_doors":113,"coordinated_doors":113}}},"prtCityOnly":{"summary":"City only — labelled approximate point (PRT)","value":{"lat":38.709801,"lng":-9.395957,"accuracy_type":"locality_centroid","point_coordinate":false,"standardized":{"city":"Estoril","country":"prt"},"formatted_address":"","reasons":["street_not_matched","postcode_not_matched","street_missing"],"approximate":true,"resolved_level":"locality","resolved_name":"Estoril"}}}}}},"400":{"description":"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":{"description":"Invalid key, no transaction balance, or anonymous geocode limit reached.\nKey-level 403s: `{\"error\": \"key_blocked\", \"message\"}` when the\nAPI key has been blocked (the `message` says why), and `{\"error\": \"ip_not_allowed\",\n\"message\", \"ip\"}` when the key is restricted to approved source IP addresses and\nthis request came from another one (`ip` is the address we saw). Source-IP\nrestriction is optional and set up per key on request via support.\n"},"404":{"description":"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`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForwardGeocodeErrorBody"},"examples":{"prtStreetType":{"summary":"Street not in the town, another street type is (PRT)","value":{"error":"no_match","message":"Street 'Rua de Portugal' not found in Estoril; did you mean Avenida de Portugal?","reasons":["street_type_mismatch","street_not_found"],"did_you_mean":[{"street":"Avenida de Portugal","city":"Estoril","doors":114,"match":"street_type"}]}},"prtNoCity":{"summary":"Street sent without a city, held in several towns (PRT; abridged, the live list has 6 entries)","value":{"error":"no_match","message":"Street 'Rua Augusta' exists in several localities; add the city or the postcode","reasons":["street_found_in_multiple_localities","city_missing"],"did_you_mean":[{"street":"Rua Augusta","city":"Lisboa","municipality":"Lisboa","doors":394},{"street":"Rua Augusta","city":"Cuba","municipality":"Cuba","doors":215}],"did_you_mean_truncated":true}}}}}},"422":{"description":"Input could not be interpreted (e.g. neither a string nor a fielded object). Same `{\"error\": \"no_match\", \"message\": \"...\"}` shape as 404.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForwardGeocodeErrorBody"}}}},"429":{"$ref":"#/components/responses/RateLimitExceeded"},"500":{"description":"Internal error during geocoding. Body: `{\"error\": \"Internal error\"}` — the real cause is logged server-side, never echoed to the caller."},"503":{"description":"Reference database not available, or another engine-level failure."},"504":{"description":"Geocode lookup timed out."}}}},"/geocode-usa":{"get":{"tags":["Geocoding"],"summary":"Geocode (United States shorthand)","description":"Same as `/geocode?country=usa` with `city` and `state` parameters.","operationId":"geocodeUsa","parameters":[{"$ref":"#/components/parameters/Password"},{"name":"street","in":"query","required":true,"schema":{"type":"string"}},{"name":"hno","in":"query","schema":{"type":"string"}},{"name":"city","in":"query","required":true,"schema":{"type":"string"}},{"name":"state","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Geocode result with coordinates and `accuracy_type` precision tier.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeocodeResponse"}}}},"400":{"description":"Missing parameters"},"403":{"description":"Limit or transaction balance.\nKey-level 403s: `{\"error\": \"key_blocked\", \"message\"}` when the\nAPI key has been blocked (the `message` says why), and `{\"error\": \"ip_not_allowed\",\n\"message\", \"ip\"}` when the key is restricted to approved source IP addresses and\nthis request came from another one (`ip` is the address we saw). Source-IP\nrestriction is optional and set up per key on request via support.\n"},"404":{"description":"Address not found. Body carries `match_type: no_match`, zeroed `match_score`, and a full-false `match_components`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeocodeErrorBody"}}}},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/reverse":{"get":{"tags":["Geocoding"],"summary":"Reverse geocode (coordinates → nearest address)","description":"Finds the nearest known address to a given `lat`/`lng` within `radius_m` metres\nfrom the reference database. Results are sorted by distance ascending and include\na `distance_m` field.\n\n**Credits:** Stripe-plan keys are charged a flat **1 transaction per request**\n(`reverse=1`), regardless of `limit`. Trial/dev keys are charged **1 transaction per\nreturned address**, pre-capped to the remaining balance so the call never\noverdraws. `units_charged` in the response echoes the number of addresses\nreturned (which equals the trial-key debit; the Stripe debit is always 1).\n\n**RapidAPI note:** For traffic routed through the RapidAPI gateway, `limit`\nis forced server-side to **1** so that one HTTP request maps to exactly one\n`Geocoding Lookups` meter decrement. The `limit` query parameter is silently\nignored for RapidAPI clients.\n\n**Availability:** Available for ~160 countries. Availability is detected per\ncountry from the reference DB — any DB carrying an `(RT_LAT, RT_LNG)`-leading\nrooftop-coordinate index serves reverse, and the set expands automatically when\nan index lands. Countries without it return **501** `reverse_not_available` —\ncurrently including `che`, `jpn`, `tur`, `kor`, `isr`, `arg`, `chl`, `vnm`,\n`pak`, `phl`, `hkg`; `gbr` reverse is served via the PAF host.\n","operationId":"reverseGeocode","parameters":[{"name":"country","in":"query","required":true,"description":"Country code (see **Country codes** above).","schema":{"type":"string","example":"usa"}},{"name":"lat","in":"query","required":true,"schema":{"type":"number","format":"float","minimum":-90,"maximum":90,"example":38.8977}},{"name":"lng","in":"query","required":true,"schema":{"type":"number","format":"float","minimum":-180,"maximum":180,"example":-77.0365}},{"name":"radius_m","in":"query","description":"Search radius in metres. Capped at `50000`.","schema":{"type":"integer","minimum":1,"maximum":50000,"default":500}},{"name":"limit","in":"query","description":"Max results to return. Capped at `10`.\n**Ignored for RapidAPI traffic** — forced to `1` to align with the\nper-request `Geocoding Lookups` meter.\n","schema":{"type":"integer","minimum":1,"maximum":10,"default":1}}],"responses":{"200":{"description":"Match found. When `limit=1` (default) the body is a single result;\nwhen `limit>1` the body wraps `results: []` with `count`.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReverseResponse"},"examples":{"singleResult":{"summary":"Default limit=1 (flat result)","value":{"country":"usa","lat":38.897653,"lng":-77.03655,"distance_m":7,"accuracy_type":"rooftop","match_type":"rooftop","match_score":1.0,"input_corrected":false,"street":"PENNSYLVANIA AVE NW","hno":"1600","city":"WASHINGTON","state":"DC","zip":"20500","query":{"lat":38.8977,"lng":-77.0365,"radius_m":200},"free_remaining":8}},"multiResult":{"summary":"limit=3 (envelope with results array)","value":{"count":2,"country":"usa","match_type":"rooftop","match_score":1.0,"input_corrected":false,"query":{"lat":38.8977,"lng":-77.0365,"radius_m":200},"results":[{"country":"usa","lat":38.897653,"lng":-77.03655,"distance_m":7,"accuracy_type":"rooftop","match_type":"rooftop","match_score":1.0,"input_corrected":false,"street":"PENNSYLVANIA AVE NW","hno":"1600","city":"WASHINGTON","state":"DC","zip":"20500"},{"country":"usa","lat":38.898123,"lng":-77.034339,"distance_m":193,"accuracy_type":"rooftop","match_type":"rooftop","match_score":1.0,"input_corrected":false,"street":"PENNSYLVANIA AVE NW","hno":"1500","city":"WASHINGTON","state":"DC","zip":"20005"}]}}}}}},"400":{"description":"Missing/invalid country, lat, lng, radius_m, or limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"401":{"description":"Invalid or inactive API key"},"403":{"description":"Insufficient transaction balance, trial expired, or anonymous limit reached.\nKey-level 403s: `{\"error\": \"key_blocked\", \"message\"}` when the\nAPI key has been blocked (the `message` says why), and `{\"error\": \"ip_not_allowed\",\n\"message\", \"ip\"}` when the key is restricted to approved source IP addresses and\nthis request came from another one (`ip` is the address we saw). Source-IP\nrestriction is optional and set up per key on request via support.\n"},"404":{"description":"No address within `radius_m`. Body includes `match_type: no_match` and `reasons: [\"no_address_within_radius\"]`.","content":{"application/json":{"schema":{"type":"object","properties":{"match_type":{"type":"string","example":"no_match"},"match_score":{"type":"number","example":0.0},"input_corrected":{"type":"boolean","example":false},"reasons":{"type":"array","items":{"type":"string"},"example":["no_address_within_radius"]},"country":{"type":"string"},"query":{"type":"object","properties":{"lat":{"type":"number"},"lng":{"type":"number"},"radius_m":{"type":"integer"}}}}}}}},"429":{"$ref":"#/components/responses/RateLimitExceeded"},"501":{"description":"Reverse geocoding not yet enabled for this country (spatial index missing).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"reverse_not_available"},"message":{"type":"string"}}}}}},"503":{"description":"Reference database unavailable on this deployment."}}}},"/geocode-credits":{"get":{"tags":["Geocoding"],"summary":"Geocode free tier or key balance","description":"Without a key: returns `free_remaining` anonymous geocodes for this IP.\nWith a valid key (header or `?key=`): the keyed response also returns `balance`,\n`validation_credits`, `geocode_credits`, `credits`, and `trial_expired`;\n`free_remaining` is null.\n","operationId":"geocodeCredits","parameters":[{"$ref":"#/components/parameters/Password"}],"responses":{"200":{"description":"Remaining anonymous free transactions and (when an API key is provided) the registered key's geocode transaction balance.","content":{"application/json":{"schema":{"type":"object","properties":{"free_remaining":{"type":"integer","nullable":true,"example":10},"balance":{"type":"integer","description":"Present when valid key supplied. Equals `geocode_credits`."},"validation_credits":{"type":"integer","description":"Present when valid key supplied."},"geocode_credits":{"type":"integer","description":"Present when valid key supplied."},"credits":{"type":"integer","description":"Combined transaction total; present when valid key supplied."},"trial_expired":{"type":"boolean","description":"True when the key's trial window has lapsed (all balances read 0); present when valid key supplied."}}}}}},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/check-key":{"get":{"tags":["Account"],"summary":"Check API key","description":"Returns whether the key is active and the current transaction balance. The\nkey may be supplied via `X-Acuris-Key`, `Authorization: Bearer`,\n`X-API-Key`, or the `key` query parameter — only one method is needed.\n","operationId":"checkKey","parameters":[{"name":"key","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Key validity and remaining transaction balance for the supplied API key.","content":{"application/json":{"schema":{"oneOf":[{"type":"object","required":["valid","credits"],"properties":{"valid":{"type":"boolean","example":true},"credits":{"type":"integer","description":"Validation + geocode transactions combined. The email and phone pools are separate — see `/account/balances` for all four."},"validation_credits":{"type":"integer","description":"Remaining validation-family trial transactions. Reported as 0 once the trial has expired."},"geocode_credits":{"type":"integer","description":"Remaining geocode-family trial transactions. Reported as 0 once the trial has expired."},"key_type":{"type":"string","enum":["trial","subscription"],"description":"Whether the key is a trial key or a Stripe subscription key."},"key_class":{"type":"string","nullable":true,"example":"free_av_geo","description":"`\"free_av_geo\"` for a verified free-tier account (see **Free tier (verified account)** above) — on these keys `validation_credits` / `geocode_credits` above are a frozen signup-time snapshot, not a live balance; use `free_remaining` instead. `null`/absent for every other key shape (legacy trial, dev key, Stripe subscription)."},"free_remaining":{"type":"integer","nullable":true,"example":947,"description":"Present only when `key_class` is `\"free_av_geo\"`: today's remaining count against the shared 1,000/day allowance (one number for validate, geocode, reverse and suggest together, not one per product). Resets at UTC midnight. UK PAF usage is never included here — see `uk_trial`."},"free_daily_limit":{"type":"integer","nullable":true,"example":1000,"description":"Present only when `key_class` is `\"free_av_geo\"`. Always 1000."},"uk_trial":{"type":"object","nullable":true,"description":"UK Royal Mail PAF allowance (`cap`, `used`, `remaining`), capped at **5 per UTC day** for a registered key, resetting at UTC midnight — separate from, and never combined with, `free_remaining`/`credits` above. Present for trial and `free_av_geo` keys alike (any key without a paid UK transaction pack); null for subscribers with a UK pack.","properties":{"cap":{"type":"integer","example":5},"used":{"type":"integer"},"remaining":{"type":"integer"}}},"uk_eval":{"type":"object","description":"Free UK evaluation under the UK PAF Evaluation Terms (trial and free keys).","properties":{"mode":{"type":"string","enum":["accepted","legacy","required","exempt"],"description":"`accepted` = terms accepted; `legacy` = key issued before acceptance was required (no acceptance needed until its end date); `required` = must accept before UK lookups work; `exempt` = internal or paid UK key, no evaluation window."},"accepted_at":{"type":"string","nullable":true,"description":"When the UK PAF Evaluation Terms were accepted for this key (`YYYY-MM-DD HH:MM:SS`, UTC), or null."},"uk_eval_expires_at":{"type":"string","nullable":true,"description":"End of this key's free UK evaluation (UTC). Accepted keys: acceptance + 90 days (or the key's own expiry if earlier). Legacy keys: the later of creation + 90 days and the start of enforcement + 14 days. Null when exempt or `required`."},"days_remaining":{"type":"integer","nullable":true,"description":"Whole days left in the UK evaluation (0 once ended)."}}},"plan":{"type":"string","description":"Stripe keys only — the subscribed plan identifier."},"shared_primary_pool":{"type":"boolean","description":"Stripe keys only — `true` when validate and geocode draw from one combined allowance."},"trial_expires_at":{"type":"string","nullable":true,"description":"Trial expiry timestamp (or null if not on a trial)."},"trial_expired":{"type":"boolean","description":"True once the trial window has elapsed; the trial transaction pools then read 0."}}},{"type":"object","properties":{"valid":{"type":"boolean","example":false},"message":{"type":"string"}}}]}}}},"400":{"description":"No key provided"},"401":{"description":"Invalid key"},"402":{"description":"Stripe subscription canceled or transaction pack expired. Body: `{\"valid\": false, \"message\": \"...\"}`."}}}},"/suggest":{"get":{"tags":["Suggest"],"summary":"Address suggestions (autocomplete)","description":"Autocomplete/typeahead. Returns ranked standardized addresses (with\n`formatted_address`, and `lat`/`lng` whenever the reference row carries\na coordinate — never invented) for the partial input `q` (or `prefix`)\nand `country`.\n\n**Authentication is required — there is no anonymous access.** A caller\nmust present *either*:\n  - a paid API key (Stripe `X-Acuris-Key` / `Authorization: Bearer`,\n    `X-API-Key`, or RapidAPI gateway) — full access, billed against the\n    key's own transaction pool; or\n  - a short-lived **widget token** (`X-Acuris-Widget-Token` header, or\n    `?t=`) minted by `/widget/token` — origin-locked to `acuris-geo.com`\n    pages, so not usable by third-party integrations (partners use API\n    keys). Widget callers are capped at 15 results and a per-token call\n    quota.\n\nRequests with neither are rejected: `403` (no widget origin / no token)\nor `401` (token invalid, expired, or quota exhausted).\n\n**Metering here depends on the `AV_GEO_REQUIRE_SIGNUP` launch flag** (see **Free tier\n(verified account)** above for the full explanation — this endpoint never draws from the\nUK daily cap described there, on either side of the flag, and draws from the 1,000/day\nfree-tier allowance only once the flag is on):\n  - **As of this writing, flag off in production:** a genuinely valid API key is\n    completely exempt from metering. Anonymous widget-token callers are bounded only by a\n    per-IP flask-limiter soft cap of **5/second, 60/minute, 500/day** (per gunicorn\n    worker — a first-line burst backstop, not an authoritative cross-fleet limit); the\n    handler does not authenticate against a quota pool or decrement one in this state.\n  - **Once the flag is on:** a registered key (any class except the policy-exempt\n    `stripe`/`integration`/`partner`) draws from the same shared recurring\n    **1,000/day** allowance as `/validate`/`/geocode`/`/reverse` (`free_limit_reached`, `403`, once exhausted); anonymous callers are capped at\n    **40/day per IP** instead (`rate_limit_exceeded`, `429`, once exhausted), and the\n    flask-limiter decorator's daily figure drops from 500 to 40 at the same moment as a\n    redundant first-line backstop.\n`country: \"gbr\"` requests carry one further, independent per-IP velocity cap\n(`PAF_SUGGEST_IP_RPM`, **600/minute** by default — 10x that for a genuinely valid, non-test\nAPI key; allowlisted keys exempt), which degrades to an empty result set\n(`{\"suggestions\": [], \"limit\": \"reached\"}`) rather than an error, on either side of the flag.\n\n**UK note:** `country: \"gbr\"` is served exclusively from\n`https://paf.acuris-geo.com` (identical path, parameters, and auth).\nRequests for `gbr` sent to `api.acuris-geo.com` return **400**\n`{\"error\": \"country_not_served_by_this_endpoint\", \"country\": \"gbr\",\n\"use_instead\": \"https://paf.acuris-geo.com\"}`.\n\n**Postcode-first input:** the query may lead with (or be) a postal\ncode. GBR: a full or partial postcode returns every delivery point at\nthat postcode, each labelled with `building_name` /\n`organisation_name` / `department`; a premise name may precede the\npostcode (`Gate House DL12 0NQ`). DEU / FIN / SWE / NLD / CAN: a\nleading postcode scopes the street search (`67549 Eckenbert`,\n`M5V 3L9`). JPN: a postcode returns chōme suggestions; then pass\n`zip`, `oaza`, `chome` with the house-number keystrokes to get\nbanchi-gō lot suggestions.\n\nSuggestions do not carry `udprn` / `uprn` / `county`. To obtain the\nRoyal Mail / OS identifiers for a chosen suggestion, submit it to\n`/validate` (returns `uprn`, `udprn`) or use `/postcode-lookup`.\n\nSuggestion `lat`/`lng` are the reference row's own point, unrefined.\n`/validate` may refine that point for the same address (France: a\npoint lying just outside its building is moved onto the building\nfootprint, by at most 8 m, and the response carries\n`coord_snapped: true`). List rows never carry that refinement; for\nthe refined point, submit the chosen suggestion to `/validate`.\n\nTypeahead is tuned and verified for **19 countries** today — GBR, USA,\nCAN, DEU, AUT, CHE, FRA, BEL, NLD, LUX, DNK, SWE, FIN, IRL, PRT, ESP,\nSGP, JPN, HKG. Any `/geocode` country code is accepted; countries\noutside this set may return empty results.\n","operationId":"suggest","security":[{"acurisKeyHeader":[]},{"bearerAuth":[]},{"apiKeyHeader":[]}],"parameters":[{"name":"q","in":"query","schema":{"type":"string"},"description":"Partial address input. Omitting `q` (or `country`) returns `200` with an empty `suggestions` array rather than an error (typeahead-friendly)."},{"name":"prefix","in":"query","schema":{"type":"string"},"description":"Alias of `q`."},{"name":"country","in":"query","required":true,"schema":{"type":"string"},"description":"Country code (see **Country codes** above). Omitting it returns `200` with an empty `suggestions` array; an unknown code returns `400`."},{"name":"limit","in":"query","schema":{"type":"integer","default":10,"maximum":50}},{"name":"state","in":"query","schema":{"type":"string"},"description":"USA only: two-letter state filter (e.g. `VT`)."},{"name":"lat","in":"query","schema":{"type":"number"},"description":"Optional location bias (with `lng`): results re-rank nearest-first from this point. Without it, ranking is unbiased."},{"name":"lng","in":"query","schema":{"type":"number"},"description":"Optional location bias — see `lat`."},{"name":"zip","in":"query","schema":{"type":"string"},"description":"JPN only (stage 2): the postcode of the chosen chōme."},{"name":"oaza","in":"query","schema":{"type":"string"},"description":"JPN only (stage 2): the ōaza of the chosen chōme, as returned in `jpn_oaza_norm`."},{"name":"chome","in":"query","schema":{"type":"string"},"description":"JPN only (stage 2): the chōme number, as returned in `jpn_chome`. With `zip` and `oaza` set, `q` carries the house-number keystrokes and the response lists banchi-gō lots."}],"responses":{"200":{"description":"Ranked list of address suggestions matching the partial input.","content":{"application/json":{"schema":{"type":"object","properties":{"suggestions":{"type":"array","items":{"$ref":"#/components/schemas/SuggestItem"}},"hint":{"type":"string","description":"Optional guidance shown when `suggestions` is empty (e.g. the caller typed only a house number). For a country where autocomplete is not available yet, an empty list carries a hint saying so (e.g. \"Address autocomplete is not available for Vietnam yet. Address validation (/validate) is supported.\")."},"autocomplete_supported":{"type":"boolean","description":"Present (and `false`) only on an empty answer for a country where address autocomplete is not available yet; use `POST /validate` for that country instead. Absent on every other response. The status stays 200 and any rows the engine does find are still returned."},"limit":{"type":"string","description":"Set to `\"reached\"` when a velocity/abuse cap emptied the result set; back off and retry after ~60s."}}}}}},"400":{"description":"Unsupported country — body `{\"error\": \"Unsupported country\"}`. Also\nreturned for `country: gbr` on this host (body:\n`country_not_served_by_this_endpoint` with `use_instead` — see the\nUK note above).\n"},"401":{"description":"Widget token invalid, expired, or quota exhausted."},"403":{"description":"No paid key and no valid widget token / non-widget origin.\nKey-level 403s: `{\"error\": \"key_blocked\", \"message\"}` when the\nAPI key has been blocked (the `message` says why), and `{\"error\": \"ip_not_allowed\",\n\"message\", \"ip\"}` when the key is restricted to approved source IP addresses and\nthis request came from another one (`ip` is the address we saw). Source-IP\nrestriction is optional and set up per key on request via support.\n"},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/widget/token":{"get":{"tags":["Suggest"],"summary":"Mint a widget token (Acuris site pages only)","description":"Mints the short-lived token that authenticates the on-page address\nwidget's `/suggest` calls. **Origin-locked to `acuris-geo.com` pages**\n— third-party integrations cannot call it and use API keys instead.\nEach token carries a per-token call quota; minting is velocity-capped\nper IP.\n","operationId":"widgetToken","security":[],"responses":{"200":{"description":"Token minted.","content":{"application/json":{"schema":{"type":"object","required":["token","expires_at"],"properties":{"token":{"type":"string"},"expires_at":{"type":"integer","description":"Unix expiry timestamp."}}}}}},"403":{"description":"Origin is not an `acuris-geo.com` page."},"429":{"description":"Per-IP minting velocity cap reached."}}}},"/api/country-config":{"get":{"tags":["Config"],"summary":"Form field order and examples","description":"Returns UPU-oriented field order and optional examples per country for building address forms.","operationId":"countryConfig","responses":{"200":{"description":"Per-country form field ordering and example values for building address-entry UIs.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/stripe/create-checkout-session":{"post":{"tags":["Billing"],"summary":"Start a Stripe Checkout subscription","description":"Creates a Stripe-hosted Checkout Session for one of the self-serve\nplans and returns the redirect URL. After successful payment Stripe\nsends a webhook that provisions a Direct API key under the verified\nemail and emails it to the customer; the key authenticates subsequent\nrequests via `X-Acuris-Key` (or `Authorization: Bearer`).\n\nMost plans are monthly subscriptions (Stripe `mode=subscription`). The\n`uk_pack_*` and `txn_pack_*` plans are one-off credit-pack purchases\n(Stripe `mode=payment`).\n","operationId":"stripeCreateCheckoutSession","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["plan"],"properties":{"plan":{"type":"string","description":"Plan identifier. `uk_pack_*` and `txn_pack_*` plans are\none-off credit-pack purchases (Stripe `mode=payment`); all\nothers are monthly subscriptions.\n","enum":["growth_na","pro_na","growth_intl","pro_intl","growth_dach","pro_dach","uk_pack_250","uk_pack_1250","uk_pack_5000","uk_pack_15000","uk_pack_35000","txn_pack_na_2500","txn_pack_na_10000","txn_pack_na_50000","txn_pack_na_250000","txn_pack_na_1000000","txn_pack_intl_1000","txn_pack_intl_5000","txn_pack_intl_25000","txn_pack_intl_100000","txn_pack_intl_500000","txn_pack_dach_1000","txn_pack_dach_5000","txn_pack_dach_25000","txn_pack_dach_100000","txn_pack_dach_500000","email_starter","email_growth","email_pro","email_scale"]},"customer_email":{"type":"string","format":"email","description":"Optional. Pre-fills the Checkout email field when supplied.\nStripe collects the email itself if omitted (the typical case\nfor marketing-page \"Get started\" buttons that POST `{plan}`\nonly). The actually-billed address is whichever the customer\nenters and verifies on the Stripe page; that one is used for\nprovisioning regardless of what was sent here.\n"}}}}}},"responses":{"200":{"description":"Checkout session created. Redirect the customer to `checkout_url`.","content":{"application/json":{"schema":{"type":"object","required":["checkout_url"],"properties":{"checkout_url":{"type":"string","format":"uri","example":"https://checkout.stripe.com/c/pay/cs_test_..."}}}}}},"400":{"description":"Invalid plan name or malformed email."},"500":{"description":"The plan is recognised but no Stripe price is configured for it on\nthis instance (`plan_price_not_configured`).\n"},"502":{"description":"Stripe API call failed."},"503":{"description":"Stripe billing not configured on this instance."}}}},"/postcode-lookup":{"post":{"tags":["Postcode lookup"],"summary":"List every address at a UK postcode (Royal Mail PAF)","description":"Returns every delivery point at a given UK postcode, backed by the official\nRoyal Mail Postcode Address File (PAF). **UK-only** (`country: \"gbr\"`). Each\naddress carries the Royal Mail `udprn`, the Ordnance Survey `uprn` (with its\n`uprn_match_m` match distance), the full printable PAF element set\n(`post_town`, dependent localities, `address_lines`, `administrative_county`),\nand rooftop coordinates when available.\n\n**UK host:** call this endpoint on `https://paf.acuris-geo.com`. Requests\nsent to `api.acuris-geo.com` return **400**\n`{\"error\": \"country_not_served_by_this_endpoint\", \"use_instead\": \"https://paf.acuris-geo.com\"}`.\n\nCharges **1 validation transaction per call**, regardless of how many addresses\nare returned. Anonymous callers use the free tier (per-IP daily cap). The\nnumber of addresses returned is capped (default 100); when the cap is hit\nthe response sets `truncated: true`. A per-IP velocity cap also applies to\nprotect the licensed dataset.\n","operationId":"postcodeLookup","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["postcode"],"properties":{"postcode":{"type":"string","example":"SW1A 2AA"},"country":{"type":"string","default":"gbr","description":"Only `gbr` is supported."}}}}}},"responses":{"200":{"description":"All addresses at the postcode.","content":{"application/json":{"schema":{"type":"object","properties":{"postcode":{"type":"string"},"country":{"type":"string"},"count":{"type":"integer"},"truncated":{"type":"boolean","description":"Present and `true` when the result set was capped."},"addresses":{"type":"array","items":{"$ref":"#/components/schemas/PostcodeAddress"}},"validation_credits_remaining":{"type":"integer","description":"Present only for authenticated (keyed) callers. Omitted for anonymous free-tier requests."},"geocode_credits_remaining":{"type":"integer","description":"Present only for authenticated (keyed) callers. Omitted for anonymous free-tier requests."}}}}}},"400":{"description":"Missing postcode, or a non-UK `country`."},"401":{"description":"Invalid or inactive API key."},"403":{"description":"Insufficient validation transactions, or expired trial.\nKey-level 403s: `{\"error\": \"key_blocked\", \"message\"}` when the\nAPI key has been blocked (the `message` says why), and `{\"error\": \"ip_not_allowed\",\n\"message\", \"ip\"}` when the key is restricted to approved source IP addresses and\nthis request came from another one (`ip` is the address we saw). Source-IP\nrestriction is optional and set up per key on request via support.\n"},"404":{"description":"Postcode not found."},"429":{"description":"Free-tier daily cap or per-IP velocity cap reached."}}}},"/v1/validate":{"post":{"tags":["Versioned aliases (v1)"],"summary":"Validate an address (versioned alias)","description":"Versioned alias of `POST /validate` — same handler, same request/response\nshapes, same billing. Accepts a single-line address string **or** structured\nfields in `input`, plus required `country`. The API key may be supplied in the\n`X-Acuris-Key` header or in the JSON body as `key`.\n\n**Credits:** `validate=1` Stripe-plan transaction per call. The trial pool\ndecrements **1** regardless. Anonymous callers consume one free slot per IP\n(per-product daily free limits apply — check remaining via `/validate-credits`;\nanonymous access is rate-limited per IP).\n","operationId":"validateAddressV1","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateRequest"},"examples":{"oneLine":{"summary":"Single-line (USA)","value":{"input":"1600 Pennsylvania Ave NW, Washington, DC 20500","country":"usa"}},"keyed":{"summary":"With API key in body","value":{"input":"Eckenbertstraße 31, 67549 Worms","country":"deu","key":"YOUR_API_KEY"}}}}}},"responses":{"200":{"description":"Validation succeeded **or** partial fallback returned. Inspect `partial_match`\nto distinguish: when `true`, the address was not fully confirmed — either the\nstreet resolved but not the house number (`street_interpolated` /\n`street_centroid`), or the SEG cascade inferred a `postcode_centroid` /\n`locality_centroid` / `admin_centroid` for `lat`/`lng`. `reasons` states what\ncould not be pinned down.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateResponse"}}}},"400":{"description":"Missing country, unsupported country, or bad payload. A missing `street`/`city`\nonly surfaces as 400 when the SEG cascade also has no centroid to offer — when SEG\ncan supply one, a 200 with `partial_match: true` is returned instead. Netherlands:\n`postcode` + `house_number` with no street and no city is never a 400 (see the\nNetherlands postcode + house number note in the `/validate` description). Portugal: a\nstreet without a city is a 404 (see below), not a 400; a city-only request\nreturns a labelled approximate 200 (`approximate: true`) when the place is\nfound. Also returned\nfor `country: gbr` requests sent to this host — the UK is served from\n`https://paf.acuris-geo.com` (body: `country_not_served_by_this_endpoint`\nwith `use_instead`).\n\nAlso returned for **non-deliverable input** (PO Box, Postfach, Rural Route, …):\nthe body then carries the full match-quality contract with\n`match_type: \"non_deliverable\"`, `non_deliverable_type` (e.g. `po_box`) and\n`reasons: [\"non_deliverable_address\"]` — see `MatchType`. With `iso20022: true`\nthe same input is instead accepted as a labelled 200 (`non_deliverable_type` on\nthe success body).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"401":{"description":"Invalid or inactive API key"},"402":{"description":"Payment required (Stripe-plan keys): `subscription_canceled`,\n`pack_expired` (body includes `expired_at`), or `credits_wrong_region`\n(body includes `country`, `have_regions`, `needed`).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"403":{"description":"Insufficient transaction balance. Body shapes: `{\"error\": \"quota_exceeded\", \"pool\", \"limit\",\n\"used\", \"message\"}` for exhausted plan quota; trial keys return\n`{\"error\": \"insufficient_credits\" | \"trial_expired\", \"key_accepted\": true,\n\"credits_remaining\", \"validation_credits_remaining\", \"geocode_credits_remaining\"}`.\nKey-level 403s: `{\"error\": \"key_blocked\", \"message\"}` when the\nAPI key has been blocked (the `message` says why), and `{\"error\": \"ip_not_allowed\",\n\"message\", \"ip\"}` when the key is restricted to approved source IP addresses and\nthis request came from another one (`ip` is the address we saw). Source-IP\nrestriction is optional and set up per key on request via support.\n"},"404":{"description":"Address not found **and** SEG cascade had no centroid to offer. Body includes\n`match_type: no_match`, `suggestions` (if any near-misses scored ≥ 0.5), and `reasons`.\nWhen SEG _does_ have a centroid, the response is 200 with `partial_match: true`\ninstead of 404.\n\nPortugal (`country: prt`): `reasons` names the cause (e.g. `city_not_found`,\n`street_not_found`, `street_found_in_multiple_localities` + `city_missing`,\n`locality_ambiguous` + `street_missing`), and `did_you_mean` lists what the input\nmost likely meant (never applied automatically) — alongside the unchanged\n`suggestions`. A street sent without a city returns this 404 (with the candidate\ntowns in `did_you_mean`) rather than a 400, unless exactly one town holds the\nstreet, in which case that town is used and disclosed as a `City` correction.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateErrorBody"}}}},"422":{"description":"Input could not be parsed (e.g. `input` was neither a string nor an object).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateErrorBody"}}}},"429":{"$ref":"#/components/responses/RateLimitExceeded"},"504":{"description":"Validation timed out","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}}}}},"/v1/validate/batch":{"post":{"tags":["Versioned aliases (v1)"],"summary":"Validate up to 200 addresses in one request (versioned alias)","description":"Synchronous bulk validation. Each row is billed and matched exactly as a\nstandalone `POST /validate` call would be (`validate=1` transaction each). An\n**API key is required** — the free-tier per-IP allowance is for single\n`POST /validate` only.\n\nEvery row shares the top-level `country` unless the row is an object of the\nform `{\"input\": <input>, \"country\": \"usa\"}`, which overrides the country for\nthat row (letting you mix countries in one batch). For volumes above 200,\nsubmit an async job via `POST /validate/jobs` (up to 50,000 addresses).\n","operationId":"validateAddressBatchV1","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateBatchRequest"},"examples":{"sharedCountry":{"summary":"One country for all rows","value":{"country":"deu","addresses":["Eckenbertstraße 31, 67549 Worms",{"street":"Schönhauser Allee","house_number":"36","city":"Berlin","postcode":"10435"}]}},"mixedCountry":{"summary":"Per-row country override","value":{"addresses":[{"input":"1600 Pennsylvania Ave NW, Washington, DC 20500","country":"usa"},{"input":"Eckenbertstraße 31, 67549 Worms","country":"deu"}]}}}}}},"responses":{"200":{"description":"Per-row results, in request order. Each element is the same body a\nstandalone `POST /validate` would return (including per-row `error`\nobjects for rows that failed).\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateBatchResponse"}}}},"400":{"description":"`addresses` is not an array, is empty, or exceeds 200 entries (`batch_too_large`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"401":{"description":"API key required (`api_key_required`) — batch has no anonymous free tier.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"429":{"$ref":"#/components/responses/RateLimitExceeded"}}}},"/v1/geocode":{"post":{"tags":["Versioned aliases (v1)"],"summary":"Geocode an address (versioned alias, JSON body)","description":"Versioned alias of `GET /geocode` — same handler, same response shape, same\nbilling. Accepts the geocode parameters as a JSON body instead of a query\nstring (scalar body fields are folded onto the query params; query-string\nvalues win on collision). In addition to the fielded parameters, this alias\naccepts a single-line free-text address as `q`, which is parsed into\ncomponents with the same parser the `/validate` path uses (explicit fielded\nparams take precedence over the parsed line). `q` also works on\n`GET /geocode`; and `GET /v1/geocode` with the same query parameters as the\nunversioned route is accepted too.\n\n**Credits:** `geocode=1` Stripe-plan transaction per call. 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\ndecrements **1** regardless. Anonymous callers consume one free slot per IP\n(per-product daily free limits apply — check remaining via `/geocode-credits`;\nanonymous access is rate-limited per IP).\n","operationId":"geocodeV1","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["country"],"properties":{"country":{"type":"string","example":"usa"},"q":{"type":"string","description":"Single-line free-text address, parsed into components.","example":"1600 Pennsylvania Ave NW, Washington, DC 20500"},"street":{"type":"string"},"hno":{"type":"string","description":"House number"},"city":{"type":"string"},"town":{"type":"string","description":"Alternative to `city` for some countries"},"state":{"type":"string","description":"State (USA) or province (Canada)"},"postalcode":{"type":"string","description":"Postcode. The aliases `postcode`, `zip`, `zipcode`, `zip_code` and `postal_code` are also accepted; `postalcode` wins when several are sent."},"key":{"type":"string","description":"API key in the body (legacy; folded onto `?key=`). Header auth is preferred."},"db_version":{"type":"string","description":"Ignored. Reference DBs are configured at server startup via ref_dbs.json."}}},"examples":{"singleLine":{"summary":"Single-line via `q`","value":{"country":"usa","q":"1600 Pennsylvania Ave NW, Washington, DC 20500"}},"fielded":{"summary":"Structured fields","value":{"country":"deu","street":"Schönhauser Allee","hno":"36","city":"Berlin","postalcode":"10435"}}}}}},"responses":{"200":{"description":"Geocode result — a whitelist of geocoding-only fields. See `GET /geocode` for worked examples.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForwardGeocodeResponse"}}}},"400":{"description":"Missing/unsupported `country`, or neither `q` nor any fielded component supplied Portugal: also `Missing required field: street` for a city-only request whose place name is not found."},"403":{"description":"Invalid key, no transaction balance, or anonymous geocode limit reached.\nKey-level 403s: `{\"error\": \"key_blocked\", \"message\"}` when the\nAPI key has been blocked (the `message` says why), and `{\"error\": \"ip_not_allowed\",\n\"message\", \"ip\"}` when the key is restricted to approved source IP addresses and\nthis request came from another one (`ip` is the address we saw). Source-IP\nrestriction is optional and set up per key on request via support.\n"},"404":{"description":"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` (see `ForwardGeocodeErrorBody`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForwardGeocodeErrorBody"}}}},"422":{"description":"Input could not be interpreted. Same `{\"error\": \"no_match\", \"message\": \"...\"}` shape as 404.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForwardGeocodeErrorBody"}}}},"429":{"$ref":"#/components/responses/RateLimitExceeded"},"500":{"description":"Internal error during geocoding. Body: `{\"error\": \"Internal error\"}`."},"503":{"description":"Reference database not available, or another engine-level failure."},"504":{"description":"Geocode lookup timed out."}}}},"/v1/reverse":{"post":{"tags":["Versioned aliases (v1)"],"summary":"Reverse geocode (versioned alias, JSON body)","description":"Versioned alias of `GET /reverse` — same handler, same response shape, same\nbilling. Accepts `lat`/`lng`/`radius_m`/`limit`/`country` as a JSON body\ninstead of a query string (scalar body fields are folded onto the query\nparams; query-string values win on collision). Results are sorted by distance\nascending and include a `distance_m` field.\n\n**Credits:** Stripe-plan keys: flat `reverse=1` transaction per request, regardless\nof `limit`. Trial/dev keys: 1 transaction per returned address, pre-capped to the\nremaining balance. `units_charged` echoes the number of addresses returned\n(equals the trial-key debit; the Stripe debit is always 1).\n\n**Availability:** Available for ~160 countries. Detected per country from the\nreference DB (rooftop-coordinate index) and expands automatically; countries\nwithout it return **501** `reverse_not_available` — currently including\n`che`, `jpn`, `tur`, `kor`, `isr`, `arg`, `chl`, `vnm`, `pak`, `phl`,\n`hkg`; `gbr` reverse is served via the PAF host.\n\n`GET /v1/reverse` with the same query parameters as the unversioned route\nis also accepted.\n","operationId":"reverseGeocodeV1","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["country","lat","lng"],"properties":{"country":{"type":"string","example":"usa"},"lat":{"type":"number","format":"float","minimum":-90,"maximum":90,"example":38.8977},"lng":{"type":"number","format":"float","minimum":-180,"maximum":180,"example":-77.0365},"radius_m":{"type":"integer","minimum":1,"maximum":50000,"default":500,"description":"Search radius in metres. Capped at `50000`."},"limit":{"type":"integer","minimum":1,"maximum":10,"default":1,"description":"Max results to return. Capped at `10`.\n**Ignored for RapidAPI traffic** — forced to `1`.\n"}}},"examples":{"default":{"summary":"Nearest single address","value":{"country":"usa","lat":38.8977,"lng":-77.0365,"radius_m":200}}}}}},"responses":{"200":{"description":"Match found. When `limit=1` (default) the body is a single result;\nwhen `limit>1` the body wraps `results: []` with `count`.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReverseResponse"}}}},"400":{"description":"Missing/invalid country, lat, lng, radius_m, or limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}},"401":{"description":"Invalid or inactive API key"},"403":{"description":"Insufficient transaction balance, trial expired, or anonymous limit reached.\nKey-level 403s: `{\"error\": \"key_blocked\", \"message\"}` when the\nAPI key has been blocked (the `message` says why), and `{\"error\": \"ip_not_allowed\",\n\"message\", \"ip\"}` when the key is restricted to approved source IP addresses and\nthis request came from another one (`ip` is the address we saw). Source-IP\nrestriction is optional and set up per key on request via support.\n"},"404":{"description":"No address within `radius_m`. Body includes `match_type: no_match` and `reasons: [\"no_address_within_radius\"]`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReverseResponse"}}}},"429":{"$ref":"#/components/responses/RateLimitExceeded"},"501":{"description":"Reverse geocoding not available for this country (`reverse_not_available`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}}}}},"/geocode-uk":{"get":{"tags":["Geocoding"],"summary":"Geocode (United Kingdom shorthand)","description":"Backward-compatible wrapper for `/geocode?country=gbr`. Provide `town`,\n`street` and `hno`; matches against the Royal Mail PAF reference data and\nreturns rooftop coordinates plus the PAF `udprn` (Unique Delivery Point\nReference Number) and, when the address matches OS Open UPRN, the `uprn`\n(Unique Property Reference Number). These are surfaced as extra fields on\nthe `GeocodeResponse` body.\n\n**Credits:** This endpoint currently authenticates at the **default**\nStripe-plan transaction amount (`1`); the trial pool decrements **1** regardless\nof endpoint weight. Billing parity with `/geocode-usa` (`geocode=1`) is\n**pending** and will be aligned in a later release. Anonymous callers\nconsume one free slot per IP — per-product daily free limits apply\n(check remaining via `/geocode-credits`); anonymous access is\nrate-limited per IP.\n\n**UK host:** call this endpoint on `https://paf.acuris-geo.com`. Requests\nsent to `api.acuris-geo.com` return **400**\n`{\"error\": \"country_not_served_by_this_endpoint\", \"use_instead\": \"https://paf.acuris-geo.com\"}`.\n","operationId":"geocodeUk","parameters":[{"$ref":"#/components/parameters/Password"},{"name":"street","in":"query","required":true,"schema":{"type":"string"}},{"name":"hno","in":"query","required":true,"schema":{"type":"string"},"description":"House number"},{"name":"town","in":"query","required":true,"schema":{"type":"string"},"description":"Post town"}],"responses":{"200":{"description":"Geocode result with coordinates and `accuracy_type` precision tier. For UK matches the body also carries `udprn` and (when available) `uprn`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeocodeResponse"}}}},"400":{"description":"Missing parameters (town, street and house number are required)"},"403":{"description":"Limit or transaction balance.\nKey-level 403s: `{\"error\": \"key_blocked\", \"message\"}` when the\nAPI key has been blocked (the `message` says why), and `{\"error\": \"ip_not_allowed\",\n\"message\", \"ip\"}` when the key is restricted to approved source IP addresses and\nthis request came from another one (`ip` is the address we saw). Source-IP\nrestriction is optional and set up per key on request via support.\n"},"404":{"description":"Address not found. Body carries `match_type: no_match`, zeroed `match_score`, and a full-false `match_components`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeocodeErrorBody"}}}},"429":{"$ref":"#/components/responses/RateLimitExceeded"},"503":{"description":"Reference database not available on this deployment"}}}},"/validate/batch":{"post":{"tags":["Validation"],"summary":"Validate up to 200 addresses in one request","description":"Synchronous bulk variant of `/validate`. Each address is fanned out\nin-process to the real `POST /validate` route, so every result — and its\nbilling — is byte-identical to a standalone call. **Billing is per row:**\neach address consumes one address-validation transaction (Stripe-plan transaction;\nthe trial pool decrements 1 regardless). There is **no submit-time `403`** —\nif the key runs out of transactions, is over quota, or is invalid, that surfaces\ninside the individual result entry rather than failing the whole batch.\n**Requires an API key** (the anonymous free-tier IP path is for `POST /validate`\nonly). For larger volumes, submit an async job via `POST /validate/jobs`.\n","operationId":"validateAddressBatch","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["addresses"],"properties":{"addresses":{"type":"array","maxItems":200,"description":"Each entry is either an `input` (same single-line string or\nfielded object as `POST /validate`), or an object\n`{\"input\": <input>, \"country\": \"usa\"}` to override the batch\n`country` per row. (`address` is accepted as an alias of `input`.)\n","items":{}},"country":{"type":"string","description":"Default ISO-style country code applied to rows without their own `country`."}},"example":{"country":"deu","addresses":["Eckenbertstraße 31, 67549 Worms",{"input":"1600 Pennsylvania Ave NW, Washington, DC 20500","country":"usa"}]}}}}},"responses":{"200":{"description":"Per-address results. Individual entries may themselves carry an error\n(e.g. `insufficient_validation_credits`) — inspect each result.\n","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer"},"results":{"type":"array","items":{"$ref":"#/components/schemas/ValidateResponse"}}}}}}},"400":{"description":"Missing/empty `addresses`, not an array, or more than 200 entries (use `POST /validate/jobs`)."},"401":{"description":"API key required — batch validation is not available on the anonymous free tier."}}}},"/validate/jobs":{"post":{"tags":["Validation"],"summary":"Submit an async address-validation job (up to 50,000)","description":"Queue a large address list for **asynchronous** validation — the path for\nlists larger than the 200-address synchronous `/validate/batch` cap.\nReturns a `job_id` immediately (HTTP 202); poll\n`GET /validate/jobs/{job_id}` for status and results, or pass `webhook_url`\nand the server POSTs `{job_id, status, addresses_count}` when processing\nfinishes. **Billing is per row inside the worker** — each address consumes\none address-validation transaction (Stripe-plan transaction; the trial pool\ndecrements 1 regardless), so there is **no submit-time `402`/`403`**. If the\naccount runs out of transactions partway through, the remaining results carry an\nerror entry rather than failing the whole job. **Requires an API key.** Runs\non the main box only (the UK PAF satellite returns `503` with a redirect hint).\n","operationId":"validateAddressCreateJob","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["addresses","country"],"properties":{"addresses":{"type":"array","maxItems":50000,"description":"Each entry is the same shape as `POST /validate`'s `input` (or `{\"input\": ..., \"country\": ...}` per-row override).","items":{}},"country":{"type":"string","description":"Default ISO-style country code for the job. Required."},"webhook_url":{"type":"string","description":"Optional http(s) URL to receive a completion callback."}}}}}},"responses":{"202":{"description":"Job accepted and queued.","content":{"application/json":{"schema":{"type":"object","properties":{"job_id":{"type":"string"},"status":{"type":"string","example":"queued"},"addresses_count":{"type":"integer"},"status_url":{"type":"string","description":"URL to poll for status / results."}}}}}},"400":{"description":"Empty list, more than 50,000 addresses, missing `country`, or a non-http(s) `webhook_url`."},"401":{"description":"API key required."},"503":{"description":"Submitted to the UK PAF satellite; resubmit to the main box (hint in body)."}}}},"/validate/jobs/{job_id}":{"get":{"tags":["Validation"],"summary":"Poll an async address-validation job","description":"Returns the job's status and, once `status` is `done`, the per-address\n`results` (each byte-identical to a `POST /validate` response). The API key\nmust own the job.\n","operationId":"validateAddressGetJob","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Job status (with results when done).","content":{"application/json":{"schema":{"type":"object","properties":{"job_id":{"type":"string"},"status":{"type":"string","description":"`queued` | `running` | `done` | `failed`"},"country":{"type":"string"},"addresses_count":{"type":"integer"},"created_at":{"type":"string"},"started_at":{"type":"string","nullable":true},"completed_at":{"type":"string","nullable":true},"error_message":{"type":"string","description":"Present when `status` is `failed`."},"results":{"type":"array","description":"Present once `status` is `done`.","items":{"$ref":"#/components/schemas/ValidateResponse"}}}}}}},"401":{"description":"API key required."},"404":{"description":"Job not found, or the job belongs to a different key."},"503":{"description":"Queried on the UK PAF satellite; retry against the main box (hint in body)."}}}},"/account/balances":{"get":{"tags":["Account"],"summary":"Live account balances (per-key quota)","description":"The true per-key quota endpoint for the logged-in console/dashboard.\nReturns all four transaction pools with their denominators, the real trial\ncountdown, and Stripe subscription state — reflecting reality on load\nand after each call (not the frozen login-fragment snapshot).\n\n**Auth:** the account's own API key — send `X-Acuris-Key: <key>`\n(primary). `Authorization: Bearer <key>`, `X-API-Key`, or the legacy\n`?key=` query param is also accepted.\n\n**Transaction costs (Stripe-plan transactions, per call):** `validate` = 1,\n`geocode` = 1, `reverse` = 1. During a trial the pool\ndecrements 1 regardless of endpoint weight.\n\nPer-product daily free limits apply (check remaining via\n`/validate-credits` and `/geocode-credits`); anonymous access is\nrate-limited per IP.\n","operationId":"accountBalances","security":[{"acurisKeyHeader":[]},{"bearerAuth":[]},{"apiKeyHeader":[]},{"apiKeyQueryLegacy":[]}],"responses":{"200":{"description":"Live balances, trial countdown, and subscription state for the caller's key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountBalances"}}}},"401":{"description":"API key required, or invalid/inactive key. Body includes `key_accepted: false`."}}}},"/me/usage":{"get":{"tags":["Account"],"summary":"Account usage history","description":"Per-account usage for the console: the caller's most recent calls plus\n7-day daily counts, for the caller's own API key. Summary fields only\n(never the request payload). A fresh account returns empty arrays.\n\n**Auth:** the account's own API key — send `X-Acuris-Key: <key>`\n(primary). `Authorization: Bearer <key>`, `X-API-Key`, or the legacy\n`?key=` query param is also accepted.\n","operationId":"meUsage","security":[{"acurisKeyHeader":[]},{"bearerAuth":[]},{"apiKeyHeader":[]},{"apiKeyQueryLegacy":[]}],"responses":{"200":{"description":"Recent calls and 7-day daily usage counts for the caller's key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageHistory"}}}},"401":{"description":"API key required, or invalid/inactive key."}}}},"/dev-key":{"post":{"tags":["Account"],"summary":"Self-serve evaluation key (zero-friction onboarding)","description":"**Recommended way to start.** Mints a low-cap, short-lived evaluation\nkey in one step — no password, no email round-trip, no free-domain\nblock. The key is returned directly in the response body.\n\nThe key seeds ~100 transactions in **each** pool (validation, geocode —\nseparate pools) and expires after **7 days**. These\nare trial-pool credits: the pool decrements **1 per call** regardless of\nendpoint. (Under a paid Stripe plan the same endpoints instead cost\nweighted transactions — e.g. validate=1, geocode=1, reverse=1.)\n\nRate-limited to 1 issuance per email and 1 per IP in any 24-hour window\n(and 60 requests/hour per IP overall). For more headroom, use the full\n`/register` flow (28-day trial). Per-product daily free limits apply to\nanonymous use — check remaining via `/validate-credits` and\n`/geocode-credits`; anonymous access is also rate-limited per IP.\n","operationId":"devKey","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","description":"A valid email address to associate with the key. Free providers (Gmail etc.) are accepted.","example":"you@example.com"},"accept_terms":{"type":"boolean","description":"`true` = you agree to the Acuris Geo\n[Terms of Service](https://api.acuris-geo.com/legal/terms) and the\n[UK PAF Evaluation Terms](https://api.acuris-geo.com/legal/uk-evaluation-terms).\nStarts the key's 90-day UK evaluation. When terms acceptance is\nenforced, a request without it returns 400\n`terms_acceptance_required`; send it on every request.\n","example":true},"country":{"type":"string","nullable":true,"description":"Optional ISO country hint (e.g. `gbr`). Drives the returned\n`info_url` and, for `gbr`, adds a `paf_note` about UK\n(Royal Mail PAF) evaluation limits.\n","example":"gbr"}}}}}},"responses":{"200":{"description":"Evaluation key issued. Send it as `X-Acuris-Key: <key>` (or `Authorization: Bearer`, `X-API-Key`, or `?key=`) on subsequent calls.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DevKeyResponse"}}}},"400":{"description":"Missing or malformed email (`error: bad_email`), or, when terms acceptance is enforced, `accept_terms` missing or not `true` (`error: terms_acceptance_required`, with `terms_url` and `uk_evaluation_terms_url`)."},"429":{"description":"Rate limited — a dev key was already issued to this email\n(`error: rate_limited_email`) or from this IP\n(`error: rate_limited_ip`) in the last 24 hours, or the hourly\nrequest limit was exceeded.\n"},"500":{"description":"Could not issue dev key (`error: internal`)."}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"opaque","description":"Send your API key as `Authorization: Bearer <key>`. Recommended.\n"},"apiKeyHeader":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Alternative header auth: `X-API-Key: <key>`.\n"},"acurisKeyHeader":{"type":"apiKey","in":"header","name":"X-Acuris-Key","description":"API key issued to direct customers who subscribed via Acuris Stripe\nCheckout (separate from RapidAPI subscribers). Stripe-issued keys\nalso work via `Authorization: Bearer <key>`. Example:\n\n```\ncurl -H 'X-Acuris-Key: <your-key>' \\\n  'https://api.acuris-geo.com/geocode?country=usa&street=Pennsylvania+Ave&hno=1600&city=Washington&state=DC'\n```\n"},"apiKeyQueryLegacy":{"type":"apiKey","in":"query","name":"key","description":"Legacy query-param auth (`?key=<key>`). Retained for backward\ncompatibility; prefer header auth — query-string secrets can leak into access logs.\n"}},"parameters":{"Password":{"name":"key","in":"query","description":"Legacy API key query parameter (`?key=...`). Prefer `Authorization: Bearer <key>` or\n`X-API-Key: <key>` header auth instead.\n","schema":{"type":"string"}}},"responses":{"RateLimitExceeded":{"description":"Too many requests (anonymous limit or WAF/limiter)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"rate_limit_exceeded"},"message":{"type":"string"}}}}}}},"schemas":{"AccountBalances":{"type":"object","required":["key_accepted","pools"],"properties":{"key_accepted":{"type":"boolean","example":true},"pools":{"type":"object","description":"The four independently-metered transaction pools. Each pool's `total` is\nthe greater of the remaining balance and the trial floor (so a granted\naccount reads N/N rather than N/1000). The `email` and `phone` pools\nreport a `total` of 0 until they hold transactions.\n","required":["validation","geocode","email","phone"],"properties":{"validation":{"$ref":"#/components/schemas/CreditPool"},"geocode":{"$ref":"#/components/schemas/CreditPool"},"email":{"$ref":"#/components/schemas/CreditPool"},"phone":{"$ref":"#/components/schemas/CreditPool"}}},"trial_expires_at":{"type":"string","nullable":true,"description":"UTC trial-window end (`YYYY-MM-DD HH:MM:SS`), or null.","example":"2026-07-30 00:00:00"},"trial_expired":{"type":"boolean","description":"True once the trial calendar window has lapsed."},"days_left":{"type":"integer","nullable":true,"description":"Whole days remaining in the trial window, or null if no/unparseable expiry.","example":14},"subscription":{"nullable":true,"description":"Stripe subscription state for the account's email, or null when none exists.","type":"object","properties":{"plan":{"type":"string","nullable":true,"example":"growth"},"status":{"type":"string","nullable":true,"example":"active"},"quota_used":{"type":"integer","example":1240},"quota_limit":{"type":"integer","example":50000}}}}},"CreditPool":{"type":"object","required":["remaining","total","used_pct"],"properties":{"remaining":{"type":"integer","example":972},"total":{"type":"integer","description":"Denominator; 0 for the email/phone pools until they are funded.","example":1000},"used_pct":{"type":"integer","description":"Rounded percentage consumed; 0 when total is 0.","example":3}}},"UsageHistory":{"type":"object","required":["recent","days","calls_7d"],"properties":{"recent":{"type":"array","description":"Up to 15 most recent calls (newest first), summary fields only.","items":{"type":"object","properties":{"tool":{"type":"string","example":"geocode"},"at":{"type":"string","description":"Call timestamp (UTC).","example":"2026-07-16 09:41:22"},"country":{"type":"string","nullable":true,"description":"Data country of the request, when known.","example":"usa"},"status":{"type":"string","description":"Outcome — `ok` or `error`.","example":"ok"}}}},"days":{"type":"array","description":"Daily call counts for the trailing 7 days (oldest first); missing days omitted.","items":{"type":"object","properties":{"date":{"type":"string","example":"2026-07-16"},"count":{"type":"integer","example":42},"ok":{"type":"integer","description":"Calls with an `ok` result on that day.","example":40}}}},"calls_7d":{"type":"integer","description":"Total calls across the trailing 7-day window.","example":118}}},"DevKeyResponse":{"type":"object","required":["api_key","validation_credits","geocode_credits","phone_credits","expires_at","tier","info_url","next_steps"],"properties":{"api_key":{"type":"string","description":"The evaluation key. Send it as `X-Acuris-Key: <key>` (or `Authorization: Bearer` / `X-API-Key` / `?key=`) on validation/geocoding calls.","example":"s3cr3t-eval-token"},"validation_credits":{"type":"integer","description":"Address-validation pool seeded on the key.","example":100},"geocode_credits":{"type":"integer","description":"Geocode pool seeded on the key.","example":100},"phone_credits":{"type":"integer","description":"Offline phone-validation pool seeded on the key.","example":100},"expires_at":{"type":"string","description":"Expiry timestamp (UTC), 7 days from issuance.","example":"2026-07-23 12:00:00 UTC"},"tier":{"type":"string","example":"dev"},"info_url":{"type":"string","description":"Pricing / info page (UK-specific for a `gbr` country hint).","example":"https://acuris-geo.com/acuris-pricing/"},"next_steps":{"type":"string","description":"Short onboarding note pointing to `/register` for more headroom."},"paf_note":{"type":"string","nullable":true,"description":"Present only when the request `country` hint is `gbr` — notes that UK addresses (Royal Mail PAF) are evaluation-only under a dev key."},"uk_evaluation_expires_at":{"type":"string","nullable":true,"description":"Present only when the request sent `\"accept_terms\": true` — end of the key's free UK evaluation (UTC)."}}},"ValidateBatchRequest":{"type":"object","required":["addresses"],"description":"Bulk validation payload. An **API key** (header or credentials) is required.\n","properties":{"addresses":{"type":"array","maxItems":200,"description":"Up to 200 rows. Each row is either the same `input` shape accepted by\n`POST /validate` (a single-line string or an object of address fields),\n**or** an object `{\"input\": <input>, \"country\": \"usa\"}` that overrides\n`country` for that one row.\n","items":{"oneOf":[{"type":"string"},{"type":"object","additionalProperties":true}]}},"country":{"type":"string","description":"Default ISO-3 country for every row that does not carry its own\n`country` override.\n"}}},"ValidateBatchResponse":{"type":"object","properties":{"count":{"type":"integer","description":"Number of rows processed (after empty rows are dropped).","example":2},"results":{"type":"array","description":"Per-row results in request order; each element is the same body a standalone `POST /validate` returns.","items":{"$ref":"#/components/schemas/ValidateResponse"}}}},"ErrorBody":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"},"ip":{"type":"string","description":"Only on `ip_not_allowed` (403): the source IP address this request\ncame from, which is not on the key's approved list.\n"}}},"MatchType":{"type":"string","description":"Internal/legacy precision tier with the score table below. New clients should\nprefer `accuracy_type` for branching.\n\nUnlike `accuracy_type`, this enum is CLOSED — the score table is fixed\nand no further values will be added. An `arrival_point` coordinate is\nreported here as `rooftop`, because the address is premise-verified\neither way; only `accuracy_type` states what the coordinate is.\nScore table:\n  * `rooftop` → 1.0\n  * `parcel_centroid` → 0.9\n  * `interpolated` → 0.8\n  * `street_level` → 0.6\n  * `zip_centroid` → 0.4\n  * `city_centroid` → 0.2\n  * `no_match` → 0.0\n  * `non_deliverable` → 0.0 — the input is a PO Box / Rural Route /\n    Postfach etc. and can never resolve to a street address\n    (USA/CAN/MEX/DEU/AUT/CHE detection). Returned on the 400 body\n    (with `non_deliverable_type`) unless `iso20022: true` opted in to\n    a labelled 200.\n","enum":["rooftop","parcel_centroid","interpolated","street_level","zip_centroid","city_centroid","no_match","non_deliverable"]},"AccuracyType":{"type":"string","nullable":true,"x-extensible-enum":["rooftop","arrival_point","street_interpolated","street_segment_centroid","street_centroid","landmark_proximity","postcode_centroid","locality_centroid","admin_centroid"],"description":"What the returned coordinate represents. `null` on `no_match`.\n\n**This is an OPEN set.** New tiers are added as reference data improves.\nClients MUST pass unrecognized values through rather than throwing, and\nSHOULD branch on `point_coordinate` rather than on these literals.\n\nA **point coordinate** identifies one address:\n  * `rooftop` — a point on the building itself.\n  * `arrival_point` — the address's entrance, gate or curb-side access\n    point. A point for *this* address, typically a few metres from the\n    roof — deliberately not claimed as the building footprint.\n\nEverything else is derived rather than observed — a segment or an area,\nnot an address:\n  * `street_interpolated` — HNO estimated along a street segment polyline\n    (SEG cascade) from the position of neighbouring house numbers.\n  * `street_centroid` — street confirmed; exact HNO not located.\n    **Singapore:** block numbers are not linear along a road and a\n    letter-suffixed block (e.g. `700D`) is a separate building with its\n    own postcode, so Singapore never returns `street_interpolated`. An\n    unconfirmed block (or a street with no block) answers\n    `street_centroid` at the street's centre, and\n    `standardized.postcode` is left empty unless you supplied a\n    postcode that exists on that street — a postcode names one\n    building, and another building's postcode is never shown as yours.\n  * `landmark_proximity` — India only. The address itself resolved no\n    further than its postcode/locality, so the coordinate is that of a\n    LANDMARK the caller named in the input (\"opp. Swami Samarth Math\").\n    It is a point on a *neighbouring* place, never the address, and it\n    is only ever used when it out-ranks what would otherwise be\n    returned. The landmark used is named back to you in\n    `landmark_used` (`name`, `matched_from`, `scope`, `source`).\n  * `postcode_centroid` — only postcode matched.\n  * `locality_centroid` — only city/locality matched.\n  * `admin_centroid` — only admin region (state/province) matched.\n"},"MatchComponents":{"type":"object","description":"Which input fields were confirmed by the match.","required":["house_number","street","city","zip","state"],"properties":{"house_number":{"type":"boolean"},"street":{"type":"boolean"},"city":{"type":"boolean"},"zip":{"type":"boolean"},"state":{"type":"boolean"}}},"FailureReason":{"type":"string","x-extensible-enum":["street_not_found","city_not_matching","locality_unknown","house_number_interpolated","house_number_not_found","house_number_unconfirmed","house_number_range_interpolated","street_not_matched","street_unconfirmed","street_not_found_in_locality","postcode_not_matched","postcode_unconfirmed","postcode_town_mismatch","postcode_locality_conflict","postcode_valid_not_stocked","city_unconfirmed","below_verification_threshold","no_coordinate_available","resolved_to_administrative_area_only","positioned_at_named_landmark","non_deliverable_address","search_budget_exhausted","fuzzy_budget_exceeded","street_type_ambiguous","city_not_found","city_missing","street_found_in_multiple_localities","street_type_mismatch","street_particle_mismatch","street_spelling_mismatch","locality_ambiguous","street_missing","fell_back_to_locality","house_number_not_in_reference","house_number_missing","postcode_house_number_ambiguous","house_number_extension_missing"],"description":"Why a validation failed to confirm the address (or part of it).\n\n**This is an OPEN set** — new codes are added as matching logic\nimproves; pass unrecognized values through rather than throwing.\nReasons appear on 404/422 error bodies AND on 200 `partial_match`\nresponses (stating what the resolved tier could not pin down).\n  * `street_not_found` — no street in the candidate set scored highly.\n    On a Portugal 200 it appears together with `fell_back_to_locality`\n    (`approximate: true`) when the name sent is an estate,\n    urbanisation or neighbourhood that is not in the street data but\n    whose town we can place: the point is then the town centre.\n  * `city_not_matching` — street looked right but the locality did not.\n  * `locality_unknown` — we could not even find candidates in the locality.\n  * `house_number_interpolated` — house number was interpolated along a street\n    segment (`street_interpolated` tier), not confirmed against a rooftop record.\n  * `house_number_not_found` — street confirmed but the exact house number is not\n    on file.\n  * `house_number_unconfirmed` — the house number could not be confirmed\n    (`street_centroid` tier partials emit this).\n  * `house_number_range_interpolated` — number placed within an official\n    numbering range, not a premise row.\n  * `street_not_matched` — the street could not be matched; resolution stopped at a\n    postcode or locality centroid.\n  * `street_unconfirmed` — a street you provided could not be confirmed\n    against the matched record.\n  * `street_not_found_in_locality` — the street exists but not in the\n    stated locality.\n  * `postcode_not_matched` — the postcode could not be matched; resolution stopped\n    at a locality centroid.\n  * `postcode_unconfirmed` / `city_unconfirmed` — the component was echoed\n    from input, not confirmed by reference data.\n  * `postcode_town_mismatch` — postcode and town point at different places.\n  * `postcode_locality_conflict` — postcode and locality conflict (India).\n  * `postcode_valid_not_stocked` — the postcode is real but our reference\n    data holds no addresses for it (Malaysia; see `postcode_status`).\n  * `below_verification_threshold` — the best candidate scored under the\n    verification threshold.\n  * `no_coordinate_available` — matched a reference row that carries no\n    coordinate.\n  * `resolved_to_administrative_area_only` — only the admin region (state/province)\n    resolved (`admin_centroid` tier).\n  * `positioned_at_named_landmark` — coordinate taken from a landmark the\n    caller named (India `landmark_proximity`; see `landmark_used`).\n  * `non_deliverable_address` — PO Box / Rural Route / Postfach input\n    (see `MatchType: non_deliverable`).\n  * `search_budget_exhausted` — 404 only. The input did not match\n    directly and the recovery search (typo, locality and postcode\n    fallbacks) ran out of its per-request time budget (about 10 s)\n    before finding a confident answer. This is a no-match, not a\n    server error: the address may still exist. Check the input for\n    typos or add the postcode, then retry; do not retry the identical\n    request in a tight loop.\n  * `fuzzy_budget_exceeded` — Sweden (`swe`), `/validate` partial 200s\n    and 404s. The street did not match as typed and the search for a\n    close real street (typo correction) was cut short by its time\n    limit before it finished. It is NOT proof that the street is\n    absent: appears together with `street_not_matched` (200) or\n    `street_not_found` (404), and the answer stops at a postcode or\n    locality centroid. The caller may retry the same request once a\n    moment later; a retry usually completes the correction.\n  * `street_type_ambiguous` — 404 only (USA). The street NAME exists in\n    the given postcode/city, but only with a different street type or\n    directional than the one supplied, and more than one real street\n    fits (e.g. `12th St N` when both `12th St NE` and `12th St NW` carry\n    the house number). We never guess between two real streets: the\n    body carries `did_you_mean`, the candidate streets (up to 6) with\n    their `city` and `postcode`; resubmit with the intended one.\n    Can also appear in a `/geocode-usa` 404 body, when no fallback\n    centroid is available for the address.\n\n  * `city_missing` — 404. A street was sent without a city or\n    postcode and cannot be placed in a single locality. Sent together\n    with another code (e.g. `street_not_found` or\n    `street_found_in_multiple_localities`). Seen for several countries\n    (e.g. Portugal, Brazil, Spain). Netherlands: also when a postcode\n    was sent but is not on file (the `message` then asks for a city\n    only); a postcode + house number with no street is answered\n    without this code (see `postcode_house_number_ambiguous`).\n  * `street_found_in_multiple_localities` — 404. The street name exists\n    in more than one locality — of the town you sent, or, when no city\n    was sent, of the country. Add the locality or the postcode. When\n    no city was sent, `did_you_mean` lists the towns holding the\n    street (at most 6).\n\n**Portugal (`country: prt`) only.** The codes below are added to\nPortuguese responses on `/validate` and `/geocode` (and their `/v1`\naliases). On a 200 they are appended after the codes listed above,\nwhich keep their meaning and position. On a 404 the first code is the\nmost specific one.\n  * `city_not_found` — 404. The city/town you sent is not a place in\n    the Portuguese reference data (often sent with\n    `locality_unknown`). Check the spelling or send the postcode.\n  * `street_type_mismatch` — 404, sent before `street_not_found`. The\n    street name exists in the town only with a different street type\n    (e.g. `Rua de Portugal` typed, `Avenida de Portugal` held). See\n    `did_you_mean`.\n  * `street_particle_mismatch` — 404, as above, when the name differs\n    only in its linking particles (`da`, `de`, `do`, `das`, `dos`).\n  * `street_spelling_mismatch` — 404, as above, for a close spelling\n    of a street of that town.\n  * `locality_ambiguous` — 404. A place name sent on its own (no\n    street) is a locality in several municipalities and nothing\n    coarser; it is never guessed. `did_you_mean` lists the candidates\n    with `municipality` and `district`. Sent with `street_missing`.\n  * `street_missing` — no street was sent. On a 200 it marks the\n    labelled approximate point for a city- or neighbourhood-only\n    request (`approximate: true`).\n  * `fell_back_to_locality` — 200. A street was sent but could not be\n    placed, and the point served is the town/area centre\n    (`approximate: true`, `resolved_level`, `resolved_name`), not the\n    address. For an estate or neighbourhood name sent with a town it is\n    accompanied by `street_not_found`; it can also carry a\n    `did_you_mean` hint and its `street_*_mismatch` code.\n  * `house_number_not_in_reference` — 200. The street was matched but\n    the house number you sent is not in the reference data;\n    `nearby_house_numbers` names the closest same-parity numbers that\n    are.\n  * `house_number_missing` — 200. The street was matched but no house\n    number was sent, so only a street-level point is possible.\n\n**Netherlands (`country: nld`), postcode + house number with no street:**\n  * `postcode_house_number_ambiguous` — 404, with `street_missing`.\n    Several streets hold that house number at that postcode; we never\n    guess between them. `did_you_mean` lists them (`street`, `city`,\n    `postcode`, `house_number`; at most 6).\n  * `house_number_extension_missing` — 200. The number exists at that\n    postcode only with a letter (`3A`, `3B`, ...) and none was sent; the\n    point is that building, and `did_you_mean` lists the letters.\n  * `house_number_not_in_reference` — 200 (`postcode_centroid`). The\n    number is not on file at that postcode; `standardized.street` is\n    empty (nothing is invented).\n"},"NearbyHouseNumbers":{"type":"object","description":"**Portugal (`country: prt`) only.** Present on a 200 answer when the\nstreet was matched but the house number you sent is not in the\nreference data — the answer is then either street-level\n(`street_centroid`) or `street_interpolated` at a point between the\nnearest same-parity house numbers (`pin_between`). It lists which\nnumbers of that street ARE held, on the same side of the street (odd\nand even numbers usually face each other). Informational only: it\nnever changes the coordinate, tier, confidence or `deliverable`. Sent\nwith reason `house_number_not_in_reference`. Pass unrecognized fields\nthrough.\n","additionalProperties":true,"properties":{"requested":{"type":"string","description":"The house number as you sent it.","example":"46"},"parity":{"type":"string","x-extensible-enum":["odd","even"]},"before":{"allOf":[{"$ref":"#/components/schemas/NearbyHouseNumber"}],"nullable":true,"description":"The nearest held number below the requested one on the same side, or `null`."},"after":{"allOf":[{"$ref":"#/components/schemas/NearbyHouseNumber"}],"nullable":true,"description":"The nearest held number above the requested one on the same side, or `null`."},"pin_between":{"type":"array","nullable":true,"items":{"type":"string"},"description":"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.","example":["44","50"]},"same_parity_available":{"type":"array","items":{"type":"string"},"description":"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":{"type":"integer","description":"Number of distinct house numbers held for the street."},"coordinated_doors":{"type":"integer","description":"How many of those carry their own coordinate."}}},"NearbyHouseNumber":{"type":"object","additionalProperties":true,"properties":{"hno":{"type":"string","example":"44"},"lat":{"type":"number","format":"float","nullable":true},"lng":{"type":"number","format":"float","nullable":true},"accuracy":{"type":"string","nullable":true,"description":"The coordinate tier of that house number (e.g. `rooftop`), `null` without a coordinate."},"has_coordinates":{"type":"boolean","description":"`false` when the number exists in the reference data without its own coordinate (`lat`/`lng`/`accuracy` are then `null`)."}}},"ResolvedLevel":{"type":"string","description":"**Portugal (`country: prt`) only.** Which kind of place an approximate\npoint (`approximate: true`) stands for. Open set — pass unknown values\nthrough.\n  * `locality` — a locality (village / town).\n  * `postal_town` — the town name of the postal address.\n  * `municipality` — a municipality (concelho).\n  * `district` — a district.\n  * `lisbon_parish` — a Lisbon parish or neighbourhood name; the point\n    is Lisbon's.\n","x-extensible-enum":["locality","postal_town","municipality","district","lisbon_parish"]},"DidYouMeanEntry":{"type":"object","additionalProperties":true,"description":"One candidate in a 404 `did_you_mean` list — what the input most\nlikely meant, for you to choose from and resubmit. Never applied\nautomatically. Which fields are present depends on the case:\n  * USA `street_type_ambiguous`: `street`, `city`, `postcode`.\n  * Portugal, street not in the town (`street_type_mismatch` /\n    `street_particle_mismatch` / `street_spelling_mismatch`):\n    `street`, `city`, `doors`, `match`.\n  * Portugal, street sent without a city\n    (`street_found_in_multiple_localities` + `city_missing`):\n    `street`, `city`, `municipality`, `doors` (most house numbers\n    first, at most 6; see `did_you_mean_truncated`).\n  * Portugal, place name only (`locality_ambiguous`): `city`,\n    `municipality`, `district`.\n  * Other countries' locality/street ambiguities carry their own\n    subset (e.g. `street` + `city`, sometimes `state`).\n","properties":{"street":{"type":"string","example":"Avenida de Portugal"},"city":{"type":"string","example":"Estoril"},"postcode":{"type":"string"},"municipality":{"type":"string"},"district":{"type":"string"},"doors":{"type":"integer","description":"Number of addresses (house numbers) held for that street in that locality — a size indicator for ranking."},"match":{"type":"string","x-extensible-enum":["street_type","particles","spelling"],"description":"How the candidate differs from what was sent: another street type, other linking particles, or a close spelling."}}},"StandardizedAddress":{"type":"object","description":"Canonical address as stored in the reference database.","properties":{"street":{"type":"string"},"house_number":{"type":"string"},"city":{"type":"string","description":"Spain (`/suggest`): for the officially bilingual municipalities the suggestion prints the Castilian name by default (`Alicante`, `Elche`, `San Sebastián`, `Castellón de la Plana`, `Valencia`); if your query already spells the regional form (`Alacant`, `Elx`, `Donostia`, `València`) that spelling is kept. Postcode and coordinates are the same either way, and submitting the suggestion to `/validate` matches the same address. `/validate` itself echoes the spelling you sent.\nSweden, city + postcode without a street (`/validate`, `/geocode`): the stored spelling of the locality (`Goteborg`, `göteborg` -> `GÖTEBORG`), as on full matches; an English or variant name (`Gothenburg`) is returned in the stored spelling too, and `/validate` lists `City` under `corrections`."},"state":{"type":"string","description":"Present for countries with regions (e.g. USA, CAN, AUS, MYS)."},"postcode":{"type":"string"},"postcode_formatted":{"type":"string","description":"The postcode as it is written on a letter, in a field of its own, for integrations that look the postcode up elsewhere. Sweden: `412 50` (`postcode` stays `41250`). Where no written form differs, it equals `postcode`. `postcode` itself is unchanged. Returned by `/validate`."},"country":{"type":"string"},"formatted_address":{"type":"string","description":"Country-specific pretty-printed form, multi-line."},"street_type":{"type":"string","description":"The thoroughfare type as its own element, where the reference data carries it separately: Malaysia (`street_type: \"Jalan\"`, `street: \"Melor 1\"`), and Canada / France where the split comes straight from the reference columns (France is type-first — `street_type: \"Place\"`, `street_name: \"de la Comédie\"`). NOT emitted for the USA, which would need a USPS-suffix parse, nor for German, Dutch, Danish, Swedish or Swiss addresses, where the type is fused into the word (*Eckenbertstraße*) and splitting it is a morphological judgement rather than a field read."},"street_name":{"type":"string","description":"Canada and France: the bare street name with the type and any directional removed. Companion to `street_type` / `street_suffix`; `street` always holds the full form."},"street_suffix":{"type":"string","description":"Canada: the directional element (N, SW, …) as its own field."},"street_id":{"type":"string","description":"France: the reference data's stable identifier for the thoroughfare."},"building_name":{"type":"string","description":"Hong Kong: the building name from the matched premise. Emitted only when every co-matched row agrees on it — a query resolving to many rows (a tower with hundreds of flats) omits it rather than picking one arbitrarily. Singapore: the building name of the matched block, when it has one (house-number-level matches, and addresses identified by a building or tenant name). It is not part of `formatted_address`."},"level_number":{"type":"string","description":"Denmark (`etage`) and Hong Kong (floor). Same unambiguity rule as `building_name`, and additionally requires a confirmed house number."},"unit_identifier":{"type":"string","description":"Denmark (`dør`), the Netherlands (sub-address) and Hong Kong (flat). Same unambiguity rule as `level_number`."},"ine_municipality":{"type":"string","description":"Spain: the 5-digit INE municipality code of the matched address (leading zeros preserved — always a string)."},"nis_code":{"type":"string","description":"Belgium: the NIS municipality code of the matched address."},"statistical_sector":{"type":"string","description":"Belgium: the 9-character Statbel statistical sector of the matched address (the trailing hyphen is part of the code, e.g. `\"41002A00-\"`). This is the key the Belgian enrichment joins on."},"county":{"type":"string","description":"UK only (`country: \"gbr\"`). Traditional/postal county, derived from the Royal Mail PAF postcode → county map."},"udprn":{"type":"string","description":"UK only. Royal Mail Unique Delivery Point Reference Number (PAF) — stable identifier for the delivery point."},"uprn":{"type":"string","description":"UK only. Ordnance Survey Unique Property Reference Number. Present when the address matches OS Open UPRN."},"unit":{"type":"string","description":"Sub-building unit, echoed from the caller's input (reference rows carry no unit, so this value is never invented). Rendered into `formatted_address` per country convention (e.g. Canada Post `23-4 Vata Crt`). When the reference data cannot confirm the unit at the matched premise, the response lists `\"unit\"` in the top-level `unverified_fields` array — the premise match itself still stands. Spain: staircase / floor / door in any common spelling (`ESC.1-PISO 1, PTA.B`, `1º B`, `3º izq`, `bajo`) are normalised to one form, e.g. `Esc. 1, 1º B`; see `unit_verified` / `unit_check`. Latvia: the flat (dzīvoklis) in any common spelling (`Brīvības iela 100 - 5`, `100-5`, `100 dz. 5`, `100 kv. 5`) is returned as the flat number, e.g. `5`, and rendered as `Brīvības iela 100 - 5`; a korpuss (`10k2`, `10 k. 2`) is part of the house number (`10 k-2`), never a unit."},"suburb":{"type":"string","description":"New Zealand. The NZ Post suburb line between street and post town (`68 Rintoul Street / Newtown / Wellington 6021`). Filled from the matched reference row — including when the caller typed only the city. A suburb typed in the city slot is a verified match, never a `City` correction."},"district":{"type":"string","description":"Neighborhood / sub-locality where the country convention carries one (e.g. the Turkish mahalle, Austrian Bezirk sublocality). Enriched from the reference row even when the caller omitted it."},"province":{"type":"string","description":"Italy only. Two-letter province sigla (MI, RM, …) for the mandatory Poste Italiane locality line (`20067 PAULLO MI`)."},"dependent_street":{"type":"string","description":"UK only (Royal Mail PAF dependent thoroughfare). The minor road the house number is addressed on (`18 Latium Close, Holywell Hill`); the parent thoroughfare stays in `street`."},"dependent_locality":{"type":"string","description":"UK (Royal Mail PAF): village / dependent locality printed between the thoroughfare and the post town. Malaysia: the Taman / Kampung sub-locality line, printed above the postcode line."},"double_dependent_locality":{"type":"string","description":"UK only (PAF). Sub-locality below `dependent_locality`."},"administrative_county":{"type":"string","description":"UK only. PAF Administrative County (local authority). Present when extended UK fields are enabled; on some postcodes it is the only county held (`county` blank)."},"welsh":{"type":"object","description":"UK only, Wales. The Welsh-language form of the SAME delivery point (Royal Mail ships Welsh addresses bilingually): `street`, `city` (post town, e.g. CAERDYDD for CARDIFF) and, where they exist, translated `dependent_locality` / `double_dependent_locality` / `dependent_street`. Present on an English-form match when a Welsh counterpart exists. Typing the Welsh form is a verified match, never a `Street`/`City` correction.","additionalProperties":true},"english":{"type":"object","description":"UK only, Wales. Mirror of `welsh`: the English-language form, present when the matched row is the Welsh one. At most one of `welsh`/`english` appears.","additionalProperties":true}}},"PostcodeAddress":{"type":"object","description":"One delivery point returned by `/postcode-lookup` (Royal Mail PAF).","properties":{"street":{"type":"string"},"house_number":{"type":"string"},"building_name":{"type":"string"},"organisation_name":{"type":"string"},"dependent_street":{"type":"string"},"dependent_locality":{"type":"string","description":"PAF village / dependent locality."},"double_dependent_locality":{"type":"string","description":"PAF sub-locality below `dependent_locality`."},"post_town":{"type":"string","description":"The PAF post town; `city` duplicates it for backward compatibility."},"city":{"type":"string"},"postcode":{"type":"string"},"address_lines":{"type":"array","items":{"type":"string"},"description":"Printable Royal Mail address lines, in order."},"formatted_address":{"type":"string","description":"Single-line join of `address_lines`."},"county":{"type":"string","description":"Traditional county (PAF postcode → county map)."},"administrative_county":{"type":"string","description":"PAF Administrative County (local authority). On some postcodes (e.g. M1 1AE) it is the only county held — `county` blank. Present when extended UK fields are enabled (on by default)."},"udprn":{"type":"string","description":"Royal Mail Unique Delivery Point Reference Number."},"uprn":{"type":"string","description":"Ordnance Survey Unique Property Reference Number."},"uprn_match_m":{"type":"number","description":"Distance in metres between the PAF delivery point and the matched OS Open UPRN coordinate (0.0 is a real and best value). Present when extended UK fields are enabled (on by default)."},"lat":{"type":"number","description":"Omitted when no coordinate is available for the delivery point."},"lng":{"type":"number","description":"Omitted when no coordinate is available for the delivery point."},"accuracy_type":{"type":"string","x-extensible-enum":["rooftop","postcode"],"description":"`rooftop` when an address-level coordinate is available, otherwise `postcode` (postcode-unit centroid). Omitted (along with `lat`/`lng`) when the delivery point has no coordinate. Open set — see AccuracyType; do not treat an unrecognized value as a failure."}}},"Suggestion":{"type":"object","description":"A ranked near-miss candidate returned on `/validate` (score ≥ 0.5, below\nthe correction threshold). Appears in `suggestions[]` on 404 no-match\nresponses and on 200 `partial_match` responses where the street could not\nbe matched — offering the closest real streets in the caller's\npostcode/locality. Not normally present on verified/corrected successes.\n","required":["standardized","score"],"properties":{"standardized":{"$ref":"#/components/schemas/StandardizedAddress"},"score":{"type":"number","format":"float","minimum":0,"maximum":1},"lat":{"type":"number","format":"float"},"lng":{"type":"number","format":"float"}}},"SuggestItem":{"description":"One autocomplete suggestion from `/suggest`. Carries the\nStandardizedAddress fields (flat, not nested) plus the additions below.\nUK identifiers (`udprn`, `uprn`, `county`) are **never** present on\nsuggestions — obtain them by submitting the chosen suggestion to\n`/validate` or via `/postcode-lookup`.\n","allOf":[{"$ref":"#/components/schemas/StandardizedAddress"},{"type":"object","properties":{"lat":{"type":"number","description":"Omitted when the reference row carries no coordinate — never invented."},"lng":{"type":"number","description":"Omitted when the reference row carries no coordinate — never invented."},"count":{"type":"integer","description":"Number of reference premises merged into this row; present when more than one. Germany (`deu`): when the query carries no house number, the printed `formatted_address` of such a row is street-level (street, postcode and town, no house number) once the street-level label is enabled; `house_number` and the coordinates (v=1) are those of one representative premise, and `GET /suggest/expand` lists the street's premises, up to 50 per page (`offset` selects the next page; `has_more` / `next_offset` in the answer), up to 400 per street."},"locality":{"type":"string","description":"Secondary locality, for countries whose reference data carries no postal code column (e.g. IRL)."},"building_name":{"type":"string","description":"UK postcode-mode: labels each delivery point at the postcode."},"organisation_name":{"type":"string","description":"UK postcode-mode: organisation at the delivery point."},"department":{"type":"string","description":"UK postcode-mode: department within the organisation."},"city_kanji":{"type":"string","description":"JPN: kanji display form of `city`."},"state_kanji":{"type":"string","description":"JPN: kanji display form of `state`."},"street_kanji":{"type":"string","description":"JPN: kanji display form of `street`."},"jpn_zip":{"type":"string","description":"JPN: feed back as the `zip` parameter for the stage-2 banchi-gō lookup."},"jpn_oaza_norm":{"type":"string","description":"JPN: feed back as the `oaza` parameter for the stage-2 lookup."},"jpn_chome":{"type":"string","description":"JPN: feed back as the `chome` parameter for the stage-2 lookup."},"building":{"type":"string","description":"SGP: the building name of the suggested premise. When the query matched a building name, this is the name that was matched (a building known under more than one name shows the one you typed). Never part of `formatted_address`. Also returned on `v=2` list rows."},"tenant":{"type":"string","description":"SGP: when the query matched the name of a business at the premise (e.g. `mcdonalds`), that name as listed. A business with several outlets returns up to five of its premises, each with its own `building`. Never part of `formatted_address`. Also returned on `v=2` list rows."}}}]},"AlternativeMatch":{"type":"object","description":"**Reserved — not currently emitted** (disabled in production pending a\nstreet-leading index). Planned behaviour: same street + same house\nnumber in a different state, on USA / CAN `verified` (exact) matches\nonly, bounded to 5 rows.\n","required":["standardized","score"],"properties":{"standardized":{"$ref":"#/components/schemas/StandardizedAddress"},"score":{"type":"number","format":"float","description":"Always 1.0 — these are exact DB matches in a different state."},"lat":{"type":"number","format":"float"},"lng":{"type":"number","format":"float"}}},"ValidateRequest":{"type":"object","required":["country"],"properties":{"country":{"type":"string","description":"ISO-3 country code, lowercase. Any country in the acceptance set\n(~223 live today — see **Country codes** in the API description)\nvalidates and returns the best tier its reference data supports;\ninspect `accuracy_type`. Highest-precision coverage includes `usa`,\n`can`, `gbr` (served from the PAF host — see Servers), `deu`,\n`aut`, `che`, `fra`, `esp`, `bel`, `nld`, `dnk`, `fin`, `swe`,\n`nor`, `ita`, `jpn`, `sgp`, among others. `country_code` and\n`countryCode` are accepted as aliases of this field.\n"},"input":{"description":"Single-line address string **or** object with `street`, `house_number`, `city`,\n`postcode`, `state`, `unit`, `floor`, `po_box`, `sublocality`, etc.\n\n**`sublocality`** is the administrative tier *below* the city — Vietnamese\nphường/xã, Indonesian kelurahan, Thai tambon, Philippine barangay. Send it in\nits own field rather than folding it into `city`, which carries the tier the\nreference data keys on (in Vietnam, the district). Your own word for the tier is\naccepted as an alias: `ward`, `sub_locality`, `sub_district`, `subdistrict`,\n`kelurahan`, `barangay`, `tambon`.\n\nIt **narrows, it never vetoes**: a sub-locality we do not hold, or one written\nin a naming scheme newer than the reference data, returns exactly the result the\nsame request returns without it. So it is always safe to send.\n\nWired for **`vnm`** today, where it separates addresses that share a district,\nstreet and house number across different wards. Other countries accept and\nignore it until their reference data carries the tier.\n","oneOf":[{"type":"string"},{"type":"object","additionalProperties":true}]},"key":{"type":"string","description":"API key in the body (legacy). Header auth is preferred."},"db_version":{"type":"string","description":"Ignored. Same reference DB as geocode (ref_dbs.json)."}}},"ValidateResponse":{"type":"object","description":"Successful validation **or** centroid-fallback. The canonical form\n**always lives in `standardized`**. When value-changing corrections were\napplied, the response carries `status: \"corrected\"` with a\nhuman-readable `corrections` list, and `standardized` holds the\ncorrected canonical form. When neither was attainable but SEG produced a\ncentroid, the response carries `partial_match: true` with `lat`/`lng`\nset; `standardized` then echoes the caller's input for every component\nthat could not be verified — only the components confirmed in\n`match_components` are reference data. All responses carry the\nmatch-quality contract (`match_type`, `match_score`, `match_components`,\n`input_corrected`).\n","additionalProperties":true,"required":["match_type","match_score","match_components","input_corrected","accuracy_type"],"properties":{"standardized":{"$ref":"#/components/schemas/StandardizedAddress"},"corrected":{"deprecated":true,"description":"Reserved legacy key — not emitted. The corrected canonical form is returned in `standardized` (with `status: \"corrected\"` and the `corrections` list); read that instead.","allOf":[{"$ref":"#/components/schemas/StandardizedAddress"}]},"status":{"type":"string","enum":["verified","corrected"],"description":"`verified` = the street and house number matched exactly; postcode/locality repairs derived unambiguously from the matched premise may still appear in `corrections` (with `postcode_corrected: true` and `confidence_level` capped at `medium`) without demoting status. `corrected` = the street or city itself required a value-changing correction (fuzzy match above the 0.85 similarity threshold, or standardized fields). Omitted (with `partial_match: true`) when the address could not be verified. Standardization is never a correction: for a city-state (Singapore, Monaco) the city implied by the country — filled in when you omit it, or typed as an alias such as `SG` / `Republic of Singapore` — does not appear in `corrections` and does not make the status `corrected`; nor do Singapore street-type abbreviations (`Jln` = Jalan, `Bt` = Bukit, `Ave`, `Cres`, `Cl`, …). A genuinely different city or a misspelt street is still reported."},"confidence":{"type":"number","format":"float","description":"1.0 for a `verified` match; the similarity score (0.85–1.0) for a `corrected` match — but capped at match_score (0.2–0.6) whenever a street or house number you PROVIDED could not be confirmed against the matched record (e.g. the match fell back to a different street, or the house number is not on file). confidence_level is demoted to `low` in the same cases."},"confidence_level":{"type":"string","enum":["high","medium","low","none"],"description":"Plain confidence grade for bulk-CSV workflows. `high` = confirmed exact, `medium` = confirmed with safe corrections, `low` = partial/approximate (e.g. house number not found, or a locality/admin-area centroid only), `none` = no match."},"corrections":{"type":"array","description":"Human-readable list of corrected input fields (e.g. `[\"Postal code\", \"City\"]`). `\"House number\"` appears when the house number in the answer differs from the one you sent because the building was renumbered (Latvia, see `former_address`).","items":{"type":"string"}},"accuracy_type":{"$ref":"#/components/schemas/AccuracyType"},"point_coordinate":{"type":"boolean","description":"`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. Emitted on matches and street-tier partials; omitted on postcode/locality/admin-centroid fallbacks."},"match_type":{"$ref":"#/components/schemas/MatchType"},"match_score":{"type":"number","format":"float","minimum":0,"maximum":1},"match_components":{"$ref":"#/components/schemas/MatchComponents"},"input_corrected":{"type":"boolean"},"reasons":{"type":"array","items":{"$ref":"#/components/schemas/FailureReason"},"description":"Present on `partial_match` responses: why full verification failed (e.g. `street_not_matched`, `house_number_unconfirmed`). The same codes appear on 404/422 error bodies."},"provided_components":{"$ref":"#/components/schemas/MatchComponents","description":"**Always returned.** Echoes which components the caller actually supplied (non-empty after parsing), keyed identically to `match_components` (`house_number`, `street`, `city`, `zip`, `state`). Pair it with `match_components` field-by-field to tell \"not provided\" apart from \"provided but not matched\"."},"partial_match":{"type":"boolean","description":"`true` when the address could not be fully verified but a coordinate was still\nproduced — at street level (`street_interpolated` / `street_centroid`: street\nconfirmed, house number not) or via the SEG cascade (postcode / locality / admin\ncentroid). Absent or `false` on full verified/corrected matches. The response\nstill carries `standardized`, but it echoes the caller's input for every\ncomponent that could not be verified (only the components confirmed in\n`match_components` are reference data) — treat `lat`/`lng` as the only\ntrustworthy output, and check `reasons` for what could not be pinned down.\n"},"nearby_house_numbers":{"allOf":[{"$ref":"#/components/schemas/NearbyHouseNumbers"}],"description":"Portugal only, optional. The street was matched but the house number you sent is not in the reference data (`street_centroid`, or `street_interpolated` between the nearest same-parity numbers with `confidence` 0.8 and `deliverable: false`); names the nearest numbers that are held. Sent with reason `house_number_not_in_reference`."},"street_postcodes":{"type":"array","description":"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.","items":{"type":"object","properties":{"postcode":{"type":"string","example":"9573 PA"},"house_number_from":{"type":"integer","example":3},"house_number_to":{"type":"integer","example":22},"parity":{"type":"string","enum":["odd","even","both"],"description":"Which side(s) of the street the postcode covers within that range."}}}},"street_postcodes_total":{"type":"integer","description":"With `street_postcodes`, how many postcodes the street covers (not capped)."},"street_postcodes_truncated":{"type":"boolean","description":"With `street_postcodes`, `true` when the street covers more postcodes than are listed."},"postcode_range":{"type":"object","description":"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.","properties":{"from":{"type":"string","example":"9573 PA"},"to":{"type":"string","example":"9573 PH"},"text":{"type":"string","example":"from 9573 PA to 9573 PH"}}},"approximate":{"type":"boolean","description":"Portugal only, optional. `true` when the point is a town / area centre standing in for the address: a city- or neighbourhood-only request (reason `street_missing`), a street that could not be placed (reason `fell_back_to_locality`), or an estate / urbanisation name sent with a town we can place (reasons `street_not_found` + `fell_back_to_locality`). `accuracy_type` is then `locality_centroid` or `admin_centroid` and `confidence` is 0.4 or lower. Absent otherwise."},"resolved_level":{"allOf":[{"$ref":"#/components/schemas/ResolvedLevel"}],"description":"Portugal only, with `approximate: true`: which kind of place the point stands for (`locality`, `postal_town`, `municipality`, `district`, `lisbon_parish`)."},"resolved_name":{"type":"string","description":"Portugal only, with `approximate: true`: the name of that place as spelled in the reference data (e.g. `Cascais`; `Lisboa` for a Lisbon neighbourhood)."},"enrichment":{"type":"object","description":"Free geographic enrichment, attached automatically (no extra\ncharge, no request parameter) for eighteen countries — USA,\nCanada, Germany, Austria, Switzerland, France, United Kingdom,\nBelgium, Spain, Portugal, Ireland, Netherlands, Finland, Sweden,\nLuxembourg, Japan, Singapore and Hong Kong — whenever the result\nis precise\nenough for a small-area lookup to be trustworthy (gates below).\nOmitted otherwise — never null, never an empty object. Fields whose\ngeography does not apply to the point are likewise omitted, never\nnull. Sub-fields are country-specific; every layer is public\ngovernment data.\n\n**When it appears**\n\n- USA, Canada, Germany, Austria, Switzerland and the France admin\n  fields need a street-accurate coordinate (`rooftop`,\n  `arrival_point`, `street_interpolated` or `street_centroid` —\n  never a postcode/locality/admin centroid, where the point could\n  fall in the wrong small area).\n- The France `building` block and the whole UK block need a\n  premise-level match (`rooftop` / `arrival_point`). The UK block\n  is keyed on the matched address's `uprn` (ONS National Statistics\n  UPRN Lookup). Great Britain only — Northern Ireland (BT\n  postcodes) carries no block because NI statistical geography is\n  separately licensed.\n- Finland and the Netherlands are keyed on the validated postcode;\n  the block describes the whole postal area (see its `scope`\n  field), not the individual household.\n- Japan derives the 500 m JIS X 0410 mesh cell from the\n  coordinate.\n- Singapore joins on the standardized block number + street; HDB\n  blocks only, so a miss on private housing is normal.\n- Belgium is keyed on the matched row's 9-character Statbel\n  statistical sector (also emitted as `statistical_sector`); a\n  Belgian postcode spans several sectors, so a postcode-grain join\n  would attribute one sector's figures to all of them.\n- Spain resolves the 10-digit census section (CUSEC) from the INE\n  Callejero — municipality + street + house-number range + parity —\n  and falls back to municipality level when no range covers the\n  number. The block's `scope` says which tier answered\n  (`census_section` or `municipality`); the parity filter is\n  load-bearing and refuses rather than assigning the wrong side of\n  the street.\n- Portugal, Ireland, Sweden, Luxembourg and Hong Kong are\n  point-in-polygon on the returned coordinate, each returning a\n  `statistical_area` block whose `code` is that country's finest\n  published unit: Portugal BGRI subsecção (11 chars, block-level),\n  Ireland CSO Small Area (2022), Sweden DeSO, Luxembourg commune\n  (LAU2), Hong Kong Small Subunit Group.\n- Three Irish Small Areas genuinely overlap (slivers of 38–433 m²\n  from 20 m generalisation). A point inside one is reported as\n  ambiguous rather than silently resolved — picking the smallest\n  area would cross an electoral-district boundary in Carlow.\n\nEnrichment can accompany `partial_match: true` when the inferred\ncoordinate still reaches a qualifying tier (e.g.\n`street_centroid`); postcode-, locality- and admin-centroid\nfallbacks never carry it.\n\nStatistical layers respect the publisher's disclosure control:\nwithheld values are absent from the block — an absent value is not\na zero (Swiss hectare grid, Dutch PC6, Japanese age bands) — and\nGerman Zensus grid counts are Cell-Key perturbed. Each such block\nsays so in its `note`.\n","additionalProperties":true,"properties":{"state_fips":{"type":"string","description":"USA: 2-digit state FIPS."},"county_fips":{"type":"string","description":"USA: 5-digit county FIPS (state+county)."},"census_tract":{"type":"string","description":"USA: 11-digit census tract GEOID. Canada: CTUID (urban areas only)."},"block_group":{"type":"string","description":"USA: 12-digit block-group GEOID."},"cbsa":{"type":"object","description":"USA: Core-Based Statistical Area (metro/micro). Omitted (not null) outside any CBSA.","properties":{"code":{"type":"string"},"name":{"type":"string"},"type":{"type":"string","enum":["metro","micro"]}}},"congressional_district":{"type":"object","description":"USA: 119th-Congress district (`00` at-large; `98`/`99` non-voting).","properties":{"state_fips":{"type":"string"},"district":{"type":"string"},"congress":{"type":"integer"}}},"school_district":{"type":"object","description":"USA: school district.","properties":{"name":{"type":"string"},"type":{"type":"string","enum":["unified","elementary","secondary"]}}},"dissemination_area":{"type":"string","description":"Canada: 8-digit Dissemination Area UID (province + census division + DA)."},"province_code":{"type":"string","description":"Canada: 2-digit province/territory (SGC)."},"census_division":{"type":"string","description":"Canada: 4-digit census division UID."},"census_subdivision":{"type":"object","description":"Canada: census subdivision (municipality).","properties":{"code":{"type":"string"},"name":{"type":"string"}}},"cma_ca":{"type":"object","description":"Canada: Census Metropolitan Area / Census Agglomeration. Omitted outside both.","properties":{"code":{"type":"string"},"name":{"type":"string"},"type":{"type":"string","enum":["metro","agglomeration"]}}},"federal_electoral_district":{"type":"object","description":"Canada: federal electoral district.","properties":{"code":{"type":"string"},"name":{"type":"string"}}},"ags":{"type":"string","description":"Germany: 8-digit Amtlicher Gemeindeschlüssel."},"ars":{"type":"string","description":"Germany: 12-digit Amtlicher Regionalschlüssel."},"gemeinde":{"type":"string","description":"Germany / Austria / Switzerland: municipality name."},"gemeinde_type":{"type":"string","description":"Germany: municipality kind (Stadt, Gemeinde, Kreisfreie Stadt, …)."},"bundesland":{"type":"object","description":"Germany / Austria: federal state.","properties":{"code":{"type":"string"},"name":{"type":"string"}}},"kreis":{"type":"object","description":"Germany: district.","properties":{"code":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"}}},"nuts3":{"type":"string","description":"Germany: NUTS-3 code (e.g. DEA12)."},"bundestagswahlkreis":{"type":"object","description":"Germany: Bundestag electoral constituency.","properties":{"number":{"type":"integer"},"name":{"type":"string"}}},"gkz":{"type":"string","description":"Austria: 5-digit Gemeindekennziffer."},"politischer_bezirk":{"type":"object","description":"Austria: political district.","properties":{"code":{"type":"string"},"name":{"type":"string"}}},"regionalwahlkreis":{"type":"object","description":"Austria: regional electoral constituency.","properties":{"code":{"type":"string"},"name":{"type":"string"}}},"zaehlsprengel":{"type":"string","description":"Austria: census enumeration district (smallest census unit)."},"bfs_nummer":{"type":"string","description":"Switzerland: BFS municipality number."},"kanton":{"type":"object","description":"Switzerland: canton — also the Nationalrat electoral constituency.","properties":{"number":{"type":"integer"},"code":{"type":"string"},"name":{"type":"string"}}},"bezirk":{"type":"object","description":"Switzerland: district.","properties":{"number":{"type":"integer"},"name":{"type":"string"}}},"grossregion":{"type":"object","description":"Switzerland: major region = Swiss NUTS-2 unit.","properties":{"number":{"type":"integer"},"nuts2":{"type":"string"},"name":{"type":"string"}}},"sprachgebiet":{"type":"object","description":"Switzerland: official language region — which language to address this customer in.","properties":{"language":{"type":"string","description":"ISO 639-1: de/fr/it/rm"},"name":{"type":"string"}}},"degree_of_urbanisation":{"type":"object","description":"Switzerland: Eurostat DEGURBA class.","properties":{"code":{"type":"string","enum":["city","town_suburb","rural"]},"name":{"type":"string"}}},"stadt_land":{"type":"string","enum":["urban","intermediate","rural"],"description":"Switzerland: BFS Stadt/Land typology."},"gemeindetyp":{"type":"object","description":"Switzerland: BFS municipality typology (9 classes); `class` is the 3-fold split.","properties":{"code":{"type":"string"},"class":{"type":"string","enum":["urban","periurban","rural"]}}},"agglomeration":{"type":"object","description":"Switzerland: agglomeration.","properties":{"code":{"type":"string"},"name":{"type":"string"}}},"arbeitsmarktregion":{"type":"object","description":"Switzerland: labour-market region.","properties":{"code":{"type":"string"},"name":{"type":"string"},"macro_region":{"type":"string"}}},"insee":{"type":"string","description":"France: INSEE commune code."},"commune":{"type":"string","description":"France: commune name."},"departement":{"type":"object","description":"France: département.","properties":{"code":{"type":"string"},"name":{"type":"string"}}},"region":{"type":"object","description":"France: région. UK: ONS region.","properties":{"code":{"type":"string"},"name":{"type":"string"}}},"iris":{"type":"object","description":"France: INSEE IRIS statistical district (metropolitan France).","properties":{"code":{"type":"string"},"name":{"type":"string"},"type":{"type":"string","enum":["residential","economic_activity","miscellaneous","whole_commune"]}}},"building":{"type":"object","description":"France, premise-level matches only: the IGN BD TOPO building the coordinate falls on (or the nearest within 8 m). `coord_verified` is true when the point is inside or ≤ 2 m from the footprint. `sub_unit_expected` is true when the building is multi-dwelling and the caller supplied no apartment/unit — the address is probably incomplete.","properties":{"coord_verified":{"type":"boolean"},"match_type":{"type":"string","enum":["inside","nearest"]},"distance_m":{"type":"number"},"building_type":{"type":"string","description":"e.g. Unspecified, Church, Castle, …"},"usage":{"type":"string","description":"Residential, Commercial and services, Industrial, …"},"usage_secondary":{"type":"string"},"height_m":{"type":"number"},"floors":{"type":"integer"},"dwellings":{"type":"integer"},"is_multi_dwelling":{"type":"boolean"},"rnb_id":{"type":"string","description":"French national building registry (RNB) id."},"sub_unit_expected":{"type":"boolean"},"source":{"type":"string"}}},"output_area":{"type":"string","description":"UK: 2021 Output Area code — finest ONS tier; output areas have no name."},"lsoa":{"type":"object","description":"UK: Lower layer Super Output Area.","properties":{"code":{"type":"string"},"name":{"type":"string"}}},"msoa":{"type":"object","description":"UK: Middle layer Super Output Area.","properties":{"code":{"type":"string"},"name":{"type":"string"}}},"local_authority":{"type":"object","description":"UK: local authority district.","properties":{"code":{"type":"string"},"name":{"type":"string"}}},"ward":{"type":"object","description":"UK: electoral ward.","properties":{"code":{"type":"string"},"name":{"type":"string"}}},"westminster_constituency":{"type":"object","description":"UK: Westminster parliamentary constituency.","properties":{"code":{"type":"string"},"name":{"type":"string"}}},"country":{"type":"object","description":"UK: constituent country (England, Scotland, Wales).","properties":{"code":{"type":"string"},"name":{"type":"string"}}},"police_force_area":{"type":"object","description":"UK: police force area.","properties":{"code":{"type":"string"},"name":{"type":"string"}}},"rural_urban":{"type":"object","description":"UK: rural/urban classification.","properties":{"code":{"type":"string"},"description":{"type":"string"}}},"demographics":{"type":"object","description":"Germany: Zensus 2022 100 m grid — grid_cell, population, avg_age, avg_household_size, avg_net_rent_per_sqm, owner_occupier_pct, vacancy_pct, foreign_national_pct; small counts are Cell-Key perturbed (approximate). Switzerland: BFS STATPOP 100 m hectare grid — hectare_cell, population, buildings, dwellings; withheld cells are absent (an absent value is not a zero). Always carries `note` and `source`.","additionalProperties":true},"economy":{"type":"object","description":"Switzerland: BFS STATENT hectare-grid workplace stats — hectare_cell, workplaces, employees_fte, note, source.","additionalProperties":true},"postal_area":{"type":"object","description":"Finland: Statistics Finland PAAVO statistics for the whole postal area (`scope: postal_area`) — names (fi/sv), municipality_code, area_km2, centroid, population + age bands, mean/median incomes (personal and household), employment, jobs_total, households by type/tenure, dwellings, avg_dwelling_area_m2, summer_cottages. CC BY 4.0; `source` inside the block.","additionalProperties":true},"postcode_area":{"type":"object","description":"Netherlands: CBS Kerncijfers for the six-character postcode (`scope: postcode6_area`) — inhabitants + age bands, households by type, dwellings, avg_home_value_eur, pct_owner_occupied, pct_rented, persons_on_benefits, avg_gas_m3, avg_electricity_kwh. CBS-suppressed cells are absent, never 0.","additionalProperties":true},"mesh_area":{"type":"object","description":"Japan: 2020 Population Census on the 500 m JIS X 0410 mesh (`scope: mesh_500m`) — mesh_code, pop_total, pop_male, pop_female, pop_0_14, pop_15_64, pop_65_plus, households. Withheld age bands are absent.","additionalProperties":true},"hdb_block":{"type":"object","description":"Singapore: HDB Property Information for the matched block (`scope: hdb_block`) — bldg_contract_town, max_floor_lvl, year_completed, residential / commercial / market_hawker / multistorey_carpark / precinct_pavilion / miscellaneous flags, total_dwelling_units and the full unit mix (units_1room … units_studio, rental_1room … rental_other). HDB blocks only — private housing has no block.","additionalProperties":true},"statistical_sector_area":{"type":"object","description":"Belgium: Statbel figures for the address's statistical sector (`scope: statistical_sector`) — municipality NIS code and names (NL/FR), sector names, population, density, area, and median / mean taxable income with its reference year.","additionalProperties":true},"census_section_area":{"type":"object","description":"Spain: INE figures for the census section resolved from the Callejero (`scope: census_section`), or for the municipality when no house-number range covers the address (`scope: municipality`). Carries `cusec` (10-digit section code) when section-level, plus population, age structure, nationality mix, household size, education breakdown and the household income series (net / gross, per person and per household). `income_top_coded: true` marks INE's censoring ceiling. Withheld figures are absent, not zero.","additionalProperties":true},"statistical_area":{"type":"object","description":"Portugal, Ireland, Sweden, Luxembourg and Hong Kong: the country's finest published statistical unit, resolved by point-in-polygon on the returned coordinate (`scope: statistical_area`). `code` is the official identifier — Portugal BGRI subsecção (11 chars, block-level, with its dt / dtmn / dicofre components and the Censos 2021 building, dwelling, household and population counts); Ireland CSO Small Area 2022 (~100 dwellings, with SAPS age, tenure, education and commuting); Sweden DeSO (with its RegSO, kommun and län codes); Luxembourg commune LAU2 (with canton, district and STATEC census figures); Hong Kong Small Subunit Group (2021 Census, names in English and Traditional Chinese). ⚠️ Ireland only: three Small Areas overlap in slivers of 38–433 m². A point inside one is reported ambiguous rather than resolved to a single area.","additionalProperties":true},"source":{"type":"string","description":"Attribution for the country's primary layer (present for USA, Canada, Germany, Austria, Switzerland, France and the UK). Sub-blocks (`demographics`, `economy`, `building`) and the whole-block countries (`postal_area`, `postcode_area`, `mesh_area`, `hdb_block`) carry their own `source` inside the block — there is no top-level `source` for Finland, the Netherlands, Japan or Singapore. Reproduce these strings where the underlying data licence requires attribution (CC BY 4.0, Etalab 2.0, dl-de/by-2-0, Statistics Canada Open Licence, Singapore Open Data Licence)."}}},"match_type_legacy":{"type":"string","enum":["exact","fuzzy"],"description":"Retained for backward compatibility. New clients should use `match_type`."},"match_score_legacy":{"type":"string","description":"Retained for backward compatibility. Human-readable label (e.g. `\"Perfect match\"`, `\"Partial match (street only)\"`)."},"suggestions":{"type":"array","description":"Ranked near-miss candidates (score ≥ 0.5, below the correction threshold). Appears on 200 `partial_match` responses where the street could not be matched — the closest real streets in the caller's postcode/locality (up to 3 items) — and on 404 no-match responses. Not normally present on verified/corrected successes.","items":{"$ref":"#/components/schemas/Suggestion"}},"alternative_matches":{"type":"array","description":"Reserved — not currently emitted (disabled pending an index). Planned behaviour: same street + house number in a different state, USA / CAN `verified` matches, up to 5 items.","items":{"$ref":"#/components/schemas/AlternativeMatch"}},"lat":{"type":"number","format":"float"},"lng":{"type":"number","format":"float"},"arrival_point":{"type":"object","description":"Entrance / access coordinate (arrival point) of the matched premise, returned beside the served coordinate on house-number-level matches when the reference row carries one. With `accuracy_type: rooftop` this is the door/curb point of the same address (useful for delivery and navigation); with `accuracy_type: arrival_point` it simply equals `lat`/`lng`. Omitted when the match is not premise-level or no arrival point is on file — never null.","properties":{"lat":{"type":"number","format":"float"},"lng":{"type":"number","format":"float"}}},"landmark_used":{"type":"object","description":"Present ONLY with `accuracy_type: landmark_proximity` (India). The address itself resolved no further than its postcode/locality, so the served coordinate was taken from a landmark named in the input. This block says which one, so the substitution is never silent: `name` is the stored name of the place we used, `matched_from` is the caller's own words that matched it, `scope` is the evidence that identified it uniquely (`pin_exact`, `pin_contains`, `locality_exact`, `locality_contains`), and `source` is the data attribution. Omitted on every other tier — never null.","required":["name","matched_from","scope","source"],"properties":{"name":{"type":"string","example":"Patiala House"},"matched_from":{"type":"string","description":"The landmark text as the caller wrote it.","example":"Patiala House"},"scope":{"type":"string","x-extensible-enum":["pin_exact","pin_contains","locality_exact","locality_contains"]},"source":{"type":"string","example":"Overture Maps Foundation (CDLA-Permissive-2.0)"}}},"house_number_not_found":{"type":"boolean","description":"The house number you sent is not on file for the matched street — either flagged by the matcher itself, or caught by the input-vs-returned comparison (a fallback row carried a different number). standardized keeps YOUR house number in this case; match tier is capped at street_level."},"postcode_corrected":{"type":"boolean"},"deliverable":{"type":"boolean","description":"`true` only when the address verified confidently against the reference data — `confidence_level` high or medium AND not a partial/centroid fallback AND a premise is identified (a house number you supplied, or a UK premise anchor / named building). This is the same threshold the on-page widget uses for its \"valid & deliverable\" verdict, so API and UI never disagree. Reflects confirmation against our authoritative reference data; it is not a CASS/DPV-certified delivery guarantee."},"hno_range_verified":{"type":"boolean","description":"The house number was confirmed against an official numbering RANGE for the street, not an individual premise row (interpolated-tier evidence, e.g. Brazil's official street ranges). Caps `confidence_level` at `medium` — `high` is reserved for premise-level verification."},"parsed":{"type":"object","description":"Always returned. For single-line `input`: the parser's field breakdown (informational echo; lowercase). For fielded input: an echo of the supplied fields. Keys include `street`, `house_number`, `city`, `postcode`, `state`, `sublocality`, `unit`, `floor`, `po_box`, `country`. Useful for debugging why a free-form string matched the way it did. Informational only, not a stable contract: formats can change between releases (for Spain, `floor` carries a normalised code such as `1`, `BJ` for ground floor or `-1` for a basement). Use `standardized` for anything you store or display.","additionalProperties":true},"match_details":{"type":"object","description":"Per-component flags from the DB lookup — keys `street`, `house_number`, `city`, `postcode` (not `zip`), `state` (when applicable), plus a duplicated `postcode_corrected` boolean. Unlike `match_components` — which scores only what the caller provided — `match_details` reports what the matched row confirmed, so the two may legitimately differ. Absent on SEG centroid-fallback responses (still present on street-tier partials).","additionalProperties":true},"unverified_fields":{"type":"array","items":{"type":"string"},"description":"Components echoed from the caller's input that reference data could NOT confirm (e.g. `[\"unit\"]` — reference rows carry no unit data). The match itself still stands; treat the listed components as unverified input, not reference data."},"unit_verified":{"type":"boolean","description":"Spain, Latvia and Singapore only. Present and `true` only when the sub-building unit you sent is listed for the matched building. Spain: staircase / floor / door (e.g. `Esc. 1, 1º B`) listed for the matched portal in a 2017 building-unit snapshot. It means \"listed in that snapshot\", nothing more: the snapshot is not current and covers multi-unit portals only. Latvia: the flat is in the State Address Register's dwelling list for the matched building. Singapore: the `#floor-unit` you sent (e.g. `#12-1415`, `#B2-19`) is in the unit list of the matched block; the floor-unit may be written with or without the `#` marker. Absent when no unit was sent, when no house number was sent, and in every other country. It never changes `confidence`."},"former_address":{"type":"object","description":"Latvia only. The address you sent is a FORMER address of the matched building in the State Address Register: the street was renamed, the building was renumbered, or a named property got a street address (or the reverse). `standardized` holds the current address. The change is disclosed in `corrections` (`Street`, `House number`) and `status` is `corrected`. Absent when the address you sent is current, and in every other country.","properties":{"street":{"type":"string","description":"The former street, or the former property name."},"house_number":{"type":"string","description":"The former house number (empty for a former property name)."},"city":{"type":"string","description":"City or village at the time (may be empty)."},"parish":{"type":"string","description":"Parish (pagasts) at the time (may be empty)."},"postcode":{"type":"string","description":"Postcode at the time (empty for records older than 2003)."},"valid_until":{"type":"string","format":"date","nullable":true,"description":"Last day the former address was in force, when recorded."},"change":{"type":"string","enum":["renumbered","street_renamed","renamed_and_renumbered","street_to_property","property_renamed","property_to_street"],"description":"What changed between the former and the current address."}}},"tenant_name_matched":{"type":"string","description":"Singapore only. The tenant or shop name (e.g. `MCDONALD'S`) that text in your input matched at the returned building, exactly as we hold it. The name is not part of the standardized address and never enters `formatted_address`. Absent when your input carried no tenant name."},"building_name_matched":{"type":"string","description":"Singapore only. The building name that text in your input matched at the returned building, when it differs from `standardized.building_name` (another name the same building is known by). Absent when it is the same name or none was matched."},"unit_check":{"type":"string","enum":["verified","not_in_list","no_data"],"description":"Spain, Latvia and Singapore only. What the reference unit list could say about the unit you sent. `verified`: listed at this building. `not_in_list`: the building has a unit list and yours is not in it. `no_data`: no usable list for this building (Spain: portal not covered, ambiguous match, or a single-dwelling portal; Latvia: checked against the State Address Register's dwelling list, and `no_data` when the building has no registered dwellings, as for single-dwelling houses, or the match is ambiguous; Singapore: the unit lists are not complete for every building, so `not_in_list` means the unit should be re-checked with the addressee, never that it does not exist, and `no_data` is returned when the building has no usable list or the list cannot rule the unit out). For `not_in_list` and `no_data` the response also lists `\"unit\"` in `unverified_fields`; the address match and `confidence` are unchanged and your unit is still echoed in `standardized.unit`. A unit the parser cannot read at all (`pta`, `Oficina 3`, `Bloque`) also answers `no_data`. Absent when no unit was sent."},"postcode_unverified":{"type":"boolean","description":"The postcode was echoed from the caller, never read from a reference row."},"locality_from_postcode":{"type":"boolean","description":"The city was derived from the postcode rather than typed by the caller."},"city_backfilled_from_postcode":{"type":"boolean","description":"No city was sent; the one in `standardized.city` was derived from the postcode (or, Netherlands, from the postcode + house number). A disclosure, not a correction. Absent otherwise."},"street_backfilled_from_postcode":{"type":"boolean","description":"Netherlands: no street was sent; the street in `standardized.street` is the one that holds the house number at the postcode sent. A disclosure, not a correction (`corrections` stays empty). Absent otherwise."},"matched_via_alias":{"type":"boolean","description":"The locality matched through a recognised alias (e.g. a USPS alternate city name) rather than the primary name. `usps_city` and `locality_note` disclose the specifics where applicable."},"usps_city":{"type":"string","description":"USA: the USPS-preferred city name when it differs from the input."},"locality_note":{"type":"string","description":"Human-readable note on how the locality was matched (alias / municipality disclosure)."},"city_mismatch_ignored":{"type":"boolean","description":"The typed city disagreed with the matched row but was overridden by stronger evidence (street + postcode); disclosed rather than silently dropped."},"postcode_supplied":{"type":"string","description":"Postcode-repair forensics — the postcode the caller sent. Also present on its own (without `postcode_suggested`) when the reasons carry `postcode_not_matched` (Sweden): the typed postcode matched nothing in the reference data, so it is returned here as typed and `standardized.postcode` is null."},"postcode_suggested":{"type":"string","description":"Postcode-repair forensics — the reference postcode for the matched premise, when it differs from `postcode_supplied`."},"postcode_incoherent":{"type":"boolean","description":"`true` when the supplied postcode does not fit the matched street/locality at all (rather than being a near-miss)."},"postcode_status":{"type":"string","x-extensible-enum":["stocked","unknown","valid_not_stocked"],"description":"Malaysia: whether the postcode is held with addresses (`stocked`), real but with no addresses on file (`valid_not_stocked` — see the matching reason code), or unknown. Companion fields `postcode_place` / `postcode_state` name the postal place when known."},"accuracy_label":{"type":"string","description":"Human-readable form of the served tier (e.g. `\"postcode centroid\"`). Display-only; branch on `accuracy_type` / `point_coordinate`."},"non_deliverable_type":{"type":"string","description":"Classification of non-deliverable input (e.g. `po_box`). Appears on the 400 rejection body, or on the 200 body under `iso20022: true`."},"uprn_match_m":{"type":"number","description":"UK only. Distance in metres between the Royal Mail PAF delivery point and the matched OS Open UPRN coordinate (0.0 is a real and best value). Present when extended UK fields are enabled (on by default)."},"credits_remaining":{"type":"integer","description":"After keyed validation."},"validation_credits_remaining":{"type":"integer"},"geocode_credits_remaining":{"type":"integer"},"key_accepted":{"type":"boolean"}}},"GeocodeErrorBody":{"type":"object","description":"Error body for 404 on the legacy `/geocode-usa` and `/geocode-uk` shorthand\nendpoints. Carries the match-quality contract so clients can key on the same\nfields regardless of success or failure. Unlike `ValidateErrorBody`, geocode\nerrors do not include `suggestions`. A `/geocode-usa` 404 may carry\n`reasons` and `did_you_mean` when the engine can name the ambiguity —\ne.g. `reasons: [\"street_type_ambiguous\"]` with candidate streets (see\n`FailureReason` and `ValidateErrorBody.did_you_mean`). The no-match body omits\n`accuracy_type`, so it is not in the required list. For `/geocode` and\n`/v1/geocode`, see `ForwardGeocodeErrorBody` instead — the AV match-quality\ncontract was retired from those two routes.\n","required":["error","match_type","match_score","match_components","input_corrected"],"properties":{"error":{"type":"string","example":"Address not found"},"accuracy_type":{"$ref":"#/components/schemas/AccuracyType"},"point_coordinate":{"type":"boolean","description":"`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. Optional but always emitted on a match."},"match_type":{"$ref":"#/components/schemas/MatchType"},"match_score":{"type":"number","format":"float","minimum":0,"maximum":1},"match_components":{"$ref":"#/components/schemas/MatchComponents"},"input_corrected":{"type":"boolean"},"reasons":{"type":"array","description":"`/geocode-usa` only, when present — e.g. `street_type_ambiguous` (with `did_you_mean`). Absent on most geocode misses.","items":{"$ref":"#/components/schemas/FailureReason"}},"did_you_mean":{"type":"array","description":"Candidates the caller may have meant (e.g. for `street_type_ambiguous`) — see `ValidateErrorBody.did_you_mean`.","items":{"type":"object","additionalProperties":true}}}},"ForwardGeocodeErrorBody":{"type":"object","description":"Error body for 404 (no match) and 422 (uninterpretable input) on `/geocode`\nand `/v1/geocode`. Deliberately not `GeocodeErrorBody`'s shape — no\n`match_type`, `match_score`, `match_components`, or `input_corrected`. A miss\nstates the fact plainly and nothing else.\n\n**Portugal (`country: prt`):** a 404 may also carry `reasons` (why the\nlookup missed), `did_you_mean` (what the input most likely meant —\nnever applied automatically) and `did_you_mean_truncated`, and\n`message` is then a specific English sentence, e.g. `Street 'Rua de\nPortugal' not found in Estoril; did you mean Avenida de Portugal?`.\nThese keys are optional and additive: they are absent for other\ncountries and whenever nothing more specific than \"not found\" is\nknown.\n","required":["error"],"properties":{"error":{"type":"string","example":"no_match"},"message":{"type":"string","example":"Address not found","description":"Human-readable English text. Generic (`Address not found`) unless a specific explanation is available (Portugal). For display only — branch on `reasons`, never on this text."},"reasons":{"type":"array","description":"Portugal only: machine-readable classification of the miss, most specific first — see `FailureReason` (e.g. `city_not_found`, `street_not_found`, `street_found_in_multiple_localities` + `city_missing`, `locality_ambiguous` + `street_missing`, or `street_type_mismatch` + `street_not_found`). Absent when nothing more specific is known.","items":{"$ref":"#/components/schemas/FailureReason"}},"did_you_mean":{"type":"array","description":"Portugal: up to 6 candidates the input most likely meant, for you to choose from and resubmit — never applied automatically. See `DidYouMeanEntry` for which fields each case carries.","items":{"$ref":"#/components/schemas/DidYouMeanEntry"}},"did_you_mean_truncated":{"type":"boolean","description":"`true` when more candidates exist than `did_you_mean` lists (a street sent without a city that exists in more than 6 towns; the 6 with the most house numbers are listed). Absent otherwise."},"locality_count":{"type":"integer","example":538,"description":"A street sent WITHOUT a city that exists in several places: how many places it was found in. `message` then reads `That street exists in several places (538). Please specify a city or postcode.` and `reasons` carries `street_found_in_multiple_localities` + `city_missing`. Not sent for Spain, nor when the count could not be established."},"locality_count_exact":{"type":"boolean","description":"With `locality_count`: `true` when exact, `false` when a lower bound (`message` reads `N or more`)."}}},"ValidateErrorBody":{"type":"object","description":"Error body for 404 and 422 on `/validate` — and for the 400 returned on\nnon-deliverable input (PO Box etc.), which carries `match_type:\n\"non_deliverable\"` plus `non_deliverable_type`. Carries the\nmatch-quality contract so clients can key on the same fields regardless\nof success or failure.\n","required":["error","match_type","match_score","match_components","input_corrected","accuracy_type"],"properties":{"error":{"type":"string","example":"Address not found"},"message":{"type":"string","description":"Human-readable English text; for display only, branch on `error` and `reasons`. Where we can say more it is specific: `That street exists in several places (538). Please specify a city or postcode.` for a street sent with no city (400 `Missing required field: city`, or the 404 for 2-6 places; Netherlands: `Please specify a city.` when the postcode sent is not on file; USA: a street sent with no city and no ZIP says to add the city and state or a ZIP code); what to send for `Country is required` (400) and for `Input must be a single-line string or a fielded/JSON object` (422)."},"accuracy_type":{"$ref":"#/components/schemas/AccuracyType"},"point_coordinate":{"type":"boolean","description":"`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. Optional but always emitted on a match."},"match_type":{"$ref":"#/components/schemas/MatchType"},"match_score":{"type":"number","format":"float","minimum":0,"maximum":1},"match_components":{"$ref":"#/components/schemas/MatchComponents"},"input_corrected":{"type":"boolean"},"reasons":{"type":"array","description":"One or more classifications of why the match failed. (The same codes also appear on 200 `partial_match` responses — see `ValidateResponse.reasons`.)","items":{"$ref":"#/components/schemas/FailureReason"}},"did_you_mean":{"type":"array","description":"404 only, when present: candidate addresses the input most likely meant, for the caller to choose from and resubmit — never applied automatically. Sent with `reasons: [\"street_type_ambiguous\"]` (USA: the same street name with different types/directionals, each entry `street` + `city` + `postcode`) and on some locality/street ambiguities in other countries. Portugal: also when the street is not in the town you sent but a street of that town differs only in type, linking particles or spelling (`street_type_mismatch` / `street_particle_mismatch` / `street_spelling_mismatch`, each entry `street` + `city` + `doors` + `match`), when a street sent without a city exists in several towns (`street`, `city`, `municipality`, `doors`), and when a place name sent on its own is ambiguous (`locality_ambiguous`: `city`, `municipality`, `district`). Sent alongside `suggestions` (which are unchanged). Netherlands: when several streets hold the house number at the postcode sent (`postcode_house_number_ambiguous`), each entry is `street` + `city` + `postcode` + `house_number`; the same shape lists the letters on a 200 with `house_number_extension_missing`. See `DidYouMeanEntry`. Pass unrecognized entry fields through.","items":{"type":"object","additionalProperties":true,"properties":{"house_number":{"type":"string","description":"Netherlands — the house number incl. its letter (`12A`).","example":"12A"},"street":{"type":"string","example":"12th St NE"},"city":{"type":"string","example":"Canton"},"postcode":{"type":"string","example":"44704"},"municipality":{"type":"string","description":"Portugal — the municipality (concelho) of `city`."},"district":{"type":"string","description":"Portugal (`locality_ambiguous`) — the district of `city`."},"doors":{"type":"integer","description":"Portugal — number of addresses (house numbers) held for that street in that locality."},"match":{"type":"string","x-extensible-enum":["street_type","particles","spelling"],"description":"Portugal — how the candidate differs from what was sent: another street type, other linking particles, or a close spelling."}}}},"did_you_mean_truncated":{"type":"boolean","description":"Portugal, 404 only: `true` when more candidates exist than `did_you_mean` lists (a street sent without a city that exists in more than 6 towns). Absent otherwise."},"locality_count":{"type":"integer","example":538,"description":"A street sent WITHOUT a city that exists in several places: how many places (localities) it was found in. Sent with `reasons` `street_found_in_multiple_localities` + `city_missing` on the 400 `Missing required field: city` (7 or more places) and on the 404 for 2-6 places. Not sent for Spain, nor when the count could not be established."},"locality_count_exact":{"type":"boolean","description":"With `locality_count`: `true` when the count is exact, `false` when it is a lower bound (the `message` then reads `N or more`)."},"received":{"type":"object","description":"Sent on the 400 `Country is required` and the 422 `Input must be a single-line string or a fielded/JSON object`, so an integrator can see how the request arrived. Names and types only, never values; authentication keys are never listed.","properties":{"content_type":{"type":"string","example":"application/json"},"input_type":{"type":"string","enum":["null","string","object","array","number","boolean"],"description":"422 only. The type of `input` as we received it (`null` when absent)."},"param_names":{"type":"array","description":"Parameter names that arrived next to the reserved ones (at most 20).","items":{"type":"string"}}}},"non_deliverable_type":{"type":"string","description":"400 non-deliverable rejections only — what the input is (e.g. `po_box`)."},"suggestions":{"type":"array","description":"Top-3 near-miss candidates scoring ≥ 0.5 but below the 0.85 fuzzy threshold (404 only).","items":{"$ref":"#/components/schemas/Suggestion"}},"parsed":{"type":"object","description":"If present, the parser's best-effort field breakdown of the input.","additionalProperties":true}}},"Iso20022Block":{"type":"object","description":"**Opt-in / beta.** Present only when the request set `\"iso20022\": true` (body)\nor `?iso20022=1`. Maps the validation result onto Swift **CBPR+** postal-address\nshapes and adds an explicit truth verdict — what we could structure, what we can\nactively refute, and what we simply could not confirm. `Ctry` + `TwnNm` are the\nonly mandatory ISO elements: without both, no legal shape exists and\n`cannot_structure` is `true`. Fields not resolved are omitted (not invented).\n","properties":{"structured":{"type":"object","nullable":true,"description":"Fully structured CBPR+ address (component tags only, no `AdrLine`). `null` when the mandatory `Ctry`+`TwnNm` pair is absent. Tags: `Ctry` (ISO alpha-2), `TwnNm`, and — when resolved — `StrtNm`, `BldgNb`, `PstCd`, `CtrySubDvsn`, `Flr`, `Room`, `PstBx`.","additionalProperties":true},"hybrid":{"type":"object","nullable":true,"description":"Hybrid shape for callers that must pass the payee's own street rendering through unaltered (EPC153-22): `Ctry`+`TwnNm` (+ `PstCd`, `CtrySubDvsn`) structured, with the unresolved remainder preserved verbatim in `AdrLine[]`. `null` when mandatory elements are absent.","additionalProperties":true},"cannot_structure":{"type":"boolean","description":"`true` when no legal CBPR+ shape could be emitted (missing Ctry or TwnNm)."},"cannot_structure_reason":{"type":"string","nullable":true,"enum":["country_unresolved","town_unresolved"],"description":"Populated only when `cannot_structure` is `true`."},"mandatory_fields_present":{"type":"boolean","description":"`true` when both `Ctry` and `TwnNm` resolved."},"assertions":{"type":"object","description":"Tri-state truth claims. `null` means \"not tested\" — deliberately distinct from `false` (\"tested and wrong\").","properties":{"town_exists_in_country":{"type":"boolean","nullable":true},"postcode_matches_town":{"type":"boolean","nullable":true},"street_resolved":{"type":"boolean","nullable":true}}},"refutation":{"type":"array","description":"Hard negatives only — claims we can defend as \"this address is wrong\" (e.g. `town_not_in_country`, `postcode_town_mismatch`). A street we simply cannot find is NEVER a refutation.","items":{"type":"string"}},"unresolved":{"type":"array","description":"Coverage gaps — \"we could not confirm\" (e.g. `street_unconfirmed`), never \"this is false\".","items":{"type":"string"}},"suggested":{"type":"object","nullable":true,"description":"Advisory-only reference values the engine deliberately did NOT write into the emitted tags (the payee address passes through unaltered). e.g. `PstCd` when the caller's postcode was incoherent. `null` when there is nothing to suggest.","additionalProperties":true},"confidence_level":{"type":"string","nullable":true,"description":"Mirror of the top-level `confidence_level`."},"match_type":{"$ref":"#/components/schemas/MatchType"},"deliverable":{"type":"boolean","nullable":true},"non_deliverable_type":{"type":"string","nullable":true}}},"InteractiveElementStatus":{"type":"object","description":"Per-element input/result status for one interactive result (named-key JSON rendering of the AD 20-position EIS/ERS strings). Keys present depend on the candidate; `number.extended` = `D` marks a house number interpolated from a range.","additionalProperties":{"type":"object","properties":{"input":{"type":"string"},"result":{"type":"string"},"extended":{"type":"string"}}}},"InteractiveResult":{"type":"object","description":"One ranked candidate in an `InteractiveEnvelope.results[]`.","properties":{"rank":{"type":"integer","description":"1-based rank, ordered by `result_percentage` descending."},"result_percentage":{"type":"number","format":"float","description":"Similarity of the candidate to the parsed input (0–100); the sort key."},"standardized":{"type":"string","description":"Single-line display rendering of the candidate."},"components":{"type":"object","description":"Candidate components: `street`, `house_number`, `postcode`, `locality`.","additionalProperties":true},"element_status":{"$ref":"#/components/schemas/InteractiveElementStatus"},"range":{"type":"object","nullable":true,"description":"Valid house-number range for an unexpanded tail entry.","properties":{"from":{"type":"integer"},"to":{"type":"integer"},"parity":{"type":"string","enum":["odd","even","both"]},"expanded":{"type":"boolean"}}},"accuracy_type":{"$ref":"#/components/schemas/AccuracyType"},"point_coordinate":{"type":"boolean","description":"`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. Optional but always emitted on a match."},"lat":{"type":"number","format":"float","nullable":true},"lng":{"type":"number","format":"float","nullable":true}}},"InteractiveEnvelope":{"type":"object","description":"**Opt-in / beta.** Returned by `POST /validate` when the request set\n`\"mode\": \"interactive\"` (AD-parity resolver). Instead of a single batch verdict,\nit returns a ranked pick-list of candidate addresses / valid house-number ranges,\nkeyed on an AD `ProcessStatus` lattice. A **unique** definite match returns\n`count: 1` with the same result as batch — no pick-list is fabricated. Billed\nidentically to a batch validation (1 transaction). Request-only fields: `mode`\n(`batch` | `interactive`), a **fielded** `input` object (required — a string\ninput is rejected), `max_results` (1–100, default 20), `ranges_to_expand`\n(`none` | `all` | `only_with_valid_items`), `flexible_range_expansion` (bool).\n","properties":{"mode_used":{"type":"string","enum":["interactive","batch","parse"],"description":"The resolver path actually taken (`parse` = degraded)."},"process_status":{"type":"string","description":"AD ProcessStatus lattice value — `V4`..`V1` (verified), `C4`..`C1` (corrected), `I4`..`I1` (incomplete/suggestions), `N2` (reference DB unavailable), `N1` (country unsupported)."},"mailability":{"type":"integer","nullable":true,"minimum":0,"maximum":5,"description":"Mailability score 0–5, derived from `process_status`. Emitted for compatibility; do not branch on it."},"count":{"type":"integer","description":"Number of results returned (after `max_results` capping)."},"count_overflow":{"type":"boolean","description":"`true` when more matches existed than `max_results` allowed."},"max_results":{"type":"integer","description":"Effective (lower-wins) cap actually applied, 1–100."},"results":{"type":"array","items":{"$ref":"#/components/schemas/InteractiveResult"}},"resolution":{"type":"object","nullable":true,"description":"ARC-equivalent — why resolution stopped and how to fix it (present on `Ix` / `Nx` outcomes).","properties":{"codes":{"type":"object","additionalProperties":true},"hint":{"type":"string"}}},"ranges_to_expand":{"type":"string","enum":["none","all","only_with_valid_items"],"description":"Request echo."},"flexible_range_expansion":{"type":"boolean","description":"Request echo."},"country":{"type":"string","description":"Echo of the requested country."}}},"InteractiveErrorBody":{"type":"object","description":"Error body for the four interactive-only failures on `POST /validate`\n(`mode=interactive`). The default `mode: batch` path never emits these.\n  * `unknown_mode` (**400**) — `mode` was neither `batch` nor `interactive`.\n  * `interactive_requires_fielded_input` (**400**) — `input` was a string; interactive needs a fielded object.\n  * `interactive_needs_locality_scope` (**400**) — `country: fra` interactive requires `city` or `postcode` (no street-leading index).\n  * `interactive_resolver_error` (**500**) — the interactive resolver raised.\n","required":["error"],"properties":{"error":{"type":"string","enum":["unknown_mode","interactive_requires_fielded_input","interactive_needs_locality_scope","interactive_resolver_error"]},"message":{"type":"string"},"detail":{"type":"string","description":"Present on `interactive_resolver_error` (truncated exception text)."}}},"GeocodeResponse":{"type":"object","additionalProperties":true,"required":["match_type","match_score","match_components","input_corrected","accuracy_type"],"properties":{"lat":{"type":"number","format":"float"},"lng":{"type":"number","format":"float"},"arrival_point":{"type":"object","description":"Entrance / access coordinate (arrival point) of the matched premise, returned beside the served coordinate on house-number-level matches when the reference row carries one. With `accuracy_type: rooftop` this is the door/curb point of the same address (useful for delivery and navigation); with `accuracy_type: arrival_point` it simply equals `lat`/`lng`. Omitted when the match is not premise-level or no arrival point is on file — never null.","properties":{"lat":{"type":"number","format":"float"},"lng":{"type":"number","format":"float"}}},"formatted_address":{"type":"string"},"street":{"type":"string"},"city":{"type":"string","description":"Present for countries with regions (USA, CAN)."},"town":{"type":"string","description":"Alternative to `city` for countries without regions."},"state":{"type":"string"},"postcode":{"type":"string"},"hno":{"type":"string"},"house_number_not_found":{"type":"boolean","description":"The house number you sent is not on file for the matched street — either flagged by the matcher itself, or caught by the input-vs-returned comparison (a fallback row carried a different number). standardized keeps YOUR house number in this case; match tier is capped at street_level."},"postcode_corrected":{"type":"boolean"},"matched_via_alias":{"type":"boolean","description":"True when a locality alias (USPS city / CAN community) was used."},"usps_city":{"type":"string"},"locality_note":{"type":"string"},"city_mismatch_ignored":{"type":"boolean","description":"Canada only — matched by province + street + HNO, city name ignored."},"accuracy_type":{"$ref":"#/components/schemas/AccuracyType"},"point_coordinate":{"type":"boolean","description":"`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. Optional but always emitted on a match."},"match_type":{"$ref":"#/components/schemas/MatchType"},"match_score":{"type":"number","format":"float","minimum":0,"maximum":1},"match_components":{"$ref":"#/components/schemas/MatchComponents"},"input_corrected":{"type":"boolean"},"balance":{"type":"integer","description":"Remaining geocode transactions after keyed call."},"validation_credits":{"type":"integer"},"free_remaining":{"type":"integer"}}},"ForwardGeocodeResponse":{"type":"object","description":"Response for `GET /geocode` and `POST /v1/geocode`. A strict whitelist of\ngeocoding-only fields — every key that can appear is listed below, and no\n`/validate` AV field (`status`, `deliverable`, `corrections`,\n`match_components`, `match_details`, `match_score`, `match_type`,\n`confidence`, `confidence_level`, `input_corrected`, `provided_components`,\n`parsed`, `partial_match`, `house_number_not_found`,\n`hno_range_verified`, `enrichment`, or any legacy variant) can appear\nhere. `lat`, `lng`, `accuracy_type`, `point_coordinate`, `standardized`\nand `formatted_address` are always present on a 200; the rest — including\nthe billing tail (`balance`/`validation_credits`/`free_remaining`/\n`key_class`/`free_daily_limit`) and the country-conditional fields\n(`attribution`, `uprn`, `digipin`, and for Portugal `reasons`,\n`nearby_house_numbers`, `approximate`, `resolved_level`,\n`resolved_name`) — are emitted only when applicable.\n","required":["lat","lng","accuracy_type","point_coordinate","standardized","formatted_address"],"properties":{"lat":{"type":"number","format":"float"},"lng":{"type":"number","format":"float"},"accuracy_type":{"$ref":"#/components/schemas/AccuracyType"},"point_coordinate":{"type":"boolean","description":"`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":{"type":"object","description":"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 `\"\"`.","properties":{"street":{"type":"string"},"house_number":{"type":"string"},"postcode":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"country":{"type":"string","example":"deu"},"dependent_locality":{"type":"string","description":"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":{"type":"string","description":"Royal Mail PAF sub-element (GBR), finer than dependent_locality."},"dependent_street":{"type":"string","description":"Royal Mail PAF sub-element (GBR) — a secondary street name."},"street_type":{"type":"string","description":"Thoroughfare type carried in its own DB column rather than folded into `street` (e.g. Malaysia's UPU S42 type)."},"suburb":{"type":"string","description":"NZ Post's line between street and post town (NZL). Omitted when it just repeats `city`."},"province":{"type":"string","description":"Province sigla for the mandatory Poste Italiane locality line (ITA)."}}},"formatted_address":{"type":"string","description":"Printable multi-line address block, e.g. for a shipping label."},"arrival_point":{"type":"object","description":"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`.","properties":{"lat":{"type":"number","format":"float"},"lng":{"type":"number","format":"float"}}},"input_modified":{"type":"array","items":{"type":"string"},"description":"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":{"type":"string","description":"GBR only.","example":"Contains OS data © Crown copyright and database right 2026"},"uprn":{"type":"string","description":"GBR only. Ordnance Survey Unique Property Reference Number, present when known."},"digipin":{"type":"string","example":"39J49LL8T4","description":"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":{"type":"array","items":{"$ref":"#/components/schemas/FailureReason"},"description":"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":{"allOf":[{"$ref":"#/components/schemas/NearbyHouseNumbers"}],"description":"PRT only, optional. The house number you sent is not in the reference data; names the nearest same-parity numbers that are. The point is then `street_centroid`, or `street_interpolated` between those numbers."},"street_postcodes":{"type":"array","description":"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.","items":{"type":"object","properties":{"postcode":{"type":"string","example":"9573 PA"},"house_number_from":{"type":"integer","example":3},"house_number_to":{"type":"integer","example":22},"parity":{"type":"string","enum":["odd","even","both"],"description":"Which side(s) of the street the postcode covers within that range."}}}},"street_postcodes_total":{"type":"integer","description":"With `street_postcodes`, how many postcodes the street covers (not capped)."},"street_postcodes_truncated":{"type":"boolean","description":"With `street_postcodes`, `true` when the street covers more postcodes than are listed."},"postcode_range":{"type":"object","description":"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.","properties":{"from":{"type":"string","example":"9573 PA"},"to":{"type":"string","example":"9573 PH"},"text":{"type":"string","example":"from 9573 PA to 9573 PH"}}},"approximate":{"type":"boolean","description":"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":{"allOf":[{"$ref":"#/components/schemas/ResolvedLevel"}],"description":"PRT only, with `approximate`. Which kind of place the point stands for."},"resolved_name":{"type":"string","description":"PRT only, with `approximate`. The place's name as spelled in the reference data."},"balance":{"type":"integer","description":"Remaining geocode transactions after a keyed, non-free-tier call."},"validation_credits":{"type":"integer"},"free_remaining":{"type":"integer","description":"Free calls left today, for anonymous and non-`free_av_geo` free-tier callers."},"key_class":{"type":"string","description":"Present only for verified `free_av_geo` keys — `\"free_av_geo\"`. See `/check-key`."},"free_daily_limit":{"type":"integer","description":"Present only for verified `free_av_geo` keys. Always `1000` (the shared daily allowance)."}}},"ReverseResponse":{"description":"Reverse geocoding response. When the request's `limit=1` (default), the body\nis a single flat result. When `limit>1`, the body contains a `results` array\nof flat result objects plus `count` and top-level `match_type` / `match_score`\nreflecting the best (closest) match.\n","type":"object","additionalProperties":true,"properties":{"country":{"type":"string","example":"usa"},"lat":{"type":"number","format":"float","description":"Latitude of the matched address (not the query point)."},"lng":{"type":"number","format":"float"},"distance_m":{"type":"integer","description":"Distance in metres from the query point to this result."},"accuracy_type":{"$ref":"#/components/schemas/AccuracyType"},"point_coordinate":{"type":"boolean","description":"`true` when the coordinate identifies one address (`rooftop` or `arrival_point`), `false` for any derived/area tier. **Not yet emitted by `/reverse`** — until it is, derive it from `accuracy_type` (`rooftop` / `arrival_point`)."},"match_type":{"$ref":"#/components/schemas/MatchType"},"match_score":{"type":"number","format":"float"},"input_corrected":{"type":"boolean","description":"Always `false` for reverse geocoding (input is coordinates, not an address)."},"street":{"type":"string"},"hno":{"type":"string"},"city":{"type":"string"},"state":{"type":"string","description":"Present for countries with regions (USA, CAN)."},"zip":{"type":"string"},"query":{"type":"object","description":"Echo of the effective query parameters (after clamping).","properties":{"lat":{"type":"number"},"lng":{"type":"number"},"radius_m":{"type":"integer"}}},"results":{"type":"array","description":"Only present when `limit > 1`.","items":{"type":"object"}},"count":{"type":"integer","description":"Only present when `limit > 1`; equals `results.length`."},"units_charged":{"type":"integer","description":"Echoes the number of addresses returned (`count`, or `1` when the\nbody is a flat single result). This equals the trial-key debit;\nStripe-plan keys are debited a flat `1` per request regardless.\nAlways `1` for RapidAPI traffic.\n"},"balance":{"type":"integer","description":"Remaining geocode transactions after keyed call."},"free_remaining":{"type":"integer","description":"Remaining anonymous geocodes for this IP today."}}}}}}