The model in one line
Vepler search is a two-step funnel —suggest as the user types, then
open the full address record for the one they pick. You
are billed per search, not per keystroke.
Keystrokes are free. A search costs 1 credit.
search_id), that search settles a flat 1-credit charge — automatically,
about ten minutes later, whether or not the user picks anything. The record they open is charged
separately, once per address per billing period: look up the same address again within the
same period and you are not charged for it again.search_id is issued. See How a search is billed.Quick start
Two calls: surface suggestions as the user types, then look up the one they choose.x-api-key header and run server-side — your API key
must never reach the browser. Put the search endpoints behind your own backend and proxy the
results to your UI.Step 1: Suggest
search_id is
issued (see How a search is billed).
Address suggestions come back as a discovery projection — a label, the uprn, and the
matched substrings for highlighting. They deliberately carry no coordinates, postcode, or
classification; those arrive with the full record lookup.
Parameters
address (individual properties) or location (postcodes,
towns, places). Omit to search both. Pair with source=address for the most predictable
proximity behaviour.residential, commercial, or all. Filters address results by property class.address (one row per property) or street (one row per named street / USRN — useful for
early keystrokes and street-level pickers).true, excludes historical and superseded addresses — only live, addressable records.lng.lat.geo_mode=restrict.bias (soft: near matches rank higher, distant matches
still returned) or restrict (hard: only address results within radius_meters are returned).
See Proximity.Response
The response is a standard list envelope. Address rows are the slim discovery projection:type is address, postcode, location, etc.; address rows carry uprn.null when no candidate set has formed yet.true when data already holds the complete match set — you can filter further keystrokes
locally instead of calling the API again.limit/offset).searchId, setComplete, hasMore,
totalCount, mainText, matchedSubstrings.Step 2: Select — the full address record
uprn from the chosen suggestion.
Parameters
uprn of the chosen suggestion (1–12 digits). Its full record is returned and charged.geography to add a geographic-context block (administrative
and statistical geographies) to the record.os (OS AddressBase, default) or paf (Royal Mail PAF).search_id — there is nothing to link or complete. The search session
settles on its own (see How a search is billed); the record lookup is
its own, separately deduplicated charge.Response
vepler.address.lookupUprn), the same fields are camelCased — line1,
postTown, classificationCode.How a search is billed
The model is honest and simple: a search that forms a result set costs 1 credit; the record you open is charged once per address per month. Never one charge per keystroke. The lifecycle:search_id is issued, that session settles exactly
one credit, on its own, with nothing for you to do. Narrowing within a set you already hold costs
nothing, and repeat searches that reuse a live set do not open a new session.
search_id entirely. Sessions are
coalesced on the server: keystrokes that fetch a subset of a live candidate set attach to that
session rather than opening a new one. Echoing search_id is a performance optimisation, not a
billing requirement.X-Already-Charged: true) and is not charged again until the next period. Retries after a timeout never
double-charge. See Address Billing & Sessions for the full model.Getting autocomplete right
A search box that fires a raw request on every keystroke feels laggy and burns your rate limit. Four patterns make it feel instant. They are mostly about latency and rate limits — but debouncing and a minimum length also form fewer throwaway result sets, which trims session settlements too.Debounce keystrokes (~300ms)
Set a minimum query length (3 chars)
Cancel superseded requests
AbortController to each request and abort the previous one when a new keystroke
fires. This prevents a slow early response from clobbering a fast later one (out-of-order
results).Reuse the search_id
search_id, pass it back on the next keystroke. The server narrows
within the cached candidate set instead of re-running the whole search — faster for the user,
lighter on your rate limit.Flexibility — the tuning levers
Proximity: bias vs restrict
Pass the map centre (or the user’s location) aslat/lng to make results local. Two modes:
geo_mode=bias
geo_mode=restrict
radius_meters of the point are returned. Best
for “search within this area” experiences. Requires radius_meters.Source and classification
source=addressfor property-level typeahead;source=locationfor postcode / town pickers. Omit to blend both.classification=residential(default) /commercial/allto scope address results to the property class your product cares about.
Granularity: address vs street
granularity=street collapses results to one row per named street (USRN). It shines on early
keystrokes and in “pick a street” flows, where a list of every flat on the road is noise.
Candidate sets: narrow without re-fetching
When a query resolves to a small exact match set, the response carries asearch_id and, often,
set_complete: true. That is your signal to stop calling the API:
First real query returns a candidate set
search_id. If set_complete is true, data is the entire
match set.Further keystrokes narrow locally
set_complete is true, filter the rows you already hold client-side. No new request,
no latency, nothing to meter.Reuse search_id when you do call again
set_complete was false), pass search_id back so it narrows
within the cached set rather than re-running the search.search_id is the billable moment — that session settles its flat 1-credit
charge automatically (see How a search is billed). Narrowing within
a set you already hold is free, so once set_complete is true, filter locally.Cost saving
You are billed 1 credit per search that forms a set and charge-once per address, so keeping your bill low comes down to two things: form fewer throwaway sets, and never pay twice for the same address — the API already handles the second for you.Debounce and gate short queries
Open records only on selection
/v1/address/uprn/{uprn} only when a user
actually picks a result — never speculatively for every suggestion on screen.Charged once per address, per period
Cache within the period
Filter locally when set_complete
Billing transparency headers
Every charged response tells you exactly what happened, so you can reconcile without guessing:search_id is minted by the server when a query first
narrows to a result set — echo it on subsequent suggest calls for faster narrowing, or don’t:
server-side session coalescing keeps the billing identical either way. Record charges
deduplicate on the UPRN, on the server.Rate limits
Suggest and the charged lookups are metered separately.Suggest throughput
429 with a Retry-After header. Debouncing keeps you well under it.Daily spend cap
429 handling and backoff, and contact us for higher limits.
FAQ
Do autocomplete keystrokes cost anything?
Do autocomplete keystrokes cost anything?
search_id is issued), and that session settles a flat 1 credit — see the next question.What if a user searches but never selects a result?
What if a user searches but never selects a result?
search_id
issued), the flat 1-credit session settlement is the only cost — and it applies regardless
of whether anything is selected. Nothing else is charged unless a full record is opened.
Debouncing and a minimum query length reduce how often throwaway sets form.If I look up the same address ten times this month, what am I charged?
If I look up the same address ten times this month, what am I charged?
X-Already-Charged: true) and are
not charged again until the next period.Does a retry after a network timeout double-charge me?
Does a retry after a network timeout double-charge me?
Do I need to send search_id?
Do I need to send search_id?
search_id still cannot be charged per keystroke.Why don't suggestions include coordinates?
Why don't suggestions include coordinates?
/v1/address/uprn/{uprn}. This split is what keeps the type-ahead responses free.Can I supply my own session identifier?
Can I supply my own session identifier?
search_id is always minted by the server — client-generated identifiers are never
accepted. Echo the search_id you receive and every request in that search is grouped and
attributed for you, in your usage dashboard and in billing.Next steps
Address Billing & Sessions
Usage & Limits
429 handling, and backoff.API Reference
Authentication
x-api-key header.