API Reference
Base URL: https://api.planwire.io · Version: v1
Authentication
Pass your API key in the X-API-Key header. You can also use Authorization: Bearer YOUR_KEY.
X-API-Key: pw_live_a1b2c3d4e5f6...
Errors
All errors return JSON with an error field and an appropriate HTTP status code.
| Status | Meaning |
|---|---|
| 400 | Bad request — missing or invalid parameters |
| 401 | Unauthorised — missing or invalid API key |
| 404 | Not found — resource does not exist |
| 429 | Rate limit exceeded — upgrade your plan |
| 500 | Server error — contact support |
Pagination
All list endpoints return a meta object. Use ?page=2&limit=50 to paginate. The max limit is 100 records per page; this is a page-size cap, not a Starter-tier data cap.
"meta": { "total": 4821, // total matching records "page": 1, // current page (1-indexed) "limit": 25, // records per page "pages": 242 // total pages }
Freshness & dates
PlanWire exposes source-check freshness and application-date freshness separately. lastScrapedAt means the source was checked or refreshed. It should not be treated on its own as proof that new application records were ingested.
For data recency, use latestApplicationDate on councils and dates.applicationDate on applications. Application lists are sorted by applicationDate desc, firstSeenAt desc by default.
"freshness": { "sourceCheckStatus": "fresh", "dataStatus": "stale", "lastScrapedAt": "2026-05-01T09:20:00.000Z", "latestApplicationDate": "2026-03-12" }
Rate limits
Limits reset at midnight UTC. Exceeding the limit returns 429.
| Plan | Requests/day | Price |
|---|---|---|
| Free | 100 | £0 |
| Lite | 300 | £9/mo |
| Starter | 1,000 | £29/mo |
| Growth | 10,000 | £99/mo |
| Enterprise | Unlimited | £299/mo |
/v1/applications
List planning applications. All parameters are optional and can be combined. Each application includes council, source, and freshness metadata so you can verify where the record came from and when that source was last checked.
Query Parameters
oxf, cam)Approved, Refused)page to continue.curl "https://api.planwire.io/v1/applications?council=adu&q=extension&status=Approved&limit=5" \ -H "X-API-Key: YOUR_KEY"
/v1/applications/nearby
Find applications within a radius using PostGIS spatial indexing. Extremely fast even over millions of records.
curl "https://api.planwire.io/v1/applications/nearby?lat=51.4975&lng=-0.1278&radius_km=1" \ -H "X-API-Key: YOUR_KEY"
/v1/applications/:id
Fetch a single planning application by its UUID. Includes property enrichment — EA flood zone and Land Registry sold prices for the postcode.
curl "https://api.planwire.io/v1/applications/8f6fac3a-d93a-453e-b5db-6c5ecc631bf0" \ -H "X-API-Key: YOUR_KEY"
Property Enrichment Fields
floodRisk
object | null
EA Flood Map for Planning zone. zone is one of low, 2, 3a, 3b. Cached 30 days. Null on first call, populated within ~10s.
nearbyPrices
object | null
Land Registry price paid data for the same postcode over the last 2 years. Returns avgPrice (pence), count, postcode. Null if no sales in period or on first call.
/v1/applications/ref/:council/:reference
Fetch an application using the council's own reference number (e.g. 24/01234/FUL). Also includes flood risk and nearby sold prices.
curl "https://api.planwire.io/v1/applications/ref/adu/AWDM%2F0158%2F25" \ -H "X-API-Key: YOUR_KEY"
/v1/councils
List all 384 active council sources, with application counts.
{ "data": [{ "id": "adu", "name": "Adur District Council", "portalType": "official", "applicationCount": 874 }] }
/v1/councils/:id
Get a single council's details including the date of the most recent application.
curl "https://api.planwire.io/v1/councils/adu" \ -H "X-API-Key: YOUR_KEY"
/v1/webhooks
List all webhooks registered to your API key.
/v1/webhooks
Subscribe to planning application events. You'll receive an HTTP POST to your URL whenever a matching application is new or updated.
Request Body
SW1)curl -X POST "https://api.planwire.io/v1/webhooks" \ -H "X-API-Key: YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://your-app.com/hooks/planning", "filters": { "postcodePrefix": "SW1", "status": "Approved" } }'
Webhook Payload
Requests are signed with HMAC-SHA256 — verify using the X-PlanWire-Signature header.
{ "event": "application.new", // or "application.updated" "timestamp": "2025-03-19T14:23:01Z", "application": { /* full application object */ } }
Verifying signatures
Compute HMAC-SHA256(secret, rawBody) and compare to the X-PlanWire-Signature header value (after stripping the sha256= prefix).
import { createHmac } from 'crypto'; function verify(secret, rawBody, sigHeader) { const expected = 'sha256=' + createHmac('sha256', secret) .update(rawBody).digest('hex'); return sigHeader === expected; }
import hmac, hashlib def verify(secret, raw_body, sig_header): expected = 'sha256=' + hmac.new( secret.encode(), raw_body, hashlib.sha256 ).hexdigest() return hmac.compare_digest(sig_header, expected)
/v1/webhooks/:id
Remove a webhook by its UUID.
/v1/webhooks/:id/test
Send a test event to verify your endpoint is reachable and your signature verification works.
curl -X POST "https://api.planwire.io/v1/webhooks/YOUR_WEBHOOK_ID/test" \ -H "X-API-Key: YOUR_KEY"
/v1/webhooks/:id/deliveries
View the last 50 delivery attempts for a webhook — useful for debugging failed deliveries.
{ "data": [{ "id": "a3f2...", "event": "application.new", "statusCode": 200, "success": true, "createdAt": "2025-03-19T14:23:01Z" }] }
Ready to build?
Get your free API key →