Postcode Intelligence

Enrich any UK postcode with geographic, demographic, environmental, and economic signals from authoritative OGL sources.

Endpoints

GET /v1/postcode/{postcode} GET /v1/postcode/nearest?lat={lat}&lon={lon} GET /v1/postcode/within?lat={lat}&lon={lon} POST /v1/postcode/bulk POST /v1/postcode/bulk/async GET /v1/postcode/bulk/jobs/{jobId} DELETE /v1/postcode/bulk/jobs/{jobId}

Input formats

The endpoint accepts four input modes:

ModeExampleReturns
Full postcodeGET /v1/postcode/SW1A+2AAAll signals. Case-insensitive, space optional.
Outward code onlyGET /v1/postcode/SW1ADistrict-level signals only — geography, admin areas, constituency. Flood, broadband, property price, crime, and MP data are omitted as they vary too much within a district.
Nearest to coordinatesGET /v1/postcode/nearest?lat=51.50&lon=-0.13Nearest single postcode centroid with full signal set, plus queryPointDistanceMetres.
All postcodes within radiusGET /v1/postcode/within?lat=51.50&lon=-0.13Postcode centroids within the radius, ordered by distance, up to your plan's bulk cap (Starter 50, Pro 100, Business 250, Enterprise 500). Each result costs 1 quota unit. Starter and above only.

Northern Ireland (BT postcodes) return a 422 unsupported_region error on all input modes.

Reverse geocode — nearest postcode

Snap a coordinate to its nearest postcode — useful for resolving GPS coordinates, validating delivery addresses, or snapping device location to a postcode. Returns the full signal set plus a queryPointDistanceMetres field.

ParameterTypeNotes
latnumberRequired. Decimal degrees, WGS84.
lonnumberRequired. Decimal degrees, WGS84.
radiusintegerOptional. Search radius in metres. Default 1000. Returns 404 if no centroid falls within the radius.
GET /v1/postcode/nearest?lat=51.5034&lon=-0.1276&radius=500 abbreviated — full signal set below
{
  "postcode": "SW1A 2AA",
  "queryPointDistanceMetres": 87.3,
  "latitude": 51.5034,
  "longitude": -0.1276,
  "country": "England",
  "region": "London",
  "adminDistrict": "City of Westminster",
  /* ... geography, broadband, flood, crime, property,
         deprivation, demographics, housing, political ... */
  "summary": { "liveabilityLevel": "medium", "propertyRiskLevel": "low" /* ... */ },
  "signals": { /* full signal set */ },
  "quota": { "remaining": 9999, "limit": 10000, "resetAt": "2026-07-01T00:00:00Z" }
}

Same shape as a single postcode lookup, plus queryPointDistanceMetres. See the full response shape and all fields in the Response section below.

Postcodes within a radius

Use this when you need to understand an area rather than a single point — zone risk assessment, delivery catchment analysis, or property research across a neighbourhood. Returns every postcode centroid within the radius, ordered by distance. Each postcode in the result costs one quota unit.

ParameterTypeNotes
latnumberRequired. Decimal degrees, WGS84.
lonnumberRequired. Decimal degrees, WGS84.
radiusintegerOptional. Search radius in metres. Default 1000, max 5000. Returns 404 if no centroids fall within the radius.
TierMax results per call
FreeNot available
MicroNot available
Starter50
Pro100
Business250
Enterprise500
GET /v1/postcode/within?lat=51.5034&lon=-0.1276&radius=200 abbreviated — each result has the full signal set
{
  "total": 3,
  "results": [
    {
      "postcode": "SW1A 2AA",
      "queryPointDistanceMetres": 87.3,
      "latitude": 51.5034,
      "longitude": -0.1276,
      "country": "England",
      "region": "London",
      "adminDistrict": "City of Westminster",
      /* ... geography, broadband, flood, crime, property,
             deprivation, demographics, housing, political ... */
      "summary": { "propertyRiskLevel": "low", "liveabilityLevel": "medium" /* ... */ },
      "signals": { /* full signal set — same shape as single postcode lookup */ }
    },
    {
      "postcode": "SW1A 1AA",
      "queryPointDistanceMetres": 142.1
      /* ... full signal set ... */
    },
    {
      "postcode": "SW1Y 5AH",
      "queryPointDistanceMetres": 198.4
      /* ... full signal set ... */
    }
  ],
  "quota": { "remaining": 9997, "limit": 10000, "resetAt": "2026-07-01T00:00:00Z" }
}

Each result in results[] has the full postcode signal set — identical to a single GET /v1/postcode/{postcode} response, plus queryPointDistanceMetres. See the signal reference for all fields.

Response

Returns a JSON object. See the signal reference for all fields and values. All field names are camelCase.

Brief example — SW1A 2AA
{
  "postcode": "SW1A 2AA",
  "adminDistrict": "City of Westminster",
  "region": "London",
  "summary": {
    "propertyRiskLevel": "low",
    "liveabilityLevel": "medium",
    "insuranceRiskLevel": "low"
  },
  "signals": {
    "flood":      { "riversSea": "very_low" },
    "deprivation":{ "imdDecile": 8 },
    "crime":      { "rateBand": "high" },
    "property":   { "averagePrice": 2847000 },
    "broadband":  { "gigabit": true },
    "political":  { "mpName": "Nickie Aiken" }
  },
  "scores": {
    "propertyRiskScore": 0.22,
    "liveabilityScore": 0.61
  }
}

Bulk lookups

Available on Starter and above. Quota is consumed upfront for the full batch.

TierPostcodes per call
FreeNot available
MicroNot available
Starter50
Pro100
Business250
Enterprise500

Synchronous bulk

All results returned immediately. Best for batches processed inline.

POST /v1/postcode/bulk
// Request
{ "postcodes": ["SW1A 2AA", "EC1A 1BB", "M1 1AE"] }

// Response 200
{
  "total": 3,
  "results": [
    { /* full postcode response */ },
    { "postcode": "EC1A 1BB", "error": "not_found" },
    { "postcode": "BT1 1AA",  "error": "unsupported_region" }
  ]
}

Async bulk

Submit a job and poll for results. Useful for large batches or background processing. Jobs expire 24 hours after submission.

POST /v1/postcode/bulk/async → 202 Accepted
// Request
{ "postcodes": ["SW1A 2AA", "EC1A 1BB"] }

// Response 202
{
  "jobId":   "bulk_4f3a9c1e72b8d5",
  "status":  "queued",
  "total":   2,
  "pollUrl": "/v1/postcode/bulk/jobs/bulk_4f3a9c1e72b8d5"
}
GET /v1/postcode/bulk/jobs/{jobId} — poll until status = "complete"
{
  "jobId":       "bulk_4f3a9c1e72b8d5",
  "status":      "complete",
  "total":       2,
  "done":        2,
  "createdAt":   "2026-05-18T10:00:00Z",
  "completedAt": "2026-05-18T10:00:03Z",
  "expiresAt":   "2026-05-19T10:00:00Z",
  "results": [ /* full postcode responses */ ]
}

Status lifecycle: queuedprocessingcomplete | failedexpired

Use DELETE /v1/postcode/bulk/jobs/{jobId} to clean up a job before it expires.