API reference

Overview

Base URL /v1. All requests and responses are JSON. Send a UPRN or a UK postcode; get back coordinates and a precision tier. 1,000 successful lookups are free per account, then a one-time £20 unlocks unlimited use. Unmatched lookups never count against your allowance.

Authentication

HEADER X-API-Key: <your-key>

Get a key from the dashboard or via POST /v1/signup. The demo endpoints below work without a key.

Precision & coverage

Every response carries a precision field:

TierMeaning
propertyExact building coordinate, via a UPRN or an address match against the register. matched_via says which.
postcodePostcode-centroid fallback. Typically 50 m – several hundred metres from the building.
unmatchedNothing resolved. Free — not counted against your allowance.

Property-level coverage: England & Wales. Postcode centroids: England, Wales, Scotland. Northern Ireland (BT) postcodes return unmatched for data-licensing reasons.

Single geocode

GET /v1/geocode?uprn={uprn}
GET /v1/geocode?postcode={postcode}
ParamNotes
uprnPositive integer, up to 12 digits. Tried first.
postcodeUK postcode, any casing or spacing.
addressOptional address text. Fuzzy-matched against the register within the postcode; a confident match returns building-level coordinates with matched_via: "address" and a confidence score.
curl -H "X-API-Key: $KEY" \
  "BASE/v1/geocode?uprn=100012"

{
  "query": { "uprn": 100012 },
  "matched": true,
  "precision": "property",
  "lat": 51.4566671,
  "lon": -2.5591032,
  "uprn": 100012
}

Batch geocode

POST /v1/geocode/batch

Up to 500 queries per call, answered in order. The response includes a per-tier summary. This is what the upload tool uses under the hood.

curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
  -d '{ "queries": [ {"uprn": 100012}, {"postcode": "SW1A 1AA"} ] }' \
  "BASE/v1/geocode/batch"

{
  "results": [
    { "query": {"uprn": 100012}, "matched": true, "precision": "property",
      "lat": 51.4566671, "lon": -2.5591032, "uprn": 100012 },
    { "query": {"postcode": "SW1A 1AA"}, "matched": true, "precision": "postcode",
      "lat": 51.5010, "lon": -0.1416 }
  ],
  "summary": { "property": 1, "postcode": 1, "unmatched": 0 }
}

Demo endpoints

GET /v1/demo?postcode={postcode}
POST /v1/demo/batch

No key required — these power the site's try-it box and the tool's 25-row preview. Same response shapes as above. Allowance: 300 lookups per IP per day; the batch form accepts up to 25 queries per call and returns demo_remaining.

Signup

POST /v1/signup
curl -X POST -H "Content-Type: application/json" \
  -d '{ "email": "you@company.co.uk" }' "BASE/v1/signup"

{ "api_key": "…", "usage_count": 0, "free_limit": 1000, "unlocked": false }

One key per email. The key is shown once in the response and also emailed to you.

POST /v1/recover-key

Forgotten keys: send { "email": "..." } and the key is re-emailed to that address (the response never reveals whether an account exists).

Usage

GET /v1/usage
curl -H "X-API-Key: $KEY" "BASE/v1/usage"

{
  "email": "you@company.co.uk",
  "usage_count": 342,
  "free_limit": 1000,
  "unlocked": false,
  "breakdown": { "property": 291, "postcode": 44, "unmatched": 7 }
}

Checkout

POST /v1/checkout

Returns a Stripe Checkout URL for the one-time £20 unlock. On completion your key becomes unlimited — nothing else changes.

curl -X POST -H "X-API-Key: $KEY" "BASE/v1/checkout"

{ "checkout_url": "https://checkout.stripe.com/c/pay/…" }

Errors & limits

StatusMeaning
400Malformed request — missing or invalid parameters.
401invalid_api_key
402free_tier_exhausted — body includes checkout_url. Unlock for £20 once.
429Rate limited — 600 requests/minute per key, or the daily demo allowance.
{
  "error": "free_tier_exhausted",
  "usage_count": 1000,
  "free_limit": 1000,
  "checkout_url": "BASE/dashboard"
}

Rate limits protect the infrastructure, not revenue: 600 requests/minute per key, 3 signups per IP per day.