What it does
- Forward geocoding. An address in, a WGS-84 coordinate out.
- Reverse geocoding. A coordinate in, a structured address out.
- Bounded batches of either, up to 100 items in one round trip — the common case when a set of stops all need coordinates at once.
- A quality verdict on every answer, so you can tell a confirmed front door from an approximation that happens to be in the right suburb.
- A shared cache, so an address your account has already resolved costs nothing to resolve again.
Unlike most of the platform, every uncached lookup is a paid call to an external vendor. That is precisely why geocoding is a module you switch on rather than something every account silently consumes. Cache hits are free; it is the misses that bill.
How it works
Branch on quality, never on confidence alone
This is the single most important thing on this page. Every result carries both a confidence number and a quality verdict. Confidence describes how tightly the returned point reflects whatever was matched — it is not a correctness score, and it is not safe to threshold on. A measured street-level result, one that never resolved the house number at all, scored 0.9. No confidence cutoff separates that from a correct answer.
The quality field is the service’s own verdict, combining confidence with what kind of thing was actually matched:
| Quality | What it means | What to do |
|---|---|---|
| accepted | Premise-level match, high confidence. | Use it. |
| uncertain | Premise-level, but middling confidence or a suspiciously wide bounding box. | Usable; flag for review. |
| rejected | Street- or area-level, or no usable match. The coordinate may be hundreds of metres out. | Do not route a driver to it. |
| ambiguous | The address matched several equally precise places far apart. | Do not route to it; re-ask with a locality or postcode. |
On an ambiguous result the service deliberately refuses to pick a winner. “100 Queen Street” with no city matches Melbourne, Brisbane and Sydney, all at maximum confidence — choosing one at random would be guessing and calling it an answer. Instead you get up to four alternatives so you can show a chooser or re-query with the locality that was meant.
Structured fields beat a single string
You can pass a freeform address, but supplying addressLine1, locality, region and postcode separately is better: it stops the vendor’s parser guessing where the locality ends and the region begins. If you already hold the fields separately, do not concatenate them just to send one string.
Supplying a two-letter countryCode narrows the search space and materially improves accuracy. Omit it when the country is genuinely unknown — a single-line address from an uploaded file, or a job spanning several countries — and expect more results to come back rejected, because the search then runs globally. Note that it must be exactly two letters: AUS and Australia are both rejected as malformed.
A location bias is a hint, not a filter
When two addresses share a street name and number and you have no postcode to tell them apart, a rough known position — a depot, the last stop, the vehicle — picks the right one. Two cautions. The bias is rounded to roughly a kilometre before it reaches the vendor, so sub-kilometre precision is neither preserved nor useful. More importantly, a bias weakens ambiguity detection: the far-apart rivals that would have produced an ambiguous verdict may never be returned at all. Supplying a bias means trusting your hint over this service’s refusal to guess.
Fuzzy matching is capped on purpose
Opting in to allowFuzzy accepts a match the vendor found only by loosening the query — a relaxed spelling, a dropped token. Such a match is capped at uncertain and can never be accepted, no matter how well it scores. The reason is measured, not theoretical: against the live vendor, a correct relaxed match scored 0.943 and a match 100 km from the address asked for scored 0.824. No threshold separates those. Turn it on when you want volume out of messy data and will review the output; leave it off when a wrong coordinate is worse than no coordinate.
Batches fail per item, and that is normal
A batch request returns 200 even when some items failed. Each item carries its own result or its own error, keyed by its position in the request, because the answers already obtained were paid for and throwing them away to signal one failure would be wasteful. Check every item’s error and quality individually — a 200 does not mean every item resolved.
Batches are bounded, not queued. There is no submit-then-poll contract here: a request over the item limit is rejected rather than accepted and worked through later. For tens of thousands of addresses, page against the endpoint. Within one batch, duplicate addresses collapse to a single vendor call.
One abstraction, so the vendor can change
Callers never talk to a geocoding vendor directly. That indirection buys three things: the vendor can be replaced, or split by country, without any caller changing; a shared read-through cache means a repeat address costs nothing; and the vendor’s account-wide rate limit is absorbed here instead of surfacing to everyone.
That last point has a visible consequence. When the shared provider budget is exhausted, you get a 503, never a 429 — the limit is account-wide and is not the individual caller’s fault. Retry after a short backoff.
A result’s provider field tells you where the answer came from; cache means no vendor call was made and nothing was billed. In steady state most answers are cache hits, so do not read the vendor distribution in your results as traffic share.
One setting
Try another provider for ambiguous addresses (escalateAmbiguous, off by default). When an address matches several places, this asks the next provider rather than stopping and reporting it as ambiguous. Your answer is never worse — if nobody does better you still get the ambiguous result and its alternatives — but it costs an extra lookup each time it fires. Leave it off unless your addresses often match businesses named after the text you searched for.
Results derive from OpenStreetMap and are ODbL-licensed. Attribution is obligatory on any surface that displays them.
Permissions
| Permission | What it allows | Needed |
|---|---|---|
| geocoding.execute | Perform forward, reverse and batch lookups. This is the only permission the module defines — there is nothing to read back and nothing to write, because a geocode is a question rather than a stored resource. | Required |
| settings.write | Change the module’s escalateAmbiguous setting for the account. | Required to configure |
| stops.write | Write a resolved coordinate back onto a stop. | Recommended |
A credential that is valid but lacks geocoding.execute gets a 403, not a 401. If lookups start failing after a credential change, check the permission before suspecting the token itself.
API reference
One contract, covering forward and reverse lookups, individually and in batches.
| Service | What it covers | Reference | Contract |
|---|---|---|---|
| geocoding-api | Forward, reverse and bounded batch geocoding. | OpenAPI description | openapi.json |
Each openapi.json is the generated OpenAPI 3.1 contract, served by the service itself — it is never hand-edited, so it cannot drift from the running API. The OpenAPI description link opens the same contract as a browsable reference. Both resolve to the environment these docs are served from, so a page read on the test site links to the test contract.
Events
This module raises no events.
Geocoding is a request-and-response surface: you ask a question and get an answer in the same call. There is nothing asynchronous to subscribe to, and no webhook to register.
Where geocoding shows up indirectly is on the resources that store a resolved coordinate — a stop whose position is filled in raises the ordinary stop.updated event, not a geocoding-specific one.
The modules that do put events on the stream are listed with their event types in the event catalog; the envelope they arrive in and the delivery guarantees behind them are in Events & webhooks.