Documentation

Australian address API documentation

WattleAddr turns a partly typed Australian address into a correct, structured one: street, suburb, state, postcode and coordinates. Base URL https://api.wattleaddr.com.au/v1. JSON only. Australian addresses only.

Not a developer? This page is for developers. If that is not you, here is the short version: WattleAddr adds an address box to a website or app that suggests real Australian addresses as someone types, and gives your system the address in clean, separate fields. On Shopify, install the app instead: WattleAddr for Shopify. Otherwise, hand your developer this page. The Free plan includes 5,000 lookups (completed address searches) a month with no card; paid plans are on the pricing page, GST included.

Before you start

You need three things.

  1. An account. Sign up with your name, work email and a password, then press Create account. You start on the Free plan: 5,000 lookups a month, no card.
  2. An API key. In the console open API Keys and press Create my first key. That makes a secret key in test mode (waddr_sk_test_…). Test mode uses the real address data, costs nothing and never counts against your 5,000 monthly lookups, for the first 15 days of your account. The console shows the key once, under Copy your key now. Copy it somewhere safe.
  3. A terminal with curl, or any HTTP client. Every example below is a plain HTTPS request.

Want to choose the key yourself? Press Choose the options myself. Pick Secret (server) for code that runs on your server, or Publishable (browser) for code that runs in a web page. Pick Live or Test. A live browser key must list the domains it may run on. Never put a secret key in a web page or a public repository; use a publishable key there.

Your first request in 5 minutes

Replace YOUR_KEY with the key you just copied.

1. Ask for suggestions as someone types

Pick any unique string as the session and reuse it for every request about this one address. Autocomplete is never charged. Suggestions start from three characters.

curl -s -H "Authorization: Bearer YOUR_KEY" \
  "https://api.wattleaddr.com.au/v1/addresses/autocomplete?q=1+martin+pl&session=demo-1"
{
  "session": "demo-1",
  "query": "1 martin pl",
  "suggestions": [
    { "id": "GANSW706124693", "formatted": "1 Martin Place, Sydney NSW 2000", "score": 42.66 }
  ]
}

The -H line sends your key in a header named Authorization; that is how a secret key is always sent. In the response, id is the address’s identifier in G-NAF, the national address dataset (see Words we use). formatted is the text to show in the dropdown. score only ranks suggestions within this one response; you can ignore it. Show the list, let the person pick one.

2. Retrieve the one they picked

Same session. This is the charged call.

curl -s -H "Authorization: Bearer YOUR_KEY" \
  "https://api.wattleaddr.com.au/v1/addresses/GANSW706124693?session=demo-1"
{
  "id": "GANSW706124693",
  "formatted": "1 Martin Place, Sydney NSW 2000",
  "components": {
    "flat_number": null, "level_number": null,
    "street_number": "1", "street_name": "Martin", "street_type": "Place",
    "locality": "Sydney", "state": "NSW", "postcode": "2000"
  },
  "geo": { "lat": -33.8678, "lng": 151.2073 },
  "confidence": "high",
  "source": "gnaf", "gnaf_release": "2026-08",
  "billed": false, "test": true
}
FieldWhat it is
componentsThe address in parts. All strings, any may be null. locality is the suburb or town. Keep postcode as a string: Darwin is 0800.
geoLatitude and longitude, or null if the record has no coordinates.
confidenceG-NAF’s own confidence in this record. Not a match score.
gnaf_releaseThe quarterly dataset that answered. Store it with the address.
billedWhether this call used one lookup from your plan. false here because the key is a test key.
testPresent, and true, only on a test key. Nothing is ever charged on one.

3. What you were charged

Nothing yet, because this was a test key: that is what "billed": false and "test": true are telling you. On a live key the same two calls use exactly one lookup, for step 2, and billed comes back true. Every keystroke in step 1 is free because it shared the session. Leave the session out and every retrieve is charged on its own.

Every successful response on a plan with a quota also carries X-WattleAddr-Quota-Limit and X-WattleAddr-Quota-Remaining headers, so on a live key you can watch your month’s allowance drop by one.

4. Save the address properly

Store id, formatted and components together. Identifiers can change between G-NAF releases, so never keep the id on its own. There is a schema you can copy in how to store an Australian address, and the address format checker shows how a messy address splits into these fields.

Before you go live: create a Live key. Test keys stop working after the test period with 402 test_mode_expired. Live keys work on every plan, including Free.

Prefer to explore first? Try every endpoint live, with no key, in the interactive reference, or take the OpenAPI 3.1 spec or Postman collection into your own tools.

Add it to your site

Three ways, all using a publishable key (waddr_pk_…) locked to your domains in the console. Create one under API Keys, Choose the options myself, Publishable (browser); test mode is fine while you build. Each of the three handles the session for you, so all the keystrokes behind one address count as a single lookup.

The browser widget

One script tag, no build step, no dependencies.

<input id="address" />
<script src="https://api.wattleaddr.com.au/v1/widget.js"></script>
<script>
  const wa = new WattleAddr('waddr_pk_live_…');
  wa.attach('#address', {
    onSelect: (a) => console.log(a.formatted, a.components, a.geo)
  });
</script>
OptionDefaultWhat it does
onSelectrequiredCalled with the full record once someone picks an address.
onErrorconsole warningCalled instead of logging, if you want to handle failures yourself.
themelightlight, dark, or auto to follow the visitor’s system setting.
limit6How many suggestions to show.
stateallRestrict to one state, for example NSW.

The npm packages

Official, typed, MIT-licensed packages. Use @wattleaddr/react for React, or the zero-dependency @wattleaddr/js for vanilla JavaScript or server-side Node.

# React: useAddressAutocomplete hook + <AddressAutocomplete> component
npm install @wattleaddr/react

# Vanilla JS / Node: headless client + the same drop-in widget
npm install @wattleaddr/js

The React component drops into any form:

import { AddressAutocomplete } from '@wattleaddr/react';

<AddressAutocomplete
  apiKey="waddr_pk_live_…"
  onSelect={(a) => console.log(a.formatted, a.components.postcode)}
/>

Or call it headlessly with the client, which runs in the browser and in Node 18+. On the server, set keyTransport: 'header' to send a secret key as a Bearer token instead of in the URL:

import { WattleAddrClient, createSession } from '@wattleaddr/js';

const client = new WattleAddrClient('waddr_sk_live_…', { keyTransport: 'header' });
const session = createSession();
const { suggestions } = await client.autocomplete('1 mart', { session });
const addr = await client.retrieve(suggestions[0].id, { session }); // the charged call

Worked examples: a React form, a Next.js App Router form and a checkout with the widget.

Keys and authentication

Two key types, both created in the console. Never expose a secret key in the browser.

KeyPrefixWhereSecured by
Secretwaddr_sk_live_…Server-sideAuthorization: Bearer + optional IP allowlist
Publishablewaddr_pk_live_…Browser (autocomplete and retrieve only)The website domains you list + rate limits

Either type can be made in test mode (waddr_sk_test_…, waddr_pk_test_…): real data, never charged, free for the first 15 days of an account. Responses from a test key carry "test": true.

That is how your application authenticates. How your team signs in to the console is separate: on Enterprise plans you can point it at your own identity provider over OpenID Connect, and require it. See single sign-on setup.

What you are charged

Billing is session-based, the same model as Google Places: send a session token with each autocomplete keystroke and the final retrieve, and the whole session counts as one lookup, however many keystrokes it took. Autocomplete on its own is never charged. Retrieve or verify with no session token always charges, so always send one. A verify that finds no match is not charged.

Exhausting a plan’s monthly quota returns 402 quota_exceeded; a per-key burst limit returns 429 rate_limited with a Retry-After header. Both, and every other code, are in common errors. Plan allowances and prices are on the pricing page.

Limits and performance

Every key has a requests-per-second limit set by its plan. It is a token bucket: a key can send that many requests at once, then continues at that rate. Over it, the API returns 429 rate_limited with a Retry-After header saying how many seconds to wait. Nothing is queued, and a refused request is neither counted nor charged.

PlanRequests per second, per keyLive keys per workspace
Free52
Starter1510
Growth4025
Enterprise2001,000

There is no separate concurrency limit: parallel requests are fine within the per-second rate. Each key has its own bucket, and the right setup is one key per system, each with its own limit. If one system needs more than its plan’s rate, talk to us rather than fanning out across keys; limits above the published ones are set by agreement. Test keys have a separate, smaller allowance. Monthly volume is governed separately by the plan’s quota (above).

Latency. Measured inside the API in September 2026: autocomplete about 65 ms at the median and about 225 ms at the 95th percentile; verify 35 to 100 ms once a query is warm, and up to about 600 ms on the first call for a large block of units. On top of that, a fresh HTTPS connection from within Australia adds roughly 50 to 90 ms and a reused one about 45 ms, so keep connections alive. Repeated prefixes are served from an in-memory cache. Live availability and the G-NAF release being served are on the status page.

Under the hood: the full G-NAF release, loaded into OpenSearch by the open-source Addressr loader that we host and queried directly by our API (the exact query first, a spelling-tolerant one only when that finds nothing); the same API does keys, metering, scoring and the corrections described below; Postgres for keys, usage and billing. Sydney is primary, Melbourne a warm standby, and nothing leaves Australia. Quarterly G-NAF releases are loaded in place with no downtime.

Endpoints

MethodPathPurpose
GET/v1/addresses/autocompleteType-ahead suggestions for a partial query
GET/v1/addresses/{id}Full structured record for a chosen suggestion (charged)
POST/v1/addresses/verifyMatch free-text to its official G-NAF form, with a per-field verdict (charged on a match)
GET/v1/statusService health & current G-NAF release

Every parameter and response schema is in the interactive reference.

Example: verify, and what a verdict means

There is a plain-language overview of verification, and what it is not, on the verification page.

verify takes free text you already hold and returns the best match in its official G-NAF form, plus an assessment of how well it answers what you sent. Branch on verdict.

curl "https://api.wattleaddr.com.au/v1/addresses/verify" \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"address": "23 wakool ave deer park", "session": "demo-2"}'
{
  "matched": true,
  "match": { /* the full record, same shape as retrieve */ },
  "verdict": "corrected",
  "match_score": 75,
  "match_level": "premise",
  "elements": { "street_number": "verified", …, "postcode": "missing" },
  "changed_elements": [],
  … plus alternatives, source, gnaf_release, billed and, on a test key, test
}
verdictMeaningHandling
verifiedEvery element you supplied agrees, and no other candidate fitsAccept
correctedAgrees as far as it goes; you abbreviated or left something outAccept the official form, or re-prompt for the missing elements you need (missing means not supplied, not required: a house has no unit)
ambiguousAn element was contradicted, input was discarded, a runner-up fits equally well, or you gave a building address and the building has units (the alternatives list them)Review, never auto-accept. If your data is deliberately at building level, accept on match_level: premise and check alternatives
unverifiedNothing matched, or the match scored too low to rely onReject and flag

elements gives every field its own status (verified, changed or missing), so a checkout can re-prompt for the one field that is wrong instead of the whole address. match_level says how precisely we identified it (subpremise a unit, premise a building, thoroughfare the street only, locality the suburb only) and is independent of the verdict. When you supply no unit or level, verify prefers the building over its units; supply the unit to get subpremise. We publish no accept/reject score threshold: the right line depends on what a wrong address costs you. The older top-level confidence field on a verify response is deprecated; branch on verdict. A verified address exists in G-NAF and we know where it is; that is not a promise that mail can be delivered to it. There is a worked example of verifying server-side, without paying twice, in the Next.js guide.

Typos, misspellings and units

Matching is fuzzy but not phonetic. A word of three to five letters may have one character wrong, missing, extra or swapped; a longer word may have two; a word of one or two letters must be exact. That applies to the street name and the suburb alike, with one exception: the last word typed is treated as a prefix and gets no tolerance. So 589 Beems Rd Carseldine and 589 Beams Rd Carsledine QLD both find 589 Beams Rd, but a suburb misspelt at the very end of the query matches nothing on its own. When nothing matches, the trailing words (suburb, state, postcode) are dropped one at a time and the search retried; verify reports what it discarded in dropped_tokens and scores the match lower. Suggestions appear once the query names a street or suburb; a bare unit, level or small street number on its own returns an empty list.

Verify never corrects a street number. A number that disagrees with the record is marked changed, not swapped. Autocomplete is looser: a one- or two-digit number is matched exactly, so if no premise carries it the suggestions are sub-dwellings that do (8 Beams Rd returns Unit 8 of the blocks on Beams Rd); a number of three or more digits gets the same one-character tolerance as a word, so a number that does not exist on the street can bring up its neighbours. When you type a number and no unit, the premise with that number on that street comes before anybody’s units, and a building normally comes before its own units even when the block is large. Type the unit (3/589, unit 3 589) to get the unit.

Verify tells you what it changed. elements marks each part verified, changed or missing, and changed_elements lists the corrected ones; the corrected values are in match.components. A corrected street name lowers match_score and gives an unverified or ambiguous verdict, never verified, so a misspelt street reaches you as the right record flagged for review, not as an automatic accept. A building address on a block with units matches the building with an ambiguous verdict and some of its units in alternatives.

PO Boxes & postal addresses

G-NAF is a register of physical addresses, so it contains no PO Boxes, GPO Boxes, Locked Bags or Private Bags. Rather than returning a confusing empty list, a query for one returns 200 with an empty suggestions array and a notice, so your form can prompt for a street address or accept the PO Box in a separate field. verify returns the same notice with matched: false and billed: false. A query the dataset cannot answer is never charged. If you need PO Boxes validated, you need a product licensed for Australia Post’s PAF; AMAS and PAF vs G-NAF explains the boundary.

{ "suggestions": [], "notice": {
  "code": "postal_address_unsupported",
  "kind": "PO Box",
  "message": "PO Box addresses aren’t in the G-NAF dataset…"
} }

Common errors

Every error is JSON: { "error": { "code", "message", "docs" } }. The code is stable; switch on it. The message may change. The docs link points at the matching row of the full error reference.

StatuscodeWhat happenedWhat to do
400bad_requestThe query (q) or address is under 3 characters, or over the length limit.Wait until the person has typed 3 characters before calling. Trim very long input.
401unauthorizedNo API key was sent.Add an Authorization: Bearer YOUR_KEY header (secret key), or ?key= for a publishable key in the browser.
401invalid_keyThe key is wrong, has been revoked, or has a typo.Copy it again from the console, or create a new key. Revoked keys never come back.
402quota_exceededThis month’s lookups are used up and your plan does not run over (Free, Shopify, a cancelled plan, or a paid plan with a spending cap set at your request), or a paid plan has reached the overage ceiling of five times its included lookups. The message says which.Upgrade in the console under Billing, or wait for the period to roll over. If the message says the overage ceiling was reached, contact support to lift it; a plan change only takes effect next period. Autocomplete keeps working; only charged calls are refused.
402test_mode_expiredA test key was used after the free test period (15 days from account creation).Create a Live key in the console. Live keys work on every plan, including Free.
402feature_unavailableThe endpoint is not included in the workspace’s plan.Check the plan in the console under Billing.
403forbidden_referrerA publishable key was used from a domain that is not on its allowed list.Edit the key in the console and add the domain to Allowed domains. Match the exact host the page is served from.
403forbidden_key_typeA publishable (browser) key was used to call verify. Publishable keys can only call autocomplete and retrieve.Call verify from your server with a secret key. If a person is typing the address, use autocomplete and retrieve with the publishable key instead; verify is for addresses you already hold.
403forbidden_ipA secret key was used from an IP address that is not on its allowed list.Edit the key in the console and add the address to Allowed IPs / CIDRs, or clear the list to allow any IP.
404not_foundNo address has that id.Use an id exactly as it came back from an autocomplete suggestion. Ids can change between G-NAF releases, so re-search rather than replaying an old one.
429rate_limitedToo many requests per second on one key.Wait the number of seconds in the Retry-After header, then retry. Debounce keystrokes in the browser.

Not an error: 200 with "suggestions": [] and a notice. See PO Boxes above.

Building with a coding agent

If you use Claude Code, Cursor, Copilot or similar, give it our agent skill. It covers the things an assistant otherwise gets wrong: session tokens and what they cost, which key belongs in the browser, PO Boxes being absent from G-NAF by design, reading a verify verdict, and how to store the address components. It is a single markdown file with no telemetry.

# any assistant: fetch it into your project
curl -o WATTLEADDR.md https://wattleaddr.com.au/skills/wattleaddr/SKILL.md

# Claude Code: drop it in as a skill
mkdir -p .claude/skills/wattleaddr && curl -o .claude/skills/wattleaddr/SKILL.md \
  https://wattleaddr.com.au/skills/wattleaddr/SKILL.md

It also ships inside @wattleaddr/js, at node_modules/@wattleaddr/js/skills/wattleaddr/SKILL.md, so an agent working in a project that already depends on the SDK can find it without downloading anything.

Words we use

WordMeaning
endpointOne URL the API answers on. There are four: autocomplete, retrieve, verify and status.
autocompleteThe call that returns suggestions as someone types. Never charged.
retrieveThe call that returns the full record for one suggestion. Charged once per session.
verifyThe call that matches free text you already hold to its official form. Charged on a match.
lookupThe unit you are charged in. One lookup is one address a person actually picked (retrieve) or one free-text address matched (verify). The Free plan includes 5,000 a month.
sessionAny string you choose that ties the keystrokes for one address to the final retrieve. Shared session means one lookup. No session means every retrieve is a lookup.
quotaThe lookups included in your plan each month. When they are used up, charged calls return 402 on plans that do not run over.
rate limitHow many requests per second one key may make. Over it, the API returns 429 with Retry-After.
secret keywaddr_sk_…. For your server, sent as Authorization: Bearer. Never in a web page.
publishable keywaddr_pk_…. For the browser. Safe to be public because it only works from the domains you list.
test keywaddr_sk_test_… or waddr_pk_test_…. Real data, never charged, time limited.
G-NAFThe Geocoded National Address File: the open register of every physical address in Australia, published quarterly by Geoscape. WattleAddr is built on it. It has no PO Boxes.
localityG-NAF’s word for suburb or town.
verdictVerify’s answer on what to do with a match: verified, corrected, ambiguous or unverified. Branch on this, not on confidence.
noticeA note on a successful response explaining why it is empty. Not an error.

Data & privacy

Every request is served from Australian infrastructure. No query or matched address is processed, cached or routed offshore, and your end-users’ input never touches a third-party ad platform such as Google Places.

Autocomplete queries and the addresses they match are recorded in a per-workspace search log for usage, debugging and support. In the console you choose what it keeps:

ModeWhat it stores
full (default)Query and matched-address text, in full, until retention purges it.
hashedEach query as a salted keyed hash; matched-address text is dropped. This is pseudonymisation, not anonymisation: we hold the key.
noneNo query or matched-address text at all; only counts, timing and billing.

Retention is configurable (7–365 days, by plan) and old query text is purged automatically; you can also apply a privacy mode to logs already stored, in one click. Why hashing an address is pseudonymisation explains the distinction. See the FAQ and Privacy Policy for detail.

Attribution

WattleAddr is built on the open Geocoded National Address File. The G-NAF licence requires attribution. Display this wherever you surface address data:

Incorporates or developed using G-NAF © Geoscape Australia,
licensed under the Open G-NAF End User Licence Agreement.
Modified by [your product] for search and display.

Explore every endpoint and try calls live in the interactive reference. Questions? hello@wattleaddr.com.au