Sessions & Billing
All four geocoding SDKs are built around one billing model: the v2 autocomplete API bills by session, not by request. This page is the shared reference the per-language pages link back to — see Sessions (v2 Autocomplete Billing) for the underlying HTTP-level rules this section builds on.
The rule
A session starts on the first suggest() call on a fresh session object, and ends — closing the session — on either retrieve() or retrieveBatch(). The next suggest() call after that automatically opens a new session. You never see or manage the session_token yourself; every SDK mints, reuses, and rotates it for you.
What a session costs
Measured against the gateway (one token, counting session starts):
| sequence | sessions billed |
|---|---|
3 suggest() calls on one session | 1 |
suggest() → retrieve() → suggest() | 2 |
suggest() → retrieveBatch() → suggest() | 2 |
Two consequences follow directly from this table:
Resolving picks one at a time is expensive. Three sequential retrieve() calls on three different suggestions cost three sessions, because each retrieve() both closes the session it belongs to and — if none is open — starts one. One retrieveBatch() of the same three suggestions costs one session. If you're resolving more than one result at a time — plotting a set of markers, say — always prefer the batch call.
Omitting a stable session token costs roughly 5x. If nothing carries a consistent token across a search, the gateway mints a fresh session for every single keystroke instead of one session covering the whole search. For a typical multi-character search this multiplies cost by roughly 5x. This is exactly the mistake the SDKs exist to prevent — a hand-rolled fetch/URLSession call that constructs a new session (or omits session_token entirely) per keystroke will hit this without any error or warning; the gateway returns HTTP 200 every time.
How each SDK prevents it
Every SDK ties one session object to the lifetime of one search-box interaction:
- JavaScript/TypeScript —
client.geocoding.createSession()returns aSessionthat owns the token;select()/retrieve()/retrieveBatch()close it and the nextsuggest()reopens one automatically. TheuseAutocompletehook owns oneSessionper component instance. - Dart/Flutter —
mapatlas.geocoding.createSession()returns aGeocodeSessionwith the same lifecycle.GeocodeSearchControllercreates exactly oneGeocodeSessionin its constructor and reuses it for the controller's whole lifetime. - Swift —
mapatlas.geocoding.createSession()returns aSession.GeocodeSearchControllercreates one for its lifetime as an@Observablecontroller. - Kotlin —
mapatlas.geocoding.createSession()returns aSession.GeocodeSearchControllerowns one internally and exposes it only throughStateFlow<GeocodeSearchState>.
In all four, constructing a new session object per keystroke — e.g. calling createSession() inside a text-change handler instead of once, up front — reintroduces the roughly-5x cost the SDK is meant to prevent. The reactive controllers exist specifically so you never have to think about this: bind the controller to the lifetime of the search field, not the keystroke.
Retrievability
Not every suggestion can be resolved. The gateway injects locality rows (e.g. two of the fifteen results for q=Amsterdam) alongside ordinary results; those rows are shown in the suggestion list but carry no ord, so they can't be retrieved. Every SDK exposes an isRetrievable check on the suggestion — use it to disable or filter those rows before the user can tap one. See the error-handling section of each language page for what happens if you call retrieve() on a non-retrievable suggestion anyway.