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 forq=10 Downing Street&classification=all&limit=100:
- Show
title.matched_substringsgives the character ranges oftitlethat match the query, for highlighting. - Address rows (
type: "address") carry only the label, theuprnand the match ranges: no coordinates, distance, classification or separatepostcodefield. The UPRN lookup returns coordinates, postcode and classification. - Other rows have a
typesuch aspostcode,streetorlocality, nouprn, and ametadataobject whose fields vary by type. - Page with
offsetwhilehas_moreistrue.
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 itssearch_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_idis charged once, about 11 minutes after its set formed, whether or not the user picks an address. Responses withsearch_id: nullcost nothing. - Narrowing a set costs nothing more. A request that sends a live
search_idreuses 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 thesearch_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.
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, includinglocation 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.0or later, such asX-API-Version: 6.26.2, gets the current format.- An earlier release, such as
X-API-Version: 2.150.0, gets the earlier format.
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.