API · v1

Get UK Address API

One REST endpoint. Bearer auth. JSON in, JSON out. Errors follow RFC 9457 Problem Details. If you've used a typed HTTP API before, you already know how this works.

Address lookup

GET/api/v1/autocomplete

Query parameters

NameTypeRequiredDescription
querystringYesFree-text, 3+ chars.
api_keystringYesYour API key, prefixed gua_. Generate from the dashboard.

Results are capped at 100 per request — that's the maximum number of addresses that can share a single UK postcode.

Response shape

json · 200
{
"requestId": "00000001",
"results": [
{
"organisation": "",
"addressLine1": "Buckingham Palace",
"addressLine2": "",
"town": "London",
"postcode": "SW1A 1AA",
"summaryLine": "Buckingham Palace, London, SW1A 1AA"
}
]
}

Authentication

Pass your API key as a Bearer token in the Authorization query parameter. Keys are environment-scoped — create separate keys for dev, staging and prod from your dashboard.

shell
curl "https://getukaddress.com/api/v1/autocomplete?query=SW1A+1AA&api_key=gua_your_key"

Hiding the API key

Never embed your API key in browser-side JavaScript. Anything that ships to the browser — minified bundles, environment variables prefixed VITE_ / NEXT_PUBLIC_ / REACT_APP_, query strings in fetch calls — is visible to anyone who opens DevTools. A leaked key is someone else's quota; once it's published you have to revoke and reissue.

The right pattern is a thin proxy on your own server. Your frontend calls your backend, your backend appends the API key and calls Get UK Address. The key never leaves your server.

❌ Don't — key in browser code

javascript · client-side
// Anyone opening DevTools sees gua_live_... in the network tab.
const res = await fetch(
`https://getukaddress.com/api/v1/autocomplete` +
`?query=${q}&api_key=gua_your_key`
);

✅ Do — proxy through your backend

javascript · your frontend
// Hits your own server. No key in client code.
const res = await fetch(`/api/addresses?query=${q}`);
node · your backend (express)
const KEY = process.env.GETUKADDRESS_API_KEY; // server env, not exposed
app.get("/api/addresses", async (req, res) => {
const q = encodeURIComponent(req.query.query ?? "");
const upstream = await fetch(
`https://getukaddress.com/api/v1/autocomplete?query=${q}&api_key=${KEY}`
);
res.status(upstream.status).json(await upstream.json());
});

Same idea applies to Next.js / SvelteKit / Nuxt route handlers, Cloudflare Workers, or any serverless function — keep the key in the runtime environment, expose only a thin endpoint to the browser. Mobile apps are no exception: binaries can be reverse-engineered, so route mobile traffic through your backend too.

If a key ever does leak, revoke it from the dashboard and issue a fresh one — the old key stops working immediately.

Error envelope

Every 4xx/5xx response is shaped like RFC 9457 Problem Details, with two extensions: requestId for support traceability, and code for machine-readable client handling.

json · 429
{
"type": "https://getukaddress.com/errors/rate-limit-exceeded",
"title": "Rate Limit Exceeded",
"status": 429,
"code": "RATE_LIMIT_EXCEEDED",
"requestId": "req_a1b2c3d4"
}

Error codes

CodeHTTPWhen
INVALID_API_KEY401Key not found or revoked
EMAIL_NOT_VERIFIED403Account email unconfirmed
ACCOUNT_SUSPENDED403Account suspended by admin
SUBSCRIPTION_EXPIRED403Plan has lapsed
RATE_LIMIT_EXCEEDED429Daily quota exhausted
INVALID_REQUEST400Missing or malformed parameters
INTERNAL_ERROR500Unhandled server error

Rate limits

Every response includes three headers so you can throttle client-side:

headers
X-RateLimit-Limit: 500
X-RateLimit-Remaining: 423
X-RateLimit-Reset: 1712012400

Limits reset at 00:00 UTC. When you hit zero, you get a 429 with the RATE_LIMIT_EXCEEDED code.