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.
curl "https://api.plota.co.uk/v1/applications?postcode=SW11&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}/matches | Applications matching a saved alert |
GET /v1/applications/{id}/history | Status & decision timeline |
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 | Full or partial postcode, e.g. SW11 or SW11 6HB |
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) |
q | Keyword match in description, address, or reference |
status | Substring match on status, e.g. pending, approved |
date_from / date_to | Filter by received date, YYYY-MM-DD |
limit | Page size, capped per plan (Demo 10 → Business 250) |
cursor | Opaque pagination cursor from meta.next_cursor |
format | json (default) or csv |
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 | Per month | Max page |
|---|---|---|---|
| Demo | 30 / min | 500 / month | 10 |
| Starter | 120 / min | 20,000 / month | 50 |
| Pro | 300 / min | 100,000 / month | 100 |
| Business | 600 / min | 500,000 / month | 250 |
| Enterprise | 1,200 / min | Custom | 500 |
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
{
"id": "a1b2c3d4",
"reference": "2026/2284/FUL",
"authority": {
"slug": "wandsworth",
"name": "Wandsworth"
},
"address": "81 Example Road, London SW11 6HB",
"postcode": "SW11 6HB",
"description": "Single storey rear extension.",
"category": {
"slug": "extensions",
"label": "Extensions & alterations"
},
"categories": [
{
"slug": "extensions",
"label": "Extensions & alterations"
}
],
"planning_route": "Full planning permission",
"status": "Pending",
"stage": "pending",
"date_received": "2026-06-18",
"date_validated": "2026-06-20",
"date_decided": null,
"location": {
"lat": 51.4601,
"lng": -0.1702
},
"links": {
"plota": "https://plota.co.uk/application/a1b2c3d4",
"council": "https://..."
},
"source": "live"
}Webhooks
Register an HTTPS endpoint 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. 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 (Zapier, Make, Slack, Sheets, Airtable, HubSpot, Pipedrive). Manage keys & webhooks in your dashboard. Machine-readable schema: /openapi.json. Building with AI: paste /llms.txt into your assistant, or use the MCP server for live access. Questions? hello@plota.co.uk.