Skip to content

Both copy text to your clipboard — Build with AI copies a setup prompt to paste into Claude Code, Cursor, Codex or Copilot; Copy page as Markdown copies this page to paste into a chat. How it works

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):

sequencesessions billed
3 suggest() calls on one session1
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 a Session that owns the token; select()/retrieve()/retrieveBatch() close it and the next suggest() reopens one automatically. The useAutocomplete hook owns one Session per component instance.
  • Dart/Flutter — mapatlas.geocoding.createSession() returns a GeocodeSession with the same lifecycle. GeocodeSearchController creates exactly one GeocodeSession in its constructor and reuses it for the controller's whole lifetime.
  • Swift — mapatlas.geocoding.createSession() returns a Session. GeocodeSearchController creates one for its lifetime as an @Observable controller.
  • Kotlin — mapatlas.geocoding.createSession() returns a Session. GeocodeSearchController owns one internally and exposes it only through StateFlow<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.

See Also ​