Locio API

Version 1.0.0

Address and locality search across Australia, and the post offices, parcel lockers and posting boxes to send things from.

Address data comes from G-NAF (CC BY 4.0, Geoscape Australia), localities from GeoNames (CC BY 4.0) and places from OpenStreetMap (ODbL) and operator feeds. Attribution travels with the data: whatever you build shows those credits where the data appears.

Every response is JSON. Errors are RFC 7807 problem documents.

Quick start

Free, no card, and the free tier does not expire. Create a key, then send it as a bearer token on every request. The base URL is https://api.locio.com.au.

Free for the first 10,000 units a month, no card. What it costs.

From an agent? The same four calls are tools on an MCP server, with the same key. Connect a client.

Your first request
curl -sS "https://api.locio.com.au/v1/addresses?q=145%20sydney%20road&country=AU" \
  -H "Authorization: Bearer lc_live_..."

Endpoints

Authorise

Paste a key to run the examples below against it. It stays in this browser tab and is never sent anywhere except to this API.

No key here? Run uses your own account instead. Create a key.

G-NAF Addresses

Australian addresses from G-NAF, the Geocoded National Address File: the national address register, the same source Australia Post and the ABS work from. Resolve one to its G-NAF id, coordinates, ABS mesh block and structured fields. This is the product; everything below it is either a convenience over it or the plumbing around it.

get/v1/addressesCosts 1 per request

Suggest addresses as someone types

G-NAF only. Unlike `/v1/typeahead`, which also returns suburbs and places, every result here is a resolved address, so nothing has to be filtered out.

Matching is a prefix of the street line, so type it as it is written: number first, then the street. A unit in front is understood and resolves to the unit's own record, not the building's: `3/90 Bay Road` returns the pid of unit 3, and `90 Bay Road` returns the pid of the parcel. `unit 3`, `u3`, `apt 3` and `3 90` are read the same way. A trailing postcode narrows.

Each result carries its `id`. Store that, not the text: the text is however your user typed it that day, the id is the address. An Australian result carries the same value under `address_detail_pid`, which is G-NAF's own column name.

Parameters

NameTypeDescription
qstringrequired

For example 145 sydney road

limitinteger

Defaults to 10

countrystring

Which country's addresses to search, as a two letter ISO 3166-1 code. Defaults to `AU`.

Only a secret key may send it. A public key is scoped to the country the request came from, which Cloudflare resolves from the browser's address, and this parameter is ignored on one: a key that sits in a page cannot choose what it may see.

A country no address data is loaded for answers 200 with an empty `data`, a `country_code` and a `note` saying so. That is not an error: it is the right answer for somebody typing from a country you do not hold.

Defaults to AU. For example AU

The answer application/json

NameTypeDescription
dataarray
country_codestring

The country these results were searched in. `AU` today. Distinct from an address's own `country`, which is the country's name.

notestring

Why the answer is empty when empty is correct: no address data is loaded for this country, or the country could not be determined. Absent on an ordinary answer.

StatusMeaning
200Matching addresses, best first.
400`q` is missing.
401No key, or a key we do not recognise. Send it as `Authorization: Bearer pf_live_...`.
402The quota for this billing period is spent. `X-Quota-Reset` says when it returns; the billing portal is how to raise it sooner.
429Too many requests a second for this plan. `RateLimit-Limit` says the rate and `Retry-After` says how long to wait; this is a rate, not a quota, so it clears in a second.

Try it

Runs against your own key. Costs 1 per request.

GET /v1/addresses
curl -sS "https://api.locio.com.au/v1/addresses?q=145%20sydney%20road&country=AU" \
  -H "Authorization: Bearer lc_live_..."
Response
Example response, 28 lines
{
  "data": [
    {
      "id": "GATAS717990791",
      "address_detail_pid": "GATAS717990791",
      "gnaf_pid": "GATAS717990791",
      "formatted": "Piermont Resort, Unit 9, 12990 Tasman Highway, Swansea TAS 7190",
      "components": {
        "building_name": "Piermont Resort",
        "flat_type": "Unit",
        "flat_number": "9",
        "number_first": "12990",
        "street_name": "Tasman",
        "street_type": "Highway",
        "locality_name": "Swansea",
        "state": "TAS",
        "postcode": "7190"
      },
      "lat": -42.1557993,
      "lng": 148.07629134,
      "mesh_block": "60049060000",
      "country": "Australia",
      "region": "Tasmania",
      "locality": "Swansea"
    }
  ],
  "country_code": "AU"
}
get/v1/addresses/resolveCosts 1 per request

Resolve a whole address string to one record

For an address you are holding rather than one being typed: a delivery address off a checkout form, a row in a spreadsheet.

Give the whole thing, however it is written. Abbreviations, missing commas and a missing state are all fine; where the street ends and the suburb begins is worked out by trying the readings against G-NAF.

This answers validation, geocoding and parsing in one call, because they are one question: `matched` says whether the address is real, and `address` carries the coordinates, the components and the pid. It is one unit, not three.

Parameters

NameTypeDescription
qstringrequired

For example 1 george st sydenham nsw 2044

countrystring

Which country's addresses to search, as a two letter ISO 3166-1 code. Defaults to `AU`.

Only a secret key may send it. A public key is scoped to the country the request came from, which Cloudflare resolves from the browser's address, and this parameter is ignored on one: a key that sits in a page cannot choose what it may see.

A country no address data is loaded for answers 200 with an empty `data`, a `country_code` and a `note` saying so. That is not an error: it is the right answer for somebody typing from a country you do not hold.

Defaults to AU. For example AU

The answer application/json

NameTypeDescription
dataobject
country_codestring

The country these results were searched in. `AU` today. Distinct from an address's own `country`, which is the country's name.

notestring

Why the answer is empty when empty is correct: no address data is loaded for this country, or the country could not be determined. Absent on an ordinary answer.

StatusMeaning
200Whether it resolved, and what it resolved to. An address that is not in G-NAF is a 200 with matched false, not an error: that is the answer you asked for.
400`q` is missing.
401No key, or a key we do not recognise. Send it as `Authorization: Bearer pf_live_...`.
402The quota for this billing period is spent. `X-Quota-Reset` says when it returns; the billing portal is how to raise it sooner.
429Too many requests a second for this plan. `RateLimit-Limit` says the rate and `Retry-After` says how long to wait; this is a rate, not a quota, so it clears in a second.

Try it

Runs against your own key. Costs 1 per request.

GET /v1/addresses/resolve
curl -sS "https://api.locio.com.au/v1/addresses/resolve?q=1%20george%20st%20sydenham%20nsw%202044&country=AU" \
  -H "Authorization: Bearer lc_live_..."
Response
Example response, 29 lines
{
  "data": {
    "matched": true,
    "address": {
      "id": "GATAS717990791",
      "address_detail_pid": "GATAS717990791",
      "gnaf_pid": "GATAS717990791",
      "formatted": "Piermont Resort, Unit 9, 12990 Tasman Highway, Swansea TAS 7190",
      "components": {
        "building_name": "Piermont Resort",
        "flat_type": "Unit",
        "flat_number": "9",
        "number_first": "12990",
        "street_name": "Tasman",
        "street_type": "Highway",
        "locality_name": "Swansea",
        "state": "TAS",
        "postcode": "7190"
      },
      "lat": -42.1557993,
      "lng": 148.07629134,
      "mesh_block": "60049060000",
      "country": "Australia",
      "region": "Tasmania",
      "locality": "Swansea"
    }
  },
  "country_code": "AU"
}
get/v1/addresses/similarCosts 3 per request

Find addresses close to one that is misspelled

For when `/v1/addresses/resolve` found nothing. An address typed by a person is wrong often enough that "no match" is not a useful final answer: `1 gorge rd sydenhum` is one address, and saying which is the point.

The suburb is corrected first, then street lines within it are scored by similarity. Include the suburb if you have it — it is what keeps this fast, and it is what makes the correction good.

**This is the expensive endpoint.** Every other address call is a prefix seek; this is a similarity scan, and it costs three units accordingly. Call it once on an address that failed to resolve, never on a keystroke — use `/v1/addresses` for that.

Parameters

NameTypeDescription
qstringrequired

For example 1 gorge rd sydenhum nsw

limitinteger

Defaults to 10

countrystring

Which country's addresses to search, as a two letter ISO 3166-1 code. Defaults to `AU`.

Only a secret key may send it. A public key is scoped to the country the request came from, which Cloudflare resolves from the browser's address, and this parameter is ignored on one: a key that sits in a page cannot choose what it may see.

A country no address data is loaded for answers 200 with an empty `data`, a `country_code` and a `note` saying so. That is not an error: it is the right answer for somebody typing from a country you do not hold.

Defaults to AU. For example AU

The answer application/json

NameTypeDescription
dataarray
country_codestring

The country these results were searched in. `AU` today. Distinct from an address's own `country`, which is the country's name.

notestring

Why the answer is empty when empty is correct: no address data is loaded for this country, or the country could not be determined. Absent on an ordinary answer.

StatusMeaning
200Addresses close to the term, best first. Empty when nothing was close enough.
400`q` is missing, or shorter than four characters, which similarity cannot say anything useful about.
401No key, or a key we do not recognise. Send it as `Authorization: Bearer pf_live_...`.
402The quota for this billing period is spent. `X-Quota-Reset` says when it returns; the billing portal is how to raise it sooner.
429Too many requests a second for this plan. `RateLimit-Limit` says the rate and `Retry-After` says how long to wait; this is a rate, not a quota, so it clears in a second.

Try it

Runs against your own key. Costs 3 per request.

GET /v1/addresses/similar
curl -sS "https://api.locio.com.au/v1/addresses/similar?q=1%20gorge%20rd%20sydenhum%20nsw&country=AU" \
  -H "Authorization: Bearer lc_live_..."
Response
Example response, 28 lines
{
  "data": [
    {
      "id": "GATAS717990791",
      "address_detail_pid": "GATAS717990791",
      "gnaf_pid": "GATAS717990791",
      "formatted": "Piermont Resort, Unit 9, 12990 Tasman Highway, Swansea TAS 7190",
      "components": {
        "building_name": "Piermont Resort",
        "flat_type": "Unit",
        "flat_number": "9",
        "number_first": "12990",
        "street_name": "Tasman",
        "street_type": "Highway",
        "locality_name": "Swansea",
        "state": "TAS",
        "postcode": "7190"
      },
      "lat": -42.1557993,
      "lng": 148.07629134,
      "mesh_block": "60049060000",
      "country": "Australia",
      "region": "Tasmania",
      "locality": "Swansea"
    }
  ],
  "country_code": "AU"
}
get/v1/addresses/{id}Costs 1 per request

Retrieve one address by its id

The pid a search or a resolve returned. This is the endpoint that makes storing a pid worthwhile: the address can be read back a year later without knowing how it was originally typed.

A 404 means G-NAF retired the id between releases, which does happen. Search for the address again to get its current one.

Parameters

NameTypeDescription
idstringrequired

The id from a result you stored. In Australia that is G-NAF's ADDRESS_DETAIL_PID, which a result also carries under `address_detail_pid`.

In the path. For example GAVIC411711441

countrystring

Which country's addresses to search, as a two letter ISO 3166-1 code. Defaults to `AU`.

Only a secret key may send it. A public key is scoped to the country the request came from, which Cloudflare resolves from the browser's address, and this parameter is ignored on one: a key that sits in a page cannot choose what it may see.

A country no address data is loaded for answers 200 with an empty `data`, a `country_code` and a `note` saying so. That is not an error: it is the right answer for somebody typing from a country you do not hold.

Defaults to AU. For example AU

The answer application/json

NameTypeDescription
data
country_codestring

The country these results were searched in. `AU` today. Distinct from an address's own `country`, which is the country's name.

notestring

Why the answer is empty when empty is correct: no address data is loaded for this country, or the country could not be determined. Absent on an ordinary answer.

StatusMeaning
200The address.
400That is not the shape of a G-NAF address id.
401No key, or a key we do not recognise. Send it as `Authorization: Bearer pf_live_...`.
402The quota for this billing period is spent. `X-Quota-Reset` says when it returns; the billing portal is how to raise it sooner.
404No address with that id. Also when the address is outside the country this key may search: an id either resolves for you or it does not, and which ids exist elsewhere is not something a key can probe for.
429Too many requests a second for this plan. `RateLimit-Limit` says the rate and `Retry-After` says how long to wait; this is a rate, not a quota, so it clears in a second.

Try it

Runs against your own key. Costs 1 per request.

GET /v1/addresses/{id}
curl -sS "https://api.locio.com.au/v1/addresses/GAVIC411711441?country=AU" \
  -H "Authorization: Bearer lc_live_..."
Response
Example response, 26 lines
{
  "data": {
    "id": "GATAS717990791",
    "address_detail_pid": "GATAS717990791",
    "gnaf_pid": "GATAS717990791",
    "formatted": "Piermont Resort, Unit 9, 12990 Tasman Highway, Swansea TAS 7190",
    "components": {
      "building_name": "Piermont Resort",
      "flat_type": "Unit",
      "flat_number": "9",
      "number_first": "12990",
      "street_name": "Tasman",
      "street_type": "Highway",
      "locality_name": "Swansea",
      "state": "TAS",
      "postcode": "7190"
    },
    "lat": -42.1557993,
    "lng": 148.07629134,
    "mesh_block": "60049060000",
    "country": "Australia",
    "region": "Tasmania",
    "locality": "Swansea"
  },
  "country_code": "AU"
}

Account

Keys, usage and plans. Session authenticated, not key authenticated.

get/v1/keysCosts not metered

List your keys

Hints only. The key itself exists in the response that created it and nowhere else.

The answer application/json

NameTypeDescription
dataarray
StatusMeaning
200Your keys.
401No key, or not a valid one. Revoked and unknown keys answer the same way.
402The quota for this billing period is spent. `X-Quota-Reset` says when it returns; the billing portal is how to raise it sooner.
403Signed in, but the email address is not confirmed.
429Too many requests a second for this plan. `RateLimit-Limit` says the rate and `Retry-After` says how long to wait; this is a rate, not a quota, so it clears in a second.
GET /v1/keys
curl -sS "https://api.locio.com.au/v1/keys" \
  -H "Cookie: locio_session=..."
post/v1/keysCosts not metered

Create a key

The response is the only time the key is shown: only a hash is stored, so it cannot be retrieved again.

A public key is safe in a browser and must name the sites it may be used from.

Body application/json

NameTypeDescription
namestringrequired

Up to 60 characters. For example Checkout autocomplete

kindstring

One of secret, public. Defaults to secret

allowed_originsarray of string

For example https://example.com

StatusMeaning
201Created. Copy the key now.
400A public key was requested with no allowed origins, or an origin is not an origin.
401No key, or not a valid one. Revoked and unknown keys answer the same way.
402The quota for this billing period is spent. `X-Quota-Reset` says when it returns; the billing portal is how to raise it sooner.
403Signed in, but the email address is not confirmed.
429Too many requests a second for this plan. `RateLimit-Limit` says the rate and `Retry-After` says how long to wait; this is a rate, not a quota, so it clears in a second.
POST /v1/keys
curl -sS -X POST "https://api.locio.com.au/v1/keys" \
  -H "Cookie: locio_session=..." \
  -H "Content-Type: application/json" \
  -d '{"name":"Checkout autocomplete","kind":"secret","allowed_origins":["https://example.com"]}'
delete/v1/keys/{id}Costs not metered

Revoke a key

Immediate. A key belonging to another account answers 404, the same as one that never existed.

Parameters

NameTypeDescription
idintegerrequired

In the path

StatusMeaning
204Revoked.
401No key, or not a valid one. Revoked and unknown keys answer the same way.
402The quota for this billing period is spent. `X-Quota-Reset` says when it returns; the billing portal is how to raise it sooner.
404No such key.
429Too many requests a second for this plan. `RateLimit-Limit` says the rate and `Retry-After` says how long to wait; this is a rate, not a quota, so it clears in a second.
DELETE /v1/keys/{id}
curl -sS -X DELETE "https://api.locio.com.au/v1/keys/<id>" \
  -H "Cookie: locio_session=..."
get/v1/me/usageCosts not metered

What this account has used this period

Nobody should learn their usage from an invoice, so the reset date is part of the answer.

The answer application/json

NameTypeDescription
data
StatusMeaning
200Usage against the plan.
401No key, or not a valid one. Revoked and unknown keys answer the same way.
402The quota for this billing period is spent. `X-Quota-Reset` says when it returns; the billing portal is how to raise it sooner.
429Too many requests a second for this plan. `RateLimit-Limit` says the rate and `Retry-After` says how long to wait; this is a rate, not a quota, so it clears in a second.
GET /v1/me/usage
curl -sS "https://api.locio.com.au/v1/me/usage" \
  -H "Cookie: locio_session=..."
get/v1/plansCosts not metered

The pricing ladder

What each plan includes: units a month, requests a second, overage rate and export cadence. Public, and the same numbers the meter enforces.

The answer application/json

NameTypeDescription
dataarray
StatusMeaning
200Every plan, cheapest first.
GET /v1/plans
curl -sS "https://api.locio.com.au/v1/plans" \
  -H "Authorization: Bearer lc_live_..."

What it costs

A unit is one typeahead or one address. GeoJSON is one unit per hundred features. Refused requests are not charged.

PlanPriceUnits a monthPer secondOver the limit
freeFree10,00010Stops
starter$19100,00025$3.00 per 10,000
growth$991,000,00050$1.50 per 10,000
scale$2495,000,000167$1.00 per 10,000

The machine readable version is at https://api.locio.com.au/v1/openapi.json. Generate a client from it rather than writing one by hand. Data licences and attribution.