Error Handling
Every error response follows a consistent JSON format. Use HTTP status codes to handle errors programmatically.
Error format
All error responses return JSON with a consistent structure:
{
"error": "not_found",
"message": "No property found with UPRN 999999999999",
"status": 404
}
| Field | Type | Description |
|---|---|---|
| error | string | Machine-readable error code (snake_case) |
| message | string | Human-readable description |
| status | integer | HTTP status code (mirrors the response status) |
HTTP status codes
OK
Request succeeded. Response body contains the requested data.
Bad Request
Missing or invalid parameters. Check the message field for specifics.
Unauthorized
Missing or invalid API key. Make sure you're using the Authorization: Api-Key header.
Forbidden
API key is valid but doesn't have permission for this resource. May indicate a revoked key or tier restriction.
Not Found
The requested resource doesn't exist. For property endpoints, this means no data for that UPRN.
Rate Limit Exceeded
You've exceeded your plan's monthly request limit or per-second rate limit. Check the X-RateLimit-* headers.
→ Upgrade your plan for higher limits
Internal Server Error
Something went wrong on our side. These are rare and we're alerted automatically. If persistent, please contact us.
Gateway Timeout
Request took too long to process. Retry with exponential backoff. If frequent, the endpoint may be under heavy load.
Rate limiting
Every authenticated response includes rate limit headers:
| Header | Description |
|---|---|
| X-RateLimit-Limit | Your plan's monthly request allowance |
| X-RateLimit-Remaining | Requests remaining in current billing period |
| X-RateLimit-Reset | Unix timestamp when your limit resets (start of next billing period) |
Best practice: handle 429 gracefully
# Python — retry with backoff import time def api_call(url, headers, max_retries=3): for attempt in range(max_retries): response = requests.get(url, headers=headers) if response.status_code == 429: wait = 2 ** attempt # 1s, 2s, 4s time.sleep(wait) continue return response.json() raise Exception("Rate limit exceeded after retries")