Skip to main content
Address autocomplete takes two calls: GET /v1/search/suggest while the user types, then GET /v1/address/uprn/{uprn} for the address they pick. Make both calls from your server. An API key in browser code can be copied and used against your balance (see Authentication).

Which endpoint

The rest of this page covers the first two.

Quick start

Suggest

GET /v1/search/suggest reads the query as a postcode, an address or a place name and returns address and location suggestions in one list. geo_mode and radius_meters need lat and lng. The centre point applies to address results, so it behaves most predictably with source=address. A bad parameter returns 400 with error.type invalid_request_error, error.code validation_error and error.param naming the parameter: for example lat without lng, geo_mode=restrict without radius_meters, or limit=0.

Response

An example for q=10 Downing Street&classification=all&limit=100:
  • Show title. matched_substrings gives the character ranges of title that match the query, for highlighting.
  • Address rows (type: "address") carry only the label, the uprn and the match ranges: no coordinates, distance, classification or separate postcode field. The UPRN lookup returns coordinates, postcode and classification.
  • Other rows have a type such as postcode, street or locality, no uprn, and a metadata object whose fields vary by type.
  • Page with offset while has_more is true.
The SDK returns the same fields in camelCase: hasMore, totalCount, searchId, setComplete, and on rows mainText and matchedSubstrings.

Candidate sets

When a query matches between 1 and 100 addresses, the server fetches all of them as a candidate set and returns its search_id. Queries with more matches, and requests with source=location or granularity=street, return search_id: null. set_complete: true means data holds the whole set: the response is the first page and limit cut nothing. Request limit=100 and every set arrives whole. Once you hold a whole set, and while the user’s query still starts with the query that produced it, filter the rows you hold instead of calling again. Keep a row when every word of the query is the start of a word in its title, ignoring case, where a word is a run of the letters a to z and digits. The server narrows with the same rule. If no row is left, call again without a search_id. With a smaller limit, send the search_id with the next query instead, and the server answers from the set without searching again. Drop it when the new query no longer starts with the old one (the user deleted characters or edited earlier text): the server would still answer from the old set, which can miss addresses that match the new query. A set is kept for 10 minutes from when it formed. An unknown or expired search_id runs a normal search, as does a narrowing request that matches nothing in the set. Either can form a new set.

A type-ahead input

Wait for a short pause in typing (around 250 ms), do not call for fewer than 3 characters, and abort a request when a newer one replaces it, so a slow early response cannot overwrite a later one. This browser-side sketch applies the length check, the abort and local narrowing. Call it from your debounced input handler.

Streets

granularity=street returns one row per named street instead of one per address, for input such as West Street, Sheffield. Each row has type: "street", a representative centre point in location and the street’s USRN in metadata.usrn. Streets with the same name are told apart by the town in the query and, when you send them, by lat, lng, radius_meters and geo_mode. dataset picks the source: open (Ordnance Survey open data under the Open Government Licence), ngd (the Ordnance Survey National Geographic Database) or open_then_ngd, the default, which reads the NGD only when the open data has no matching street. Sending dataset with any other granularity returns 400. When a page includes open-data streets, the response’s top-level metadata.attribution (not a row’s metadata) holds the attribution you must show wherever those fields are displayed. SDK 6.8.0 has neither dataset nor metadata.attribution; call the endpoint over HTTP when you need them.

Look up the picked address

GET /v1/address/uprn/{uprn} returns the full record for the uprn of the row the user picked. The SDK names these in camelCase: line1, postTown, classificationCode, royalMail. The API reference lists every field.

How a search is billed

In the current suggest format:
  • Suggest requests are not charged one by one.
  • Each candidate set costs 1 credit. A search_id is charged once, about 11 minutes after its set formed, whether or not the user picks an address. Responses with search_id: null cost nothing.
  • Narrowing a set costs nothing more. A request that sends a live search_id reuses it. A request without one joins an existing set when all its matches fall inside one of the last eight sets formed for the same API key in the past 10 minutes. On a key shared by many users that check can miss, so filter locally or send the search_id.
  • A query that no longer narrows the set (characters deleted, a typo fixed, a new address started) can form a new set, which costs another credit.
In the earlier format, each query that returns at least one address is charged a flat amount, and there are no candidate-set charges. Each successful UPRN lookup is charged at the rate shown in your dashboard, and a repeat lookup is charged again unless your account has distinct-record billing: see Address billing. Charged responses carry billing headers, described in Usage and limits; candidate-set charges are not reported on any response. SDK methods return the response body only. To read the headers, add a response hook to the SDK’s HTTP client:

Limits

Candidate-set charges count towards the daily total. Both limits can be changed for your account: email hello@vepler.com. See Usage and limits for retrying after a 429.

Response formats and the version header

Suggest has two response formats. The current one, introduced in release 3.0.0, is described on this page. The earlier one returns full address rows, including location coordinates and postcode, has no search_id or set_complete, and is charged per query. To fix the format, send a release number containing a dot in the X-API-Version header on suggest requests:
  • 3.0.0 or later, such as X-API-Version: 6.26.2, gets the current format.
  • An earlier release, such as X-API-Version: 2.150.0, gets the earlier format.
Without a release number (no header, or the X-API-Version: 2 that the SDK sends on every request), your account’s default applies. That is the current format unless your account is set to the earlier one.