UK Planning Applications API reference
Structured, classified, source-linked UK planning application data over a REST JSON API. Base URL https://api.plota.co.uk/v1
Authentication
Every request needs an API key, sent as a bearer token (preferred) or the X-API-Key header. Keys are secret - never expose them in client-side code.
# A postcode DISTRICT - matches the postcode recorded on the application
curl "https://api.plota.co.uk/v1/applications?postcode=SW11&limit=5" \
-H "Authorization: Bearer plota_live_your_key"
# A FULL postcode, or anything "within X metres of here" - use nearby + radius.
# radius is in metres, default 1000, maximum 5000.
curl "https://api.plota.co.uk/v1/applications/nearby?postcode=SW11+6HB&radius=2000&limit=5" \
-H "Authorization: Bearer plota_live_your_key"Endpoints
| Endpoint | Purpose |
|---|---|
GET /v1/applications | Search applications with filters + cursor pagination |
GET /v1/applications/{id} | Retrieve one application by public id or numeric id |
GET /v1/applications/nearby | Applications near a coordinate or postcode |
GET /v1/councils | Covered councils with coverage metadata |
GET /v1/categories | Plota planning categories |
GET /v1/alerts | Saved alerts belonging to your key’s email |
GET /v1/alerts/{id} | Retrieve one saved alert |
GET /v1/alerts/{id}/matches | Applications matching a saved alert |
POST /v1/alerts | Create a saved alert: a radius, a council or national, or a freehold owner (Pro and above) |
PATCH /v1/alerts/{id} | Change a saved alert |
DELETE /v1/alerts/{id} | Delete a saved alert |
GET /v1/owners | Freehold owners by company name or number, owners of the most freehold titles first (Pro and above; owner docs) |
GET /v1/owners/{number} | One freehold owner, or its whole group: its Companies House record, the applications on its land, permissions about to lapse, refusals, agents, appeals and the titles it has bought |
GET /v1/owners/{number}/applications | Every application on land a company or its group owns, live then historical, as full application records |
GET /v1/owners/{number}/group | The group a company belongs to, as a tree from its top company |
GET /v1/applications/{id}/history | Status & decision timeline |
GET /v1/applications/{id}/associated | Associated applications - the family around one principal application |
GET /v1/applications/{id}/documents | Documents - every document on the council file, with its type, date and group (plans, statements, decision...), and a link to the council’s documents page; titles naming a member of the public are marked |
GET /v1/constraints | Site constraints at a point - listed buildings, conservation area, flood zone, green belt, radon, coal mining, national infrastructure, protected trees, protected views, flood zones plus climate change, flood defences, public transport access (PTAL) and the rest at any coordinate or postcode (Pro and above; one record per point) |
GET /v1/consents/expiring | Consents reaching their time limit - permitted consents whose statutory limit falls in the window, with what has been filed since |
GET /v1/appeals | Planning appeals - Inspectorate decisions, newest first, each joined to the application it concerns |
GET /v1/decision-stats | Decision times and approval rates - median days, within eight weeks, approval rate and rank for a council, a nation or the UK, by kind of application |
GET /v1/hmo-licences | HMO licences from council registers: search by place, status, licence type, occupants, expiry and planning at the address |
GET /v1/hmo-licences/{id} | Retrieve one HMO licence |
GET /v1/hmo-licences/coverage | Which councils’ HMO registers are served, at what coverage, and why not where they are not |
POST /v1/exports | Bulk export as CSV/JSON (Starter+) |
POST /v1/webhooks | Register a signed webhook (Starter+) |
GET / DELETE /v1/webhooks/{id} | List or remove webhooks |
POST /v1/webhooks/{id}/test | Send a test event |
Query parameters
GET /v1/applications accepts:
| Parameter | Description |
|---|---|
postcode | Matches the postcode recorded on the application, case- and space-insensitive (SW11 6HB and SW116HB are the same query). A district like SW11 matches everything in it. A full postcode covers about 15 addresses, so use /v1/applications/nearby for everything within a distance of a point |
council | Council slug (see /v1/councils), e.g. wandsworth |
nation | england, scotland, wales, northern-ireland |
category | One or more category slugs, comma-separated (see /v1/categories). Categories are on live records (2026 onward), so a category-filtered page does not include historical records; meta.historical_note says so. The same holds for status, applicant and agent. |
q | Keyword match in description, address, or reference |
reference | Exact council reference, e.g. 3PL/2024/0561/HOU - case- and space-insensitive. Unique only within a council, so add council to pin one application |
stage | Normalised decision stage: pending, approved, refused, withdrawn, decided, other. Councils word their status and decision 4,383 different ways, so this is the filter to use. What each value covers is set out under Normalised vs verbatim below |
procedure | Normalised consent route - what kind of permission is sought: full, outline, reserved-matters, discharge, amendment, listed-building, advert-consent, tree-works, prior-approval, lawful-dev-cert, pre-application, eia-opinion, planning-obligation, other. Comma-separated. One scheme generates several records - a full application, then condition discharges, amendments and reserved matters - so use procedure=full,outline when counting real proposals rather than paperwork. eia-opinion is a request for an EIA screening or scoping opinion: not an application, but it describes a real scheme (often the first public sign of a major one), so its categories and dwelling count describe that scheme. planning-obligation is a Section 106 (or Section 75) planning obligation record: a modification, discharge or deed of variation of an obligation, or details and notices under one, not a planning application. Normalised the same way on live and archive records. Records with no identifiable route have procedure null and are excluded by the filter. On historical (pre-2026) records the route is read from the record's own description, with the council's broader application type where the description states none; a historical record whose description states no route has procedure null. |
commercial_work | Commercial premises classification - the kind of work, comma-separated: new (new commercial premises), extension (more commercial floorspace), to-commercial (change to a commercial use), between (change between commercial uses, including subdivision), loss (commercial premises lost to another use), minor (works to existing premises with no change of floorspace or use). Every application is read individually; each record also carries commercial (null until the record has been read), commercial_use_class and floorspace_sqm where the council states them. For the supply of commercial space use commercial_work=new,extension,to-commercial,between; add dmin=5 for residential schemes of five or more homes. Live records only |
committee | committee=1 returns applications with a planning committee decision on Plota. Each record carries committee: the newest decision as { outcome, meeting_date, committee, url } (the URL is its committee page, with the vote and the minutes), or null. Combine with decided_from/decided_to as usual. Free on every plan. Live records only |
major | Major developments in the legal sense: 10 or more homes, 1,000 square metres of floorspace, a site of 1 hectare, or minerals and waste. major=1 returns the major schemes themselves (full, outline, reserved matters, variations); major=all adds the paperwork on them (condition discharges, amendments, legal agreements, certificates). Each record carries major_development: true, false, or null where the description cannot settle it. Free on every plan. Live records only |
parish | ONS parish or community code (E04… England, W04… Wales). Records whose coordinates fall inside the official parish boundary, the same test the council pages use, so council becomes optional. Records without coordinates (about 3%) cannot match and stay under their council; Scotland and Northern Ireland have no parish tier. The response carries meta.parish with the code, name and council area. Example: parish=E04004502 (Four Marks). |
dmin | Minimum stated dwelling count, e.g. dmin=5 for schemes of five or more homes. Live records only |
owner_company / owner_scope | Applications on land a company owns the freehold of: its Companies House number (owner_company=03512363; leading zeros may be left off), and owner_scope=group for every company in its group (company by default). meta.owner_filter names it. Live records only: /v1/owners/{number}/applications adds the historical ones. Pro plan and above |
leaseholder_company | Applications where a company holds a registered lease of the property, of part of its building, or of the whole building a flat or unit is in: its Companies House number. meta.leaseholder_filter names it; the leaseholders field on each record says what the lease is of. Never the freehold owner (that is owner_company). Live records only. Pro plan and above. |
owner_type | The kind of owner, alone or with owner_company: any (any company or public body), public (local authorities, county councils and other corporate bodies), housing (housing associations and the societies most of them are registered as), overseas (incorporated outside the UK). Live records only. Pro plan and above. |
min_price / max_price | The last sale price of the property the application is about, in pounds (HM Land Registry price paid, England and Wales, matched by address): min_price=500000 for properties that last sold for £500,000 or more. Applications with no matched sale are excluded. Live records only. Pro plan and above |
min_floor_area / max_floor_area | The floor area of the property the application is about, in square metres, from its latest energy performance certificate (England and Wales): min_floor_area=150 for properties of 150 m² or more. Applications with no certificate are excluded. Live records only. Every paid plan |
epc_rating | The energy rating on the property's latest energy performance certificate, one or more of A+, A, B, C, D, E, F, G, comma separated: epc_rating=E,F,G. Applications with no certificate are excluded. Live records only. Every paid plan |
date_from / date_to | Filter by received date, YYYY-MM-DD |
changed_since | The change signal for a local copy. Returns records whose content changed at or after the instant - status, decision and its dates, key dates, documents, description, classification. YYYY-MM-DD or an ISO 8601 datetime such as 2026-09-04T05:30:00Z (no offset = UTC). Every record carries changed_at; store the largest you have seen and poll with it, one call per council per night, paging with cursor and upserting by id. updated_at moves on every re-check and is not a signal. Live records only: archive records never change. Pro plan and above |
decided_from / decided_to | Filter by decision date, YYYY-MM-DD: a council's decisions in a window in one call. Records without a decision date are excluded. Live records only. Every plan |
limit / per_page | Page size, capped per plan (Demo 10 → Business 250). per_page is an alias for limit; if both are sent, limit wins. |
radius | /applications/nearby only. Search distance in metres from the lat/lng or resolved postcode. Default 1000, maximum 5000; anything larger is clamped. |
days | /alerts/{id}/matches only. How many days back to return matches for. Default 90, maximum 365. |
lat / lng or postcode | /constraints only. The point to check: a coordinate in the UK, or a full postcode geocoded server-side. Pro plan and above; one record per distinct point. |
cursor | Opaque pagination cursor from meta.next_cursor. Pages continue seamlessly from live records into the pre-2026 archive on paid plans; a null next_cursor always means the genuine end of the results |
total | total=1 adds meta.total - the whole-query match count across live and (plan permitting) archive. Costs an extra count query, so request it on the first page rather than every page |
format | json (default) or csv |
include_contact | Contact Data add-on only: false omits contact fields on this call so nothing is metered against your monthly contact allowance |
Response metadata
Every response carries a meta object. Besides paging, it is where the API explains itself: why a result set is empty, when archive records were withheld, and how much of a metered allowance a call consumed. Reading it is the difference between "no data" and "wrong query".
| Field | Meaning |
|---|---|
count | Number of records in data for this page. |
next_cursor | Pass back as cursor for the next page. Absent on the last page. |
hint | Present when a query returned nothing and the reason is knowable. A full postcode covers roughly 15 addresses, so an exact-postcode search often returns zero legitimately - this field says so and points at /applications/nearby with a radius. Check for this before treating an empty result as no data. |
historical_available | Records exist before the live cutoff that your plan cannot see. Upgrade to include them. |
historical_included | Archive records were merged into this response. |
historical_more | More archive records matched than fit this page - next_cursor continues into the archive, so keep following it exactly as with live pages. |
total | Only with ?total=1: how many records match the whole query (live plus archive where your plan includes it). total_capped marks a count that was clamped: a very large archive count, or a live count under a broad property price filter, which stops at 10,000. |
historical_note | Plain-English explanation of the archive result: either that history needs a paid plan, or that the query needs a council, nation, coordinates or keyword alongside the date range. |
contact | Contact Data add-on only: how many contact-bearing records this call metered, and what remains this month. |
monthly_rows_cap / monthly_rows_used | Export endpoints: your plan's monthly row allowance and how much of it is spent. |
owner | Alert endpoints: the account the alert belongs to. |
attribution | The licence statements for licensed data the response carries (HM Land Registry price paid, the freehold outline, the freehold owner and Companies House). Show them wherever you show that data. |
owner_filter | With owner_company, and on /v1/owners/{number}/applications: the company the records are on the land of, its name (the group's top company in the group view), the scope and how many companies it covers. |
sources | Owner endpoints: the releases the owner data comes from, HM Land Registry's owners file and Companies House's company file, each as a month and as YYYY-MM, and when the Companies House file was loaded. |
live_total / historical_total | /v1/owners/{number}/applications: the live and historical records matching; total is their sum. historical_capped marks an owner with more than 5,000 historical records, of which the first 5,000 are listed. |
applications_listed | /v1/owners/{number}: how many distinct applications the owner record's lists carry, each charged as a record like any other. |
Pagination
List endpoints use opaque cursor pagination. Pass meta.next_cursor back as cursor to fetch the next page. A null next_cursor means the last page.
{
"data": [
"..."
],
"meta": {
"limit": 25,
"count": 25,
"next_cursor": "eyJzIjoiMjAyNi0wNi0xOCIsImkiOjE4fQ"
}
}Rate limits & quotas
Every response carries X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, plus monthly counterparts. A 429 includes Retry-After.
| Plan | Per minute | Requests | Records | Max page |
|---|---|---|---|---|
| Demo | 30 / min | 500 one-off | 500 one-off | 10 |
| Starter | 120 / min | 20,000 / month | 10,000 / month | 50 |
| Pro | 300 / min | 200,000 / month | 100,000 / month | 100 |
| Business | 600 / min | 500,000 / month | 250,000 / month | 250 |
| Enterprise | 1,200 / min | Custom | Custom | 500 |
The change feed (changed_since) is available on the Pro plan and above; Starter and Demo keys receive a 403 naming the parameter. Decisions by date (decided_from, decided_to) are on every plan. The property's UPRN and outline (plota_uprn, outline) are on every paid plan. Price paid (last_sale, sales) and filtering by property price (min_price, max_price) are on the Pro plan and above; below it the fields are absent and the filters return a 403. Historical records before 2026 are on paid plans.
Site constraints are on the Pro plan and above: every record carries constraints at no extra cost, and GET /v1/constraints checks any point for one record. Starter and Demo keys do not see the field and receive a 403 from the endpoint.
Records = distinct applications delivered to your account in a calendar month, across search, the change feed and POST /v1/exports. A record is charged the first time it reaches you in a month and is free to read again; every response carries X-Records-Limit-Month and X-Records-Remaining-Month. A one-off top-up adds 25,000 for £49, up to twice a month. Keys issued before 11 September 2026 keep the request and export-rows allowances they were sold; the old export note follows.
Export rows (plans before 11 September 2026) = the total POST /v1/exports rows a key can pull per calendar month, across all export calls. Per-call caps still apply; the response reports both via meta.monthly_rows_used and meta.monthly_rows_cap.
Errors
Errors use a consistent shape with a request_id you can quote in support.
{
"error": {
"type": "invalid_request",
"message": "The postcode parameter is invalid.",
"param": "postcode",
"request_id": "req_01jz7k8a2p8b"
}
}| HTTP | type | Meaning |
|---|---|---|
| 400 | invalid_request | A parameter is missing or malformed |
| 401 | authentication_error | Missing, invalid, or revoked API key |
| 403 | permission_error | Your plan does not allow this resource |
| 404 | not_found | No resource with that id |
| 429 | rate_limit_error | Per-minute or monthly quota exceeded |
| 500 | server_error | An unexpected error on our side |
| 501 | not_implemented | A roadmap endpoint not yet live |
The application object
Every application has the same fields, whichever council it comes from. Beyond the core record, each application carries enrichment read from the full council file - ward, parish, UPRN, decision detail, procedural dates, document and public-comment counts. On every paid plan each record also carries plota_uprn, the UPRN Plota holds for the property beside the council's own uprn; a single-record response adds the freehold outline as GeoJSON where HM Land Registry names the parcel on a sale of the property and the property's UPRN point sits inside it, or the property's UPRN point lies inside exactly one freehold parcel of 30 m2 to 1 ha, at least 1 m from its edge, that holds no other property on our records (or only flats of the same building, when the outline is the building's), and the address is the property itself (not land or a place beside it). On the Pro plan and above each record also carries last_sale, the property's last sale from HM Land Registry price paid (England and Wales), and a single record every sale, and freehold_owner, the company that owns the freehold where one does, with leaseholders beside it, the companies holding a lease (Freehold owners and leaseholders, below). The licence statements are in meta.attribution. On the Pro plan and above it also carries constraints, what the national open datasets put at the site (below). A decided application looks like this:
{
"id": "a1b2c3d4",
"reference": "2026/2284/FUL",
"authority": {
"slug": "wandsworth",
"name": "Wandsworth"
},
"address": "81 Example Road, London SW11 6HB",
"postcode": "SW11 6HB",
"ward": "Northcote",
"parish": null,
"parish_code": null,
"uprn": "100022543210",
"plota_uprn": "100022543210",
"plota_uprn_source": "council",
"description": "Single storey rear extension.",
"category": {
"slug": "extensions",
"label": "Extensions & alterations"
},
"categories": [
{
"slug": "extensions",
"label": "Extensions & alterations"
}
],
"planning_route": "Full planning permission",
"dwelling_count": null,
"commercial": true,
"commercial_work": "between",
"major_development": false,
"committee": null,
"commercial_use_class": "E(b)",
"floorspace_sqm": null,
"status": "Application Permitted",
"stage": "approved",
"decision": {
"outcome": "Application Permitted",
"issued_date": "2026-07-14",
"level": "Delegated"
},
"appeal": null,
"date_received": "2026-05-18",
"date_validated": "2026-05-20",
"date_decided": "2026-07-10",
"date_precision": {
"received": "day",
"decided": "day"
},
"key_dates": {
"target_decision": "2026-07-15",
"committee": null,
"consultation_end": "2026-06-19",
"advertised": "2026-05-28",
"statutory_expiry": "2026-07-15",
"permission_expiry": "2029-07-10"
},
"location": {
"lat": 51.4601,
"lng": -0.1702
},
"last_sale": {
"price": 685000,
"date": "2021-03-12",
"property_type": "terraced",
"tenure": "freehold"
},
"constraints": [
{
"layer": "conservation",
"label": "Conservation areas",
"relation": "within",
"metres": null,
"name": "Northcote Road",
"reference": "CA12",
"grade": null,
"url": "https://...",
"dataset": null
},
{
"layer": "listed",
"label": "Listed buildings",
"relation": "near",
"metres": 64,
"name": "Church of St Michael",
"reference": "1065432",
"grade": "II",
"url": "https://historicengland.org.uk/listing/the-list/list-entry/1065432",
"dataset": null
}
],
"documents_count": 14,
"comments": {
"objections": 2,
"supporting": 5,
"received": 8,
"consulted": 21,
"counted_at": "2026-07-29T06:40:12Z"
},
"links": {
"plota": "https://plota.co.uk/application/a1b2c3d4",
"council": "https://..."
},
"source": "live"
}Site constraints
What the national open datasets put at the site, on every record for the Pro plan and above as constraints, and for any point through GET /v1/constraints?lat=&lng= (or postcode=). Areas the site is inside: conservation area, flood zone, green belt, national park and landscape, SSSI, ancient woodland, Article 4 directions, tree preservation, archaeological priority, air quality, nutrient neutrality, agricultural land grade, radon class (2 to 6, the 1 km square's highest), the coal mining development high risk area and coalfield, national infrastructure project boundaries, London protected views (a landmark viewing corridor or its wider setting), the flood zones plus climate change (the Environment Agency's zones 2 and 3 grown for its climate change allowances), TfL's public transport access level for the 100 m square (PTAL 0 to 6b, 2023), the London Plan designations, and a listed building's outline where its council has published one. Features near it: listed buildings within 150 m, scheduled monuments within 250 m, rights of way within 30 m, recorded mine shafts and adits within 50 m, national infrastructure projects within 2 km, single protected trees within 15 m of a point on the building (your own lat and lng or an address, never a postcode), and flood defences within 50 m, with the distance. Most significant first, each with a source link. Sources are Historic England, the Environment Agency, Natural England, Cadw, NatureScot, the Mining Remediation Authority, the Planning Inspectorate, the Greater London Authority, the British Geological Survey and UK Health Security Agency (radon; contains BGS materials © UKRI), Transport for London (public transport access levels; Powered by TfL Open Data, contains OS data © Crown copyright and database right 2025) and councils via planning.data.gov.uk, all Open Government Licence.
{
"data": {
"location": {
"lat": 54.314807,
"lng": -2.07982
},
"constraints": [
{
"layer": "listed",
"label": "Listed buildings",
"relation": "near",
"metres": 27,
"name": "SALISBURY HOUSE AND RAILINGS",
"reference": "1157347",
"grade": "II",
"url": "https://historicengland.org.uk/listing/the-list/list-entry/1157347",
"dataset": null
},
{
"layer": "park",
"label": "National parks",
"relation": "within",
"metres": null,
"name": "Yorkshire Dales",
"reference": null,
"grade": null,
"url": null,
"dataset": null
},
{
"layer": "conservation",
"label": "Conservation areas",
"relation": "within",
"metres": null,
"name": "Askrigg",
"reference": "307",
"grade": null,
"url": "https://www.yorkshiredales.org.uk/about/heritage/cultural-heritage/conservation-areas/",
"dataset": null
},
{
"layer": "agri",
"label": "Agricultural land",
"relation": "within",
"metres": null,
"name": null,
"reference": null,
"grade": "Grade 4",
"url": null,
"dataset": null
},
{
"layer": "listed",
"label": "Listed buildings",
"relation": "near",
"metres": 36,
"name": "WENDAL AND HOUSE TO NORTH-EAST",
"reference": "1131187",
"grade": "II",
"url": "https://historicengland.org.uk/listing/the-list/list-entry/1131187",
"dataset": null
}
]
},
"meta": {
"count": 27,
"checked_at": "2026-09-11T14:05:39.000Z",
"sources": "Historic England, the Environment Agency, Natural England, Cadw, NatureScot and councils via planning.data.gov.uk, Open Government Licence",
"records": {
"used": 1204,
"cap": 100000,
"remaining": 98796,
"one_off": false
}
}
}Reading it. relation is within for an area the point is inside and near for a feature within its distance, with metres. A listed building within 30 m is the building itself. grade carries the listing grade, the flood zone (2 or 3) or the agricultural land grade (1 to 5, with 3a and 3b; for farmland dataset says surveyed or predicted; the 1970s provisional map's grade comes as its own entry with layer agriprov, for comparison with what other services show). dataset names the designation where several share a layer (a Ramsar wetland inside protected wildlife sites). For layer nsip, a national infrastructure project within 2 km, grade is its stage (pre-application, acceptance, pre-examination, examination, recommendation, decision, decided or withdrawn), dataset its type and reference the Planning Inspectorate's reference. For radon, grade is the class (2 to 6, the highest in the 1 km square). For coal, dataset is development-high-risk-area, coalfield or mine-entry (a recorded shaft or adit within 50 m, reference the Mining Remediation Authority's). A tpo entry with dataset tree is a single protected tree within 15 m, read only for your own lat and lng, an address or a record pinned to the building. A listed entry with dataset listed-building-outline was decided by the council's outline of the building, and within means the point is inside it. For views, dataset is corridor or wider and reference the view number. floodcc is the flood zones plus climate change, with the flood source as name. For flooddef, a defence within 50 m, name is its type, grade its design standard (the N in a 1 in N year flood) and dataset what it protects against. For ptal, grade is TfL's band (0 to 6b) and dataset ptal-2023. On an application record the array is [] when the site was checked and nothing is there, and null until the nightly check reaches a new record.
What it costs. On records, nothing beyond the record. A point lookup is one record against your monthly allowance per distinct point; re-reading the same point is free, like re-reading the same record. The point must be in the United Kingdom; a boundary can run through a site and the council holds the definitive record, so confirm with the council before relying on it.
Associated applications
An outline application is followed by reserved matters, variations under section 73, and dozens of discharges of conditions and non-material amendments, each with its own reference. GET /v1/applications/{id}/associated returns that whole family for any live application: the principal application, everything beneath it, and where the requested application sits. Members are linked in two ways, both exact and within the same authority: by the references each application cites in its description, and by a shared reference core - 24/01355/FUL and 24/01355/COND1 - where the council numbers follow-on applications off the principal application and the two records share a site. Nothing is inferred from proximity alone, so a link is either certain or absent.
{
"data": {
"id": "e887wk1m",
"reference": "26/00152/NMMA",
"role": "member",
"principal": {
"id": "h_3f9c2a1b7d4e",
"reference": "16/00608/OUT",
"authority": {
"slug": "ipswich",
"name": "Ipswich"
},
"procedure": "outline",
"stage": "approved",
"date_received": "2016-06-22",
"date_decided": "2020-01-31",
"links": {
"plota": null,
"council": "https://...",
"associated": null
},
"source": "historical",
"parent_id": null,
"parent_reference": null,
"depth": 0,
"is_this": false
},
"conditions": [
{
"number": "4",
"label": "Materials",
"status": "discharged",
"parent_id": "h_3f9c2a1b7d4e",
"parent_reference": "16/00608/OUT",
"applications": [
"m8k2v1qz"
]
},
{
"number": "9",
"label": "Surface water drainage",
"status": "submitted",
"parent_id": "h_3f9c2a1b7d4e",
"parent_reference": "16/00608/OUT",
"applications": [
"e887wk1m"
]
}
],
"count": 23,
"applications": [
{
"id": "h_3f9c2a1b7d4e",
"reference": "16/00608/OUT",
"procedure": "outline",
"stage": "approved",
"depth": 0,
"parent_id": null,
"is_this": false,
"source": "historical",
"links": {
"plota": null,
"council": "https://...",
"associated": null
}
},
{
"id": "h_a81d0c5e2f77",
"reference": "23/00406/REM",
"procedure": "reserved-matters",
"stage": "approved",
"depth": 1,
"parent_id": "h_3f9c2a1b7d4e",
"parent_reference": "16/00608/OUT",
"is_this": false,
"source": "historical"
},
{
"id": "e887wk1m",
"reference": "26/00152/NMMA",
"procedure": "amendment",
"stage": "refused",
"depth": 2,
"parent_id": "h_a81d0c5e2f77",
"parent_reference": "23/00406/REM",
"is_this": true,
"source": "live",
"links": {
"plota": "https://plota.co.uk/application/e887wk1m",
"council": "https://...",
"associated": "https://api.plota.co.uk/v1/applications/e887wk1m/associated"
}
},
"..."
]
},
"meta": {
"how": "Members are linked by cited references and by shared reference cores at the same site, exactly and within the same authority.",
"historical_available": true
}
}Reading it. applications is every member in date order; rebuild the tree from parent_id and depth (0 = a principal application). role says where the requested record sits: principal (others hang off it), member (it belongs to the principal returned alongside), linked (relatives exist but no principal could be placed), or standalone. is_this marks the requested application. Every live application also carries links.associated, and single-application responses include an associated summary (role, count, principal) so you can decide whether to fetch the family at all.
Historical members. Principal applications often predate 2026, so they come from the Plota archive with source: "historical" and an h_ id (not individually retrievable - keep authority.slug + reference). On the demo plan historical members are omitted and meta.historical_omitted says how many; parent_reference still names an omitted parent. Each call is one request; rows delivered = members returned.
Conditions. conditions is the condition ledger, read from the discharge and variation applications in the family: per condition number, which member's condition it is (parent_id, parent_reference - the principal, or a variation that later discharges cite), the label the council wrote after it, a status - discharged, submitted, decided (outcome not recorded), refused, withdrawn, varied, variation_sought - and the ids of the applications about it. Where an authority's decisions are not re-checked no outcome is claimed - only submitted and variation_sought appear - and meta.conditions_note says so.
Planning appeals
GET /v1/appeals returns decided planning appeals from the Planning Inspectorate's casework database (England, Open Government Licence; meta.source says the date the file runs to), newest first, each joined to the planning application it concerns wherever the LPA reference matches inside the same authority: a live Plota id, an archive id, or the reference alone. Filter by council, outcome (allowed, dismissed, split, quashed, withdrawn, invalid, other), type (planning, householder, enforcement, listed, lawful, advert, trees), since / until, reference, postcode prefix and min_residences. reference takes the council’s application reference or a Planning Inspectorate appeal reference (APP/F2605/W/24/3351737, its case number 3351737, or APP/TPO/X1925/10554), which finds that case whatever its kind; kind=other reaches the specialist casework in the same file (call-ins, orders, certificates), which is left out by default. Single-application responses carry an appeals array. Appellant and agent names are included with the Contact Data add-on and count against its allowance like any contact record. Available on every plan.
{
"data": [
{
"case_number": "3252821",
"casework_type": "Planning Appeal",
"outcome": "dismissed",
"decision": "Dismissed",
"decision_date": "2021-08-02",
"lpa_decision_date": "2019-11-21",
"procedure": "Written Representations",
"development_type": "Other minor developments",
"authority": {
"slug": "braintree",
"name": "Braintree"
},
"application": {
"id": "h_2f0c9a1b7e33",
"reference": "19/01757/FUL",
"source": "historical",
"links": {
"plota": null
}
},
"site_address": "90-92 Newland Street, Witham, CM8 1AS",
"postcode": "CM8 1AS",
"residences": 0,
"...": "received_date, start_date, appeal_reason, lpa_name, ons_code, green_belt, costs_applied, enforcement_grounds, link_status, lead_case",
"links": {
"inspectorate": "https://acp.planninginspectorate.gov.uk/ViewCase.aspx?CaseID=3252821"
},
"source": "Horizon"
}
],
"meta": {
"count": 1,
"next_cursor": null,
"source": "Planning Inspectorate casework database (England)..."
}
}Consents reaching their time limit
A planning permission usually has three years to be begun in England and Scotland, five in Wales and Northern Ireland, and an outline three years to apply for its reserved matters. GET /v1/consents/expiring returns every permitted full or outline planning permission in the Plota archive whose statutory limit falls in the window you ask for - the next six months by default, up to 12 ahead with months, and the last 90 days too with passed=1 - scoped to a council or a bbox, with the decision date, the limit and what has been filed against it since. Householder consents are excluded unless householder=include (or only); min_homes keeps only schemes of that size. Commercial plans.
{
"data": [
{
"id": "h_9c1e77a2b4d0",
"reference": "23/01187/OUT",
"authority": {
"slug": "north-hertfordshire",
"name": "North Hertfordshire"
},
"address": "Land east of Mill Lane, Baldock",
"postcode": "SG7 6PP",
"procedure": "outline",
"decided_date": "2023-11-14",
"time_limit": {
"date": "2026-11-14",
"rule": "reserved_matters",
"years": 3,
"assumes": "three years from the outline decision to apply for reserved matters (statutory default)",
"limit_passed": false
},
"homes": 120,
"householder": false,
"follow_on": {
"count": 0,
"discharges": 0,
"variations": 0,
"reserved_matters": 0,
"last_date": null,
"conditions_named": null,
"live_applications": 0
},
"links": {
"council": "https://..."
},
"source": "historical"
}
],
"meta": {
"count": 1,
"next_cursor": null,
"window": {
"from": "2026-09-03",
"to": "2027-03-03",
"months": 6,
"includes_passed": false
},
"householder": "exclude",
"how": "..."
}
}Reading it. time_limit.rule is the statutory default the date assumes: commencement (from a full decision), reserved_matters (from an outline decision), or commencement_after_rm (the later of the full period from the outline decision and two years from the last reserved-matters approval); time_limit.years is the period applied from the decision: three in England and Scotland, five in Wales and Northern Ireland, and five for a Scottish permission in principle, which has one commencement limit and no reserved-matters deadline. Certificates, prior approvals, screening opinions and reserved-matters applications are not permissions and never appear. A condition can set a different period, which only the decision notice shows. follow_on is what the register records against the consent - discharges of conditions, variations, reserved matters - from the archive and the live record. A lawful start needs no paperwork, so a consent with no follow-on is a prompt to check the site, never a finding that it has lapsed; time_limit.limit_passed only says the date has passed. Rows are ordered by limit date; page with cursor, and add total=1 for the whole-query count. The same list is on the site at /expiring-consents with a CSV.
Freehold owners and leaseholders
The company that owns a property's freehold, from HM Land Registry's registers of UK and overseas companies that own property in England and Wales, with its Companies House record. Private owners are not in those registers, so a property with no company owner carries freehold_owner: null. Pro plan and above; Starter keys get freehold_owner_available, whether an owner is held. On live and historical records alike.
| Field | Meaning |
|---|---|
title_number | HM Land Registry's title number for the freehold: the key to its register and title plan. |
tenure, of | Always freehold; of is property (the freehold of the property itself), building (for a flat, the freehold of its building) or land (development land or a field with no postcode, matched by its description). |
via, confidence, titles_matched | How the owner was matched: address (the property's sale or address) or description (the land's description in HM Land Registry's register against the council's, within the same district). For description, confidence is high (only high matches are given) and titles_matched how many of the company's titles fit; both null for address. A place several companies share, such as a retail park, is never matched by description. |
date_proprietor_added, price_paid | When the company was registered as owner, and the price HM Land Registry records for it then (pounds); null where not recorded. |
release, release_month | The monthly HM Land Registry release the owner comes from (September 2026, 2026-09). |
proprietors[] | name, company_number (Companies House form, 8 characters; null when the number HM Land Registry gives is not checkable or is another company's), category, country_incorporated (overseas companies), links (Companies House, the Plota owner profile, the API owner record). |
proprietors[].companies_house | The company's record: name, status and status_code (Companies House's own codes: active, active-proposal-to-strike-off, liquidation, administration, receivership, voluntary-arrangement, dissolved, other), incorporated_on, sic_codes and nature_of_business, previous_names, accounts (type, made up to, next due, overdue), confirmation_statement, charges (total, outstanding), freehold_titles, group (its top company, size and titles), parents (controlling companies with their share band and whether they hold a majority) and ultimate_owner. null when Companies House does not hold the number under the proprietor's name. |
Leaseholders. leaseholders lists the companies holding a registered lease (seven years or more), from the same registers, each item in the shape of freehold_owner with tenure: "leasehold" and of: property (a lease of the whole property: a shop, an office, a restaurant), part (of part of the building the application is about: a floor, a unit) or building (of the whole building the application's flat or unit is in), and relation, how it stands to this application: this_unit, this_property, whole_building, or elsewhere_in_building (it leases another part of the building, so it is an occupier there, not necessarily the applicant). A leaseholder is never the owner. At most five, the most recently registered first; null when none is held. Leases of a roof or airspace (solar panels), substations, telecoms sites, parking spaces and garages are not matched. Pro plan and above; Starter keys get leaseholder_available. leaseholder_company filters GET /v1/applications by leaseholder; GET /v1/owners/{number} counts a company's leased applications apart (applications.leased_live, leased_historical, and of those leased_live_direct and leased_historical_direct, where the lease is the application's own), and GET /v1/owners/{number}/applications?interest=leased lists them (owned by default, any for both).
By owner: GET /v1/owners?q= finds a company by the start of its name or its number, owners of the most freehold titles first. GET /v1/owners/{number} gives the company (or, with scope=group, its whole group) and what it does with its land: the applications on it, live and historical, permissions about to lapse (the council's expiry date, else three years from the decision, marked estimated), refusals and withdrawals, the agent firms it uses, applications a month, appeals, and the titles registered to it in the last three years with the prices recorded. GET /v1/owners/{number}/applications lists every application on its land as full records, live then historical, on one cursor; GET /v1/owners/{number}/group draws its group. owner_company filters GET /v1/applications the same way, and POST /v1/alerts with type: owner emails you when the company applies for anything new.
Owner alerts. POST /v1/alerts with type: "owner", the company's number and owner_scope (company, or group for every company in its group) makes an alert that emails you when an application arrives on its land, in any council. It is an ordinary saved alert: listed by GET /v1/alerts, its applications at GET /v1/alerts/{id}/matches, and webhooks fire for it. Pro and above.
{
"type": "owner",
"owner_company": "03512363",
"owner_scope": "group",
"frequency": "daily"
}Records. An owner (a company, or a group) is one record of the month's allowance, in a search result or by its number; every application a response carries is charged as on /v1/applications, and a re-read in the month is free. meta.sources gives the releases the data comes from; meta.attribution carries HM Land Registry's and Companies House's statements, which go wherever the data goes. The licence forbids using the owner data to contact owners to offer goods or services (API terms, section 7).
{
"data": {
"company_number": "03512363",
"scope": "company",
"name": "STAR PUBS TRADING LIMITED",
"companies": 1,
"company": {
"company_number": "03512363",
"name": "STAR PUBS TRADING LIMITED",
"status": "Active",
"status_code": "active",
"incorporated_on": "1998-02-17",
"sic_codes": [
"56302"
],
"accounts": {
"type": "Subsidiary, exempt",
"made_up_to": "2024-12-31",
"next_due": "2026-09-30",
"overdue": false
},
"charges": {
"total": 361,
"outstanding": 6
},
"freehold_titles": 2253,
"group": {
"top": {
"company_number": "SC016288",
"name": "SCOTTISH & NEWCASTLE LIMITED"
},
"companies": 14,
"freehold_titles": 2295
},
"parents": [
{
"name": "HEINEKEN UK LIMITED",
"company_number": "SC065527",
"control": "75 to 100%",
"majority": true,
"country": null
}
],
"ultimate_owner": {
"company_number": "SC016288",
"name": "SCOTTISH & NEWCASTLE LIMITED"
}
},
"applications": {
"live": 86,
"historical": 1536,
"councils": 53
},
"permissions_lapsing": {
"total": 230,
"within_12_months": 108,
"listed": 100,
"capped": true,
"list": [
"..."
]
},
"refused_withdrawn": {
"total": 211,
"refused": 126,
"withdrawn": 85,
"listed": 100,
"capped": true,
"list": [
"..."
]
},
"agents": [
{
"name": "S R Signs",
"applications": 14
}
],
"appeals": {
"total": 0,
"allowed": 0,
"dismissed": 0,
"other": 0,
"list": []
},
"buying": {
"last_12_months": {
"titles": 16,
"priced": 6,
"value": 2528026
},
"last_36_months": {
"titles": 917,
"priced": 37,
"value": 18980583
}
},
"titles_bought": {
"total": 917,
"listed": 200,
"capped": true,
"list": [
{
"title_number": "MM214986",
"date_proprietor_added": "2025-11-20",
"price_paid": null,
"tenure": "freehold",
"district": "SANDWELL",
"application": null
}
]
}
},
"meta": {
"count": 1,
"applications_listed": 205,
"sources": {
"owners": {
"release": "September 2026",
"release_month": "2026-09"
},
"companies_house": {
"release": "September 2026",
"release_month": "2026-09",
"loaded_at": "2026-09-30T08:34:51Z"
}
},
"attribution": [
"Information produced by HM Land Registry. © Crown copyright 2026. Source: HM Land Registry, UK and overseas companies that own property in England and Wales, September 2026 release.",
"Company details from Companies House, licensed under the Open Government Licence v3.0."
],
"records": {
"used": 206,
"cap": 100000,
"remaining": 99794,
"one_off": false
}
}
}HMO licences
GET /v1/hmo-licences returns licensed houses in multiple occupation from councils’ public HMO registers: where each one is, its licence type, status and expiry, and, where the register gives them, how many people and households it may house and its rooms and amenities. Every search names a place: a council, a postcode, a point with a radius (lat, lng, radius) or a bbox; a search without one is refused. It returns active HMO licences unless you ask for others: licensed or applied for, and in date, and mandatory, additional or an HMO licence the register does not type. Pages hold at most 50 licences. No personal details are served.
| Endpoint | Purpose |
|---|---|
GET /v1/hmo-licences | Search licences with the filters below and cursor pagination |
GET /v1/hmo-licences/{id} | One licence by its id, whatever its status, while it is on the register |
GET /v1/hmo-licences/coverage | Every council register and every district no register covers: whether its licences are served, at what coverage, and why not where they are not |
The records. Every record carries the same fields, whichever council it comes from, and a field the council’s register does not give is null; every filter reads every council. coverage says whether the register is published under the Open Government Licence ("full", credited as meta.source says) or not ("basic"). Each HMO licence new to your account in a month counts as 2 records of your monthly records allowance; reading it again in the same month is free.
| Parameter | What it reads | Plan |
|---|---|---|
council | Council slug, as council in GET /v1/hmo-licences/coverage (leeds, camden). A council formed from older districts (somerset) includes their registers. An unknown slug is refused; a council whose register is not shown returns no records, and meta.hint says why. | Every plan |
postcode | The postcode on the register, normalised: a full postcode (N1 8NX) matches that unit, and its first half (N1) the whole district, never N19 or NW1. | Every plan |
lat | Latitude of a point in the UK. With lng, licences within radius metres of the point, nearest first, each carrying distance_m. Reads the licence's point: the council's own coordinates where the register gives them, else the property's UPRN or its postcode's centre (geo_precision says which). | Every plan |
lng | Longitude of the point; see lat. | Every plan |
radius | Metres around lat and lng, 1 to 5000, default 1000. When more than 20,000 licences match inside it, the request is refused: narrow the radius or add filters. | Every plan |
bbox | minLng,minLat,maxLng,maxLat, at most 1 degree each way: licences whose point is inside the box. Give a point or a box, not both. | Every plan |
status | Status as of today: active (the default: licensed or applied for, and in date: what the map shows), current (the same as active), licensed, pending (applied for), expired, revoked, ended (expired or revoked), or all. Reads licence_status and licence_expiry: a licence past its expiry is expired whatever the register says, and a revoked one stays revoked. | Every plan |
licence_type | Comma separated: mandatory (Housing Act 2004 s.55), additional (a council scheme for smaller HMOs), hmo_other (an HMO licence the register does not type), selective (Part 3: any rented home in a designated area; not an HMO licence) and exemption (a temporary exemption notice or management order). Default: mandatory,additional,hmo_other, the HMO licences. Reads licence_type. | Every plan |
property_type | Comma separated: house, flat, maisonette, bedsit (a house let as bedsits), building (a building of flats under s.257, or a block) and other (a hostel, staff or student accommodation, a mixed HMO). Reads property_type, which some registers state. | Every plan |
min_occupants / max_occupants | A range (either end, or both): the most people the licence allows (max_occupants). | Every plan |
min_households / max_households | A range (either end, or both): the most households the licence allows (max_households). | Every plan |
min_bedrooms / max_bedrooms | A range (either end, or both): rooms providing sleeping accommodation (bedrooms). | Every plan |
min_storeys / max_storeys | A range (either end, or both): storeys in the building (storeys). | Every plan |
expires_within | Months, 1 to 24: licences whose expiry (licence_expiry) falls between today and that many months ahead. | Every plan |
licensed_since | YYYY-MM-DD: licences whose start (licence_start) is on or after the date. | Every plan |
first_seen_since | YYYY-MM-DD: licences that first appeared on the council's register, as Plota read it, on or after the date (first_seen). | Every plan |
planning | any: a planning application is recorded at the licence's address; hmo_use: one of those applications is an HMO proposal (to create, convert to, extend or change the use of an HMO; a follow-up such as a condition discharge does not count). Reads planning on the record, Plota's match of the licence to the planning applications at the same address. | Every plan |
price | The last sale price as a band of pounds, lo-hi (150000-250000), lo- or -hi: licences whose property's last sale in HM Land Registry price paid data falls in it. Licences with no matched sale are left out. | Pro and above |
min_price / max_price | The last sale price at least this many pounds; see price. | Pro and above |
sort | newest (latest licence start first; the default without a point), nearest (needs lat and lng; the default with them), street (by street and house number within each council, a licence with no address last), expiry (soonest expiry first) or added (newest to the register first). | Every plan |
limit | Page size, at most 50 (Demo 10); a larger value is capped. | Every plan |
cursor | Opaque cursor from meta.next_cursor. It continues only the query it came from: send it with the same filters. | Every plan |
total | total=1 adds meta.total, the number of licences matching the whole query. | Every plan |
# Active HMO licences at one postcode
curl "https://api.plota.co.uk/v1/hmo-licences?postcode=NW1+3QJ" \
-H "Authorization: Bearer plota_live_your_key"
# Leeds licences for six or more people that expire in the next six months, soonest first
curl "https://api.plota.co.uk/v1/hmo-licences?council=leeds&min_occupants=6&expires_within=6&sort=expiry" \
-H "Authorization: Bearer plota_live_your_key"{
"data": [
{
"id": 35618,
"council": "camden",
"council_name": "Camden",
"coverage": "full",
"lad_code": "E09000007",
"licence_key": "101117",
"licence_ref": "101117",
"address": "Flat 10, Patterdale Osnaburgh Street London",
"postcode": "NW1 3QJ",
"uprn": null,
"lat": 51.528692,
"lng": -0.142266,
"geo_source": "postcode",
"geo_precision": "centroid",
"licence_type": "additional",
"licence_status": "licensed",
"scheme": null,
"licence_start": "2026-09-18",
"licence_start_precision": "day",
"licence_expiry": "2031-09-17",
"licence_expiry_precision": "day",
"max_occupants": 5,
"max_households": null,
"storeys": 4,
"bedrooms": 3,
"living_rooms": 0,
"kitchens": 1,
"kitchens_shared": null,
"bathrooms": null,
"bathrooms_shared": 0,
"toilets": null,
"toilets_shared": 0,
"units": 1,
"units_self_contained": 1,
"units_non_self_contained": 0,
"property_type": null,
"property_description": null,
"ward": null,
"licence_conditions": null,
"amenities_description": null,
"tribunal_referrals": null,
"tribunal_decisions": null,
"notes": null,
"application_type": null,
"application_date": null,
"application_date_precision": null,
"decision_date": null,
"decision_date_precision": null,
"first_licensed": null,
"first_licensed_precision": null,
"last_inspected": null,
"last_inspected_precision": null,
"licence_term_months": 60,
"built_from_year": null,
"built_to_year": null,
"habitable_rooms": 1,
"sinks": null,
"sinks_shared": 1,
"wash_basins": null,
"wash_basins_shared": 2,
"source_date": "2026-09-19",
"first_seen": "2026-09-27T14:45:08.369Z",
"last_seen": "2026-09-27T14:45:08.369Z",
"removed_at": null,
"planning": {
"applications": 0,
"hmo_use_applications": 0,
"latest_date": null
}
}
],
"meta": {
"count": 1,
"next_cursor": null,
"records": {
"used": 2,
"cap": 10000,
"remaining": 9998,
"one_off": false
},
"as_of": "2026-10-09",
"filters": {
"postcode": "NW1 3QJ",
"status": "active",
"licence_type": [
"mandatory",
"additional",
"hmo_other"
],
"sort": "newest"
},
"source": "Council HMO licence registers, as published by each council. Records from openly licensed registers (coverage full) contain public sector information licensed under the Open Government Licence v3.0."
}
}Reading it. licence_status is worked out for the day in meta.as_of: a licence past its expiry is expired whatever the register says, and a revoked one stays revoked. Each licence date says how exact it is (licence_start_precision and licence_expiry_precision: day, month, year, or derived when the register printed a term and no expiry). geo_precision says whether the point is the building (rooftop) or the postcode’s centre (centroid). Kitchens, bathrooms and WCs are the totals the register counts, with the shared ones beside them where it counts those. planning counts the planning applications Plota holds at the same address; planning=hmo_use finds licences where one of them is an HMO proposal (to create, convert to, extend or change the use of an HMO). meta.filters is the query as it ran, defaults included, and meta.source is the attribution to keep with the data.
Coverage by council. GET /v1/hmo-licences/coverage lists every council register, and every district no register covers, with the slug the council filter takes, whether its licences are served and at what coverage, the reason where they are not (the council does not publish its register online, provides it only on request or only as an online search, restricts reuse, or is not yet included), and its current licences beside the official count of licensed HMOs. It is counted as a request, not as records.
{
"data": [
{
"council": "camden",
"name": "Camden",
"nation": "england",
"districts": [
"E09000007"
],
"shown": true,
"coverage": "full",
"reason": null,
"active_licences": 3282,
"official_licensed_hmos": 316,
"official_year": "2024-25",
"register_date": "2026-09-19",
"last_read": "2026-09-27"
},
{
"council": "aberdeenshire",
"name": "Aberdeenshire",
"nation": "scotland",
"districts": [
"S12000034"
],
"shown": false,
"coverage": "grey",
"reason": "This council does not publish its HMO register online",
"active_licences": 0,
"official_licensed_hmos": 95,
"official_year": "2024-25",
"register_date": null,
"last_read": null
}
],
"meta": {
"...": "count, councils_shown, active_licences, official_total, official_covered, coverage_pct, official_sources, as_of, source"
}
}Enrichment & data depth
Normalised vs verbatim. Two rules keep integrations dependable. Filter and aggregate on stage - the normalised status (pending, approved, refused, withdrawn, decided, other), identical across every council. status and decision.outcome carry the council's own wording verbatim - use them for display and for verifying a record against the council source, never for filtering, because every authority words them differently.
What each stage means. stage is read from the council’s status and decision wording, the decision and issued dates, and any appeal outcome. pending: not yet decided; a blank or awaiting status lands here. approved: granted, or allowed on appeal. It also covers a ruling that prior approval, planning permission or consent is not required, conditions discharged in full, a certificate of lawfulness issued, a tree preservation order not made, and a consultee response of no comment or no objection, because in each the works may go ahead. refused: refused, or dismissed on appeal, plus a certificate not issued, conditions not discharged, a ruling that planning permission is required and a tree preservation order made in response to a notice. An appeal lodged against a refusal stays refused until the appeal is decided. withdrawn: withdrawn or not proceeded with. decided: determined with no single grant or refusal, such as a split or partial decision, conditions discharged in part, a council declining to determine, prior approval required, an EIA screening or scoping opinion, or a decision whose outcome the council does not publish. other: no outcome from this council, such as an invalid or returned application, one decided by another authority, an appeal against non-determination, or a notice that takes no decision. An approval rate counts approved against approved plus refused.
How exact each date is. date_precision says what date_received and date_decided are. day is the date the council's register publishes. A few registers publish no day-level dates in their lists, and until Plota has read the application's full record the date is a declared approximation: first-seen (the day the application, or its decision, first appeared on the register), week (from one of the register’s weekly lists, of applications registered or determined: the Monday of that week) or approx (estimated from the listing it appeared in). A decision date may also be issued: exact to the day, but the date the decision notice was issued, from a register that publishes no separate decision date (the same value as decision.issued_date). For day-level analysis, such as determination times or statutory deadlines, use the records marked day. The CSV carries the same two values in its last columns, date_received_precision and date_decided_precision.
Enrichment blocks. decision, appeal, key_dates and comments are read from the full council record on Plota's recurring checks and are null where the authority publishes nothing for them - councils vary widely in how much of the file they publish, so depth differs by authority, not by Plota. Within comments, 0 is real data: counted, none found. uprn is the authoritative UK property identifier for joining planning records to UPRN-keyed property systems. dwelling_count is Plota-derived: the number of homes explicitly stated in the description, null where none is stated. major_development is Plota-derived too: true for a major development in the legal sense (10 or more homes, 1,000 square metres, a site of 1 hectare, minerals or waste), false when it is not, null where the description cannot settle it; the council's own Major or Minor label decides where it publishes one.
Live vs historical. Enrichment is a live-data feature (2026 onward). Plota archive records (source: "historical", paid plans) carry the core record with all enrichment blocks null - except dwelling_count, which is backfilled onto the archive too. Single-application responses additionally carry created_at and updated_at; note updated_at moves on every re-check, including no-change ones, so it is not a content-change signal.
Contact Data add-on. With the add-on, records also include applicant, agent, agent_email, agent_phone, agent_address, applicant_address, case_officer, case_officer_email and case_officer_phone where the council publishes them (the two addresses are correspondence addresses, not the site address), metered as one monthly allowance (10,000 records; only records that deliver a contact value count). Pass include_contact=false to skip contact fields and metering on any call. Without the add-on these fields are absent entirely.
Webhooks
Available on Starter and above. Register an HTTPS endpoint in your dashboard (Webhooks → Add a webhook - no code needed) or with POST /v1/webhooks, linked to a saved alert. Plota POSTs an application.match.created event for each new match, with retries, and auto-disables endpoints that keep failing. Every delivery carries a Plota-Event-Id header and event id; retries reuse the same id, so treat it as an idempotency key. The full event body is the WebhookEvent schema in the OpenAPI document. Verify each delivery: compute HMAC-SHA256 over ${Plota-Timestamp}.${rawBody} with your webhook secret and compare to the Plota-Signature header.
const sig = crypto.createHmac('sha256', secret)
.update(req.headers['plota-timestamp'] + '.' + rawBody).digest('hex');
if (sig === req.headers['plota-signature']) { /* trusted */ }Integration guides (Reapit, Street, CMap, Total Synergy, Simpro, Re-Leased, Zapier, Make, n8n, HubSpot, Salesforce, Power BI and more). Manage keys & webhooks in your dashboard. Machine-readable schema: /openapi.json. Licence: API terms. Building with AI: paste /llms.txt into your assistant, or use the MCP server for live access. Questions? hello@plota.co.uk.