Getting started

The Zapex API answers with UK addresses, places and maps, as JSON over HTTPS from https://api.zapex.co.uk. Every route is in the API reference.

Keys

Make a key in the dashboard, and send it with each request in Authorization: Bearer <key>.

KeyFor
zpx_live_…Your server. Shown once, when it is made: keep it secret.
zpx_pk_live_…A page: a widget or a map. It may call only what a browser needs, from the origins you name.
zpx_test_…, zpx_pk_test_…The sandbox, free: below.

Each key has scopes, which say what it may call, and rate limits: an organisation's over all its keys, a secret key's own, and for a publishable key each IP address's, by the second and by the day. Every response carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset for the limit the key is nearest. A request over one is 429 with Retry-After too, and scope in its body says which.

The sandbox

A test key calls the same routes over fixture data, and uses no credits. Its addresses are those of the postcodes SA1 1DF, SA1 1RE, SA1 1RP, SA1 1TY and SA1 8JQ in Swansea, with their areas and the bus stops and station near them; its location lists are its own.

curl https://api.zapex.co.uk/v1/addresses?q=8-9+wind+st \
  -H "Authorization: Bearer zpx_test_…"
curl https://api.zapex.co.uk/v1/addresses/100101046097 \
  -H "Authorization: Bearer zpx_test_…"

Errors

A failure answers with its status and a problem details body (RFC 9457, application/problem+json): type, title, status and detail, with code, which tells one failure from another, and field, the field it is of, as locations[2].lat. The codes are in the reference.

Credits

A live key uses its organisation’s credits: a lookup, a geocode, a query, each a credit; a search of the typeahead is free. An organisation buys credits in packs in the dashboard. With none left, a live key is refused with credits_exhausted (402). A key may have a monthly cap of its own.

Examples

Geocode an address, in JavaScript

const response = await fetch(
  'https://api.zapex.co.uk/v1/geocode/forward?q=' + encodeURIComponent('8-9 wind st swansea'),
  { headers: { Authorization: `Bearer ${process.env.ZAPEX_KEY}` } }
);
const { results } = await response.json();
const [best] = results;
if (best && best.confidence >= 0.8) {
  console.log(best.uprn, best.lines.line_1, best.location);
}

Cleanse a list of addresses, in Python

import os, time, requests

api = "https://api.zapex.co.uk/v1/cleansing/jobs"
headers = {"Authorization": f"Bearer {os.environ['ZAPEX_KEY']}"}

job = requests.post(api, headers=headers, json={"items": [
    {"id": "crm-1", "address": "8-9 wind st swansea"},
    {"id": "crm-2", "address": "1 east burrows rd sa1 1re"},
]}).json()

while job["status"] != "completed":
    time.sleep(2)
    job = requests.get(f"{api}/{job['id']}", headers=headers).json()

after = 0
while after is not None:
    page = requests.get(f"{api}/{job['id']}/results", headers=headers,
                        params={"after": after, "limit": 1000}).json()
    for item in page["results"]:
        print(item["id"], item["status"], (item["match"] or {}).get("uprn"))
    after = page["next"]

An address field in a form

<script src="https://cdn.zapex.co.uk/widgets/1/zapex-widgets.iife.js" defer></script>

<form action="/checkout" method="post">
  <zapex-address api-key="zpx_pk_live_…" name="delivery"
    fill="line_1:#line1, post_town:#town, postcode:#postcode"></zapex-address>
  <input id="line1" name="line1"> <input id="town" name="town"> <input id="postcode" name="postcode">
</form>

In React

import { ZapexAddress } from '@zapex/widgets/react';

export function Delivery({ onAddress }) {
  return <ZapexAddress apiKey="zpx_pk_live_…" name="delivery" onSelect={onAddress} />;
}

The nearest of your stores to a postcode

curl "https://api.zapex.co.uk/v1/location-lists/ll_…/nearest?postcode=SA1+1RE&limit=3&open_now=true" \
  -H "Authorization: Bearer zpx_live_…"

Which of your delivery zones hold an order

curl https://api.zapex.co.uk/v1/zones/contains \
  -H "Authorization: Bearer zpx_live_…" -H "Content-Type: application/json" \
  -d '{"zones": {"type": "FeatureCollection", "features": [{"type": "Feature", "id": "city-centre",
        "geometry": {"type": "Polygon", "coordinates": [[[-3.95,51.61],[-3.93,51.61],[-3.93,51.63],[-3.95,51.63],[-3.95,51.61]]]}}]},
       "points": [{"id": "order-1", "lat": 51.6174, "lng": -3.9370}]}'

A map, with MapLibre GL

import maplibregl from 'maplibre-gl';

new maplibregl.Map({
  container: 'map',
  style: 'https://api.zapex.co.uk/v1/maps/styles/color?key=zpx_pk_live_…',
  center: [-3.94, 51.62],
  zoom: 13,
});