PostFinder 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.

Getting a key

Free, no card, and the free tier does not expire. Create one, then send it as a bearer token:

curl -sS "https://api.postfinder.io/v1/addresses?q=145+sydney+road" \
  -H "Authorization: Bearer pf_live_..."

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

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, so `2/32 Marine Parade` finds the same address as `32 Marine Parade`. A trailing postcode narrows.

Each result carries its `gnaf_pid`. Store that, not the text: the text is however your user typed it that day, the pid is the address.

q
string, required — e.g. 145 sydney road
limit
integer — defaults to 10

Response

Example response, 25 lines
{
  "data": [
    {
      "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": "tas",
      "locality": "swansea"
    }
  ]
}

Answers

  • 200 Matching addresses, best first.
  • 400 `q` is missing.
  • 401 No key, or a key we do not recognise. Send it as `Authorization: Bearer pf_live_...`.
  • 402 The quota for this billing period is spent. `X-Quota-Reset` says when it returns; the billing portal is how to raise it sooner.
  • 429 Too 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/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.

q
string, required — e.g. 1 george st sydenham nsw 2044

Response

Example response, 26 lines
{
  "data": {
    "matched": true,
    "address": {
      "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": "tas",
      "locality": "swansea"
    }
  }
}

Answers

  • 200 Whether 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.
  • 401 No key, or a key we do not recognise. Send it as `Authorization: Bearer pf_live_...`.
  • 402 The quota for this billing period is spent. `X-Quota-Reset` says when it returns; the billing portal is how to raise it sooner.
  • 429 Too 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/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.

q
string, required — e.g. 1 gorge rd sydenhum nsw
limit
integer — defaults to 10

Response

Example response, 25 lines
{
  "data": [
    {
      "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": "tas",
      "locality": "swansea"
    }
  ]
}

Answers

  • 200 Addresses 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.
  • 401 No key, or a key we do not recognise. Send it as `Authorization: Bearer pf_live_...`.
  • 402 The quota for this billing period is spent. `X-Quota-Reset` says when it returns; the billing portal is how to raise it sooner.
  • 429 Too 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/{pid}Costs 1 per request

Retrieve one address by its G-NAF 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.

pid
string, required — e.g. GAVIC411711441

Response

Example response, 23 lines
{
  "data": {
    "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": "tas",
    "locality": "swansea"
  }
}

Answers

  • 200 The address.
  • 400 That is not the shape of a G-NAF address id.
  • 401 No key, or a key we do not recognise. Send it as `Authorization: Bearer pf_live_...`.
  • 402 The quota for this billing period is spent. `X-Quota-Reset` says when it returns; the billing portal is how to raise it sooner.
  • 404 No address with that id.
  • 429 Too 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.

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.

Answers

  • 200 Your keys.
  • 401 No key, or not a valid one. Revoked and unknown keys answer the same way.
  • 402 The quota for this billing period is spent. `X-Quota-Reset` says when it returns; the billing portal is how to raise it sooner.
  • 403 Signed in, but the email address is not confirmed.
  • 429 Too 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/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

name
string required · up to 60 characters · e.g. Checkout autocomplete
kind
string · one of secret, public · defaults to secret
allowed_origins
array of string · e.g. https://example.com

Answers

  • 201 Created. Copy the key now.
  • 400 A public key was requested with no allowed origins, or an origin is not an origin.
  • 401 No key, or not a valid one. Revoked and unknown keys answer the same way.
  • 402 The quota for this billing period is spent. `X-Quota-Reset` says when it returns; the billing portal is how to raise it sooner.
  • 403 Signed in, but the email address is not confirmed.
  • 429 Too 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}Costs not metered

Revoke a key

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

id
integer, required

Answers

  • 204 Revoked.
  • 401 No key, or not a valid one. Revoked and unknown keys answer the same way.
  • 402 The quota for this billing period is spent. `X-Quota-Reset` says when it returns; the billing portal is how to raise it sooner.
  • 404 No such key.
  • 429 Too 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/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.

Answers

  • 200 Usage against the plan.
  • 401 No key, or not a valid one. Revoked and unknown keys answer the same way.
  • 402 The quota for this billing period is spent. `X-Quota-Reset` says when it returns; the billing portal is how to raise it sooner.
  • 429 Too 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/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.

Answers

  • 200 Every plan, cheapest first.

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

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