Integration guide
The predict and resolve flow, client rules, errors and a minimal client
Flow
user types -> POST /predict {input, session?} -> {session, suggestions[], attribution}
(repeat per keystroke, debounced, passing session back)
user picks -> POST /resolve {id, session} -> {address{...}}
(the session ends here; start a new one for the next address)Rules your client must follow
- Debounce input, at least 200 ms. Send nothing under the minimum length (3 characters by default); the service returns an empty list anyway.
- Keep the session. Take
sessionfrom the firstpredictresponse and send it on every furtherpredictand on the finalresolveof that one address entry. Discard it afterresolve. - Discard stale responses. If you sent a later
predict, ignore the results of earlier ones. - Show
attributionnext to the suggestion list whenever it is not empty. This is a licence obligation, not a styling choice. - Treat
idas opaque. Do not parse it. Do not store or cache suggestion text. If you must keep a reference, keep theidonly. - Read
address.precision.housemeans a house number was resolved.streetorareameans the user must still complete the address.
Authentication and transport
- Header
Authorization: Bearer <token>on every call, the token fromPOST /auth. - Paths are relative to the Umbrella base URL plus
/address/autocomplete(pending verification of that sub-path). The route names below are relative to that. - JSON in both directions, UTF-8.
- Calls from a browser need your origin to be on the service's allowed-origin list. The list applies to the whole service, not to a single key. Ask for yours to be added. Pending verification: the process for requesting an origin.
POST /predict
| Field | Type | Required | Notes |
|---|---|---|---|
input | string, max 200 | yes | What the user has typed so far |
session | string, max 64 | no | From a previous response; omit to start a session. A value that is not letters and digits is silently replaced with a new session, not rejected |
countries | array of ISO 3166-1 alpha-2 codes | no | Restricts the results to one or more countries, for example ["DE"] or ["DE", "FR"]. Omitted, null or [] means the deployment's default countries (currently ["DE", "AT"]); a country that is not enabled for the deployment returns 422. See Country and address type |
language | string, BCP 47 | no | Defaults to de |
near | object {lat, lng} | no | Bias results toward a point |
The response carries session, up to 5 suggestions and attribution. suggestions is [],
not an error, when the input is too short or nothing matches.
POST /resolve
| Field | Type | Required | Notes |
|---|---|---|---|
id | string, max 512 | yes | A suggestions[].id |
session | string | no | Send it, see rule 2 |
language | string | no | Defaults to de |
The response carries address and verification.
All address string fields are present and can be "". lat and lng can be null.
verification
verification is null unless a second reference source is enabled on the service. It is a
service-wide setting, not per key or per account. When it is present:
status | Meaning | What to do |
|---|---|---|
confirmed | A second source agrees on postcode, city, house number and position (within 150 m) | Accept |
differs | It disagrees on the fields listed in differs: postal_code, city, house_number, location | Show the address and let the user confirm; do not auto-accept |
unavailable | No second source answered | Treat as unverified, not as wrong |
filled lists fields the first source left empty and the second supplied. They are already merged
into address; values from the first source are never overwritten.
Errors
The body always has a detail field, but its shape depends on the error:
- A string, for example
{"detail": "Invalid or missing token."}. This covers401,404,502and the422for a country that is not enabled. - A list of objects, for field validation
422(a field that is too long, a wrong type, a missing field). Each object hasloc,msgandtype.
| Status | Meaning | What to do |
|---|---|---|
401 | Missing or invalid bearer token | Fetch a new token from POST /auth |
404 | resolve only: the id is unknown or expired | Run predict again and let the user pick again |
422 | A country that is not enabled (string detail), or field validation (list detail) | Fix the request |
502 | The address source is unavailable | Show a try-again message. Do not mark the address invalid |
Building the entry field
For the full sequence and a worked example, see Build your own UI.
Debounce and minimum length. Wait 200 to 300 ms after the last keystroke before calling predict,
and send nothing while the trimmed text is shorter than the service minimum (3 characters by default).
Shorter input returns an empty list, so a shorter threshold only wastes calls.
One session per address. Start without a session, keep the one predict returns, send it on every
later predict and on resolve, then drop it. If the user clears the field and starts over, start a new
session. A session that is not letters and digits is silently replaced, so a client that sends
"session": null or a UUID with dashes gets a fresh session every call without noticing.
Empty results. suggestions: [] is a normal answer. Keep the field editable, show "no suggestions"
or nothing, and let the user type the address by hand. Do not treat an empty list as an invalid address.
Retries. Only retry 502, and only a few times with a growing delay. 401 needs a new token, 404
needs a new predict, 422 needs a changed request; retrying any of these unchanged fails again. While a
call is pending, new keystrokes should supersede it (rule 3), not queue behind it.
Keep the user's text. Fill the structured fields only after resolve. Until then the typed text is the
user's own and must not be overwritten when suggestions arrive.
Privacy
What leaves your system: the text the user has typed so far, the optional countries, language and near
position, and the session. The text goes to the service on every keystroke that passes the debounce, and
the service passes it on to an upstream address source. Do not put anything into the field that is not an
address, and do not send near unless the user has agreed to share a position. The upstream source is
chosen on the service and is not part of the contract. Retention and the processing agreement for typed
text are pending verification.
Accessibility for a custom UI
The widget follows the ARIA combobox pattern, and a custom field should do the same:
role="combobox"on the input,aria-autocomplete="list",aria-expandedkept in step with the list,aria-controlspointing at the list.role="listbox"on the list androle="option"on each item, witharia-selectedon the active one andaria-activedescendanton the input.- Keys: up and down move through the list, Enter picks the active suggestion, Esc closes the list. Enter with no active suggestion must still submit or move on as the form normally would.
- Announce the number of suggestions in a polite live region, and render
main_textandsecondary_textas text, never as HTML. - Do not rely on colour alone for the active item, and keep the touch target of a suggestion at least 44 px high.
Mock
Mock data is invented: your own address will not be found. Try Haupt, Bahnhofstr 12 Wien, Schulg, 1010,
Gartenweg München or Strasse Muenchen.
Mock answers predict and resolve on this portal at /mock/api/services/address/autocomplete, with no
token. It follows the service's behaviour, with these limits:
- A fixed dataset of about 3,000 invented streets in 67 German and Austrian cities. Mock covers these two countries only; that is the sample, not the coverage of the service. Real city and postcode pairs, invented street names, approximate coordinates. Nothing outside it is found.
- Matching is case, umlaut and
ßtolerant (strassefindsStraße), on street words and city names, and accepts a house number and a postcode:Hauptstr 12 Graz,Haupt 8010. - At most 5 suggestions, at least 3 characters,
countrieslimited toDEandAT(the sample's countries), thesessionround trip, and the422shapes from above.idvalues look likemock:at-2421:12. resolvereturnsprecision: housewhen the id carries a number, otherwisestreet, and404for an id it does not know.verificationisnull; add?scenario=verifiedfor aconfirmedresult.- No bearer check and no rate limit;
?scenario=unauthorizedreturns the401shape.nearandlanguageare accepted and ignored.attributionis always empty. - The
/v1/predictand/v1/resolveforms the widget calls are accepted too.
Minimal client
Plain JavaScript. BASE is the Umbrella base URL plus /address/autocomplete; KEY is your bearer token.
async function post(path, body, key) {
const r = await fetch(BASE + path, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${key}` },
body: JSON.stringify(body),
});
if (!r.ok) {
const { detail } = await r.json();
throw new Error(typeof detail === 'string' ? detail : JSON.stringify(detail));
}
return r.json();
}
let session = null;
async function predict(text) {
const res = await post('/predict', { input: text, session }, KEY);
session = res.session;
return res; // { session, suggestions, attribution }
}
async function resolve(id) {
const res = await post('/resolve', { id, session }, KEY);
session = null;
return res.address;
}A key used in a browser is visible to anyone on the page. Origin checks stop other sites from using it in a browser, not a script. If that is not acceptable, call the API from your own backend and keep the key there.